Skip to content

Instantly share code, notes, and snippets.

@apohllo
Created September 21, 2009 21:28
Show Gist options
  • Save apohllo/190560 to your computer and use it in GitHub Desktop.
Save apohllo/190560 to your computer and use it in GitHub Desktop.
module Apohllo
module Synthesis
class Numeral
include Inflector
def initialize(value, det={})
@value = value
@det = det
end
def apply(*args)
# XXX for the sake of simplicity we take only the first
# argument to set the gender
gender = determine_gender(to_lexemes(args[0]))
# 0, 5 - 21, 35 - 41 ... 95 - 101, 205 - 221, ... gender?
# 1 - sg nom gender?
# 2, 3, 4, 22 - 24, 32 - 34 - pl nom gender? unless gender == m1
# 2, 3, 4 if gender == m1
det = {}
det[:case], det[:number] =
if @value == 1 || @value == -1
[:nom, :sg]
elsif [2,3,4].include?(@value.abs % 10) &&
(@value.abs > 0 && @value.abs < 10 || @value.abs > 20) &&
(gender != :m1 || @value < 20)
[:nom, :pl]
else
[:gen, :pl]
end
det[:case] = @det[:case] if @det[:case]
numeral_det = @det.dup
numeral_det[:gender] = gender
numeral_det[:number] = ([0,1].include?(@value) ? :sg : :pl)
self.to_s(numeral_det) +
" " + args.map{|a| inflect(a,det)}.join(" ")
end
def prefix
@value < 0 ? "minus " : ""
end
def to_s(det={})
result = prefix
if @value.abs >= 1000
result += big_number_to_s(@value.abs,det)
else
result += number_to_s(@value.abs,true,det).strip
end
result.strip
end
protected
def big_number_to_s(value,det={})
result = ""
while value >= 1000
factor = 10**((Math.log10(value).floor/3)*3)
value_part = value / factor
if value_part == 1
result += big(value) + " "
elsif value_part != 0
result += Numeral.new(value_part).apply(big(value)) + " "
end
value -= value_part * factor
end
result + number_to_s(value,false,det)
end
def number_to_s(value,single_digit=true,det={})
raise "Value must be at least 0" if value < 0
return "" if value == 0 && !single_digit
case value
when 0...10
inflect_numeral(value,det,single_digit)
when 10...20
inflect_numeral(value,det)
when 20...100
inflect_numeral(value,det) + " " +
number_to_s(value%10,false,det)
when 100...1000
inflect_numeral(value,det) + " " +
number_to_s(value%100,false,det)
else
raise "Value must be less than 1000: #{value}"
end
end
def inflect_numeral(value, det, single_digit=false)
literal =
case value
when 0...10
irregular(value,det,single_digit) || DIGITS[value]
when 10...20
irregular(value,det) || TEENS[value-10]
when 20...100
irregular(value/10 * 10,det) || TENS[value/10-2]
when 100...1000
irregular(value/100 * 100,det) || HUNDREDS[value/100-1]
end
return literal if det[:case].nil?
lexemes = Rlp::Lexeme.find(literal)
lexeme = INFLECTED_MAPPING[det[:gender]] &&
lexemes.find{|l| INFLECTED_MAPPING[det[:gender]][value] ==
l.inflection_label } || lexemes[0]
if value != 1
if det[:gender] == :m1
det[:gender] = :pltp
else
det[:gender] = :plti
end
end
lexeme.inflect(det)
end
def big(value)
BIG[Math.log10(value).floor/3-1]
end
def irregular(value, det, single_digit=false)
det = det.dup
if det[:gender] && INFLECTED_NUMERALS[det[:gender]] &&
INFLECTED_NUMERALS[det[:gender]][value] &&
(single_digit || value != 1)
if det[:gender] == :m1 && !single_digit && [2,3,4].include?(value)
det[:gender] = :m1a
end
INFLECTED_NUMERALS[det[:gender]][value]
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment