Created
September 21, 2009 21:28
-
-
Save apohllo/190560 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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