Array#one_hundred_thirty_two_thousand_six_hundred_and_forty_eighth とかできるよ
Rails2.2でなんとArrayオブジェクトのアクセサとして#second 〜 #tenthなんてのができちゃった。だいたい分かると思うけど ary.second は ary[1] と同じで、ary.tenth はary[9] と同じ。
正直これにはがっかりした。DHHにしては中途半端と言うほかない。なんで10thまでなんだよ。その程度じゃ全然たんねーよ。
やるならこうだろ!
$ irb >> require 'array_ordinal_accessor' => true >> array = (1..200000).to_a ..snip.. >> array.seventy_third => 73 >> array.three_hundred_and_nineth => 309 >> array.one_hundred_thirty_two_thousand_six_hundred_and_forty_eighth => 132648
もちろん代入だってこうだ。
>> array.fifty_thousand_six_hundred_and_fifty_eighth => 50658 >> array.fifty_thousand_six_hundred_and_fifty_eighth = 'hello' => "hello" >> array.fifty_thousand_six_hundred_and_fifty_eighth => "hello"
最大でだいたい一千兆くらい*1まで対応。試してないけど、アクセサの最大値はこんな感じになるはず。
>> array.nine_hundred_ninety_nine_trillion_nine_hundred_ninety_nine_billion_nine_hundred_ninety_nine_million_nine_hundred_ninety_nine_thousand_nine_hundred_and_ninety_ninth
さらにはおまけだけど、数値と英語を相互に変換もできる。
>> 90112.to_alphabetic => "ninety thousand one hundred and twelve" >> 56115.to_ordinal => "fifty six thousand one hundred and fifteenth"
>> Integer.from_alphabetic "ninety thousand one hundred and twelve" => 90112 >> Integer.from_ordinal "fifty six thousand one hundred and fifteenth" => 56115
これでもう ary[123] みたいなだっさい記法とは金輪際さよならだ。男なら ary.one_hundred_and_twenty_fourth って書くよな。
進歩的なRubyistのみなさまにおかれましては是非ともこのライブラリを活用してソースの可読性向上に努めて頂きたい。
・・・
# array_ordinal_accessor.rb class Integer LESS_THAN_20 = [ :zero, :one, :two, :three, :four, :five, :six, :seven, :eight, :nine, :ten, :eleven, :twelve, :thirteen, :fourteen, :fifteen, :sixteen, :seventeen, :eighteen, :nineteen, ] DOUBLE_FIGURES = [ nil, :ten, :twenty, :thirty, :forty, :fifty, :sixty, :seventy, :eighty, :ninety ] HUNDRED = :hundred BIG_FIGURES = [nil, :thousand, :million, :billion, :trillion] AND = :and SPECIAL_ORDINALS = [ nil, :first, :second, :third, nil, :fifth, nil, nil, :eighth, :ninth, ] DOUBLE_FIGURES[2..-1].each_with_index do |fig, i| SPECIAL_ORDINALS[(i+2) * 10] = :"#{fig.to_s[0..-2]}ieth" end class <<self def from_alphabetic(str, sep=' ') ret, tmp = 0, 0 (str.is_a?(String) ? str.split(sep) : str).map{|e| e.to_sym}.each do |num| case num when NilClass, AND; # ignore when *LESS_THAN_20; tmp += LESS_THAN_20.index num when *DOUBLE_FIGURES; tmp += DOUBLE_FIGURES.index(num) * 10 when HUNDRED; tmp *= 100 when *BIG_FIGURES; ret += tmp * 1000**BIG_FIGURES.index(num); tmp = 0 else; raise ArgumentError.new("Invalid Format: #{num}") end end ret + tmp end def from_ordinal(str, sep=' ') array = (str.is_a?(String) ? str.split(sep) : str).map{|e| e.to_sym} array[-1] = if SPECIAL_ORDINALS.include?(array.last) if (idx = SPECIAL_ORDINALS.index(array.last)) < 20 LESS_THAN_20[idx] else array.last.to_s.sub(/ieth$/, 'y').to_sym end else array[-1].to_s[0...-2].to_sym end from_alphabetic array end end def to_alphabetic(sep=' ') to_alphabetic_array.join sep end def to_ordinal(sep=' ') to_ordinal_array.join sep end private def to_alphabetic_array triples = [] num = self while num != 0 triples << num % 1000 num /= 1000 end raise RangeError.new('Too large') if BIG_FIGURES.size < triples.size ret = [] triples.each_with_index do |n, i| array = to_alphabetic_array_less_than_1000 n, ret.empty? unless array == [:zero] array << BIG_FIGURES[i] unless i == 0 ret.unshift array end end ret.flatten end def to_ordinal_array alphabetics = to_alphabetic_array alphabetics[-1] = if special = SPECIAL_ORDINALS[LESS_THAN_20.index(alphabetics.last) || 0] special elsif special = SPECIAL_ORDINALS[(DOUBLE_FIGURES.index(alphabetics.last) || 0) * 10] special else :"#{alphabetics.last}th" end alphabetics end def to_alphabetic_array_less_than_1000(num, last=false) case num when 0 # ignore when 1..19 [LESS_THAN_20[num]] when 20..99 [DOUBLE_FIGURES[num / 10], *to_alphabetic_array_less_than_1000(num % 10)].compact else double = to_alphabetic_array_less_than_1000(num % 100) if not last [LESS_THAN_20[num / 100], HUNDRED, *double] elsif double == [:zero] [LESS_THAN_20[num / 100], HUNDRED] else [LESS_THAN_20[num / 100], HUNDRED, AND, *double] end end end end class Array def method_missing(symbol, *args, &block) name = symbol.to_s if name[-1] == ?= index = Integer.from_ordinal(name[0...-1], '_') - 1 self[index] = args.first else index = Integer.from_ordinal(name, '_') - 1 self[index] end rescue super end end
*1:正確には九百九十九兆九千九百九十九億九千九百九十九万九千九百九十九まで対応