class Diachronr::Rule

rule for applying a single sound change

Attributes

condition[RW]
from[RW]
to[RW]

Public Class Methods

new(rule) click to toggle source
# File lib/diachronr/rule.rb, line 10
def initialize(rule)
  @from, @to, @condition = rule.split '/'
end

Public Instance Methods

apply(target, options = {}) click to toggle source
# File lib/diachronr/rule.rb, line 84
def apply(target, options = {})
  categories = options[:categories] || []
  return apply_categories target, categories if category? categories

  # construct regex from condition
  from_condition = @condition.gsub '_', @from
  to_condition = @condition.gsub '_', @to

  # change word boundaries to regex
  from_condition = Regexp.new from_condition.gsub('#', '\b')
  to_condition.delete! '#'

  # split on from_condition and join with to_condition
  # if you need a limit higher than 10.... nope
  split_target = target.split from_condition, 10
  split_target.join to_condition
end
apply_categories(target, categories) click to toggle source
# File lib/diachronr/rule.rb, line 73
def apply_categories(target, categories)
  # parse categories, apply each exploded rule to the original target
  # merge the changes together
  rules = category_rules(categories) + condition_rules(categories)
  matches = rules.map { |r| r.apply target, categories: categories }
  matches.uniq!
  matches.delete target

  matches.count == 1 ? matches.first : merge_matches(target, matches)
end
categories?(value, categories) click to toggle source
# File lib/diachronr/rule.rb, line 22
def categories?(value, categories)
  !get_categories(value, categories).empty?
end
category?(categories) click to toggle source
# File lib/diachronr/rule.rb, line 18
def category?(categories)
  categories?(from, categories) || categories?(condition, categories)
end
category_rules(categories) click to toggle source
# File lib/diachronr/rule.rb, line 40
def category_rules(categories)
  rules = []
  get_categories(from, categories).each_with_index do |cat, i|
    cat.contents.each_char.with_index do |f, fi|
      rules << Rule.new(
        "#{new_from(cat, f)}/#{new_to(categories, i, fi)}/#{condition}"
      )
    end
  end
  rules
end
condition_rules(categories) click to toggle source
# File lib/diachronr/rule.rb, line 52
def condition_rules(categories)
  rules = []
  get_categories(condition, categories).each do |cat|
    cat.contents.each_char do |c|
      new_condition = condition.gsub cat.sign, c
      rules << Rule.new("#{from}/#{to}/#{new_condition}")
    end
  end
  rules
end
get_categories(value, categories) click to toggle source
# File lib/diachronr/rule.rb, line 26
def get_categories(value, categories)
  categories.select { |c| value.include? c.sign }
end
merge_matches(target, matches) click to toggle source
# File lib/diachronr/rule.rb, line 63
def merge_matches(target, matches)
  new_target = target.dup
  matches.each do |match|
    match.each_char.with_index do |m, i|
      new_target[i] = m if target[i] != m
    end
  end
  new_target
end
new_from(category, char) click to toggle source
# File lib/diachronr/rule.rb, line 36
def new_from(category, char)
  from.gsub category.sign, char
end
new_to(categories, category_index, index) click to toggle source
# File lib/diachronr/rule.rb, line 30
def new_to(categories, category_index, index)
  t = get_categories(to, categories)[category_index]
  return to if t.nil?
  t.contents[index]
end
to_s() click to toggle source
# File lib/diachronr/rule.rb, line 14
def to_s
  "'#{@from}' > '#{@to}' / '#{@condition}'"
end