Ruby/Идеология: различия между версиями

Содержимое удалено Содержимое добавлено
Строка 300:
В зависимости от класса, будет вызван либо один <code>meTog</code>, либо другой. При этом, <code>meTog</code> в классе <code>String</code> используется как адаптер для <code>meTog</code>'а класса <code>Array</code>. Единственный недостаток такого подхода — случайное переопределение базовых методов. Но эта случайность быстро отлавливается. [[Участник:Rubynovich|Rubynovich]] 17:40, 5 ноября 2006 (UTC)
 
== Что дает высокоуровневый подход? ==
Все началось с заметки на http://bash.org.ru:
{{Начало цитаты}}
Vixen: 54308428790203478762340052723346983453487023489987231275412390872348475
 
tosh: что это за безумие?
 
Vixen: это?
 
Vixen: это пятьдесят четыре довигинтиллиона триста восемь унвигинтиллионов четыреста двадцать восемь вигинтиллионов семьсот девяносто новемдециллионов двести три октодециллиона четыреста семьдесят восемь септендециллионов семьсот шестьдесят два сексдециллиона триста сорок квиндециллионов пятьдесят два кваттуордециллиона семьсот двадцать три тредециллиона триста сорок шесть дуодециллионов девятьсот восемьдесят три ундециллиона четыреста пятьдесят три дециллиона четыреста восемьдесят семь нониллионов двадцать три октиллиона четыреста восемьдесят девять септиллионов девятьсот восемьдесят семь секстиллионов двести тридцать один квинтиллион двести семьдесят пять квадриллионов четыреста двенадцать триллионов триста девяносто миллиардов восемьсот семьдесят два миллиона триста сорок восемь тысяч четыреста семьдесят пять
{{Конец цитаты}}
 
Тут же появилась идея реализовать программу, которой потенциально мог воспользоваться Vixen. Первым прислал решение [http://vkontakte.ru/id418587 Руслан Мухамедов]:
 
<source lang=ruby>#!/usr/bin/ruby
# Программа для написания чисел на русском языке из цифрового представления
# Версия 0.1.1
#
# История изменений
# 0.1.1
# * Убраны лишние пробелы в числах с 00000
#
# Email, JabberID: ru.ruslan@gmail.com
#
# Названия больших чисел взяты из статьи http://mirozdanie.narod.ru/Knowleg.html и могут отличаться от иных источников
#
# Пример использования:
# $ruby bignums.rb 54308428790203478762340052723346983453487023489987231275412390872348475
# пятьдесят четыре дуовигинтиллиона ......... тысяч четыреста семьдесят пять
 
nums_for_0_9 = %w{ноль один два три четыре пять шесть семь восемь девять}
nums_for_10_19 = %w{десять одиннадцать двенадцать тринадцать четырнадцать пятнадцать шестнадцать семнадцать восемнадцать девятнадцать}
nums_for_10_90 = %w{десять двадцать тридцать сорок пятьдесят шестьдесят семьдесят восемьдесят девяносто}
nums_for_100_900 = %w{сто двести триста четыреста пятьсот шестьсот семьсот восемьсот девятьсот}
 
nums = []
nums << nums_for_0_9
nums.flatten!
nums[0] = ""
nums << nums_for_10_19
nums.flatten!
for i in 2..9 do
nums << nums_for_10_90[i-1]
for j in 1..9 do
nums << nums_for_10_90[i-1] + " " + nums[j]
end
end
 
for i in 1..9 do
c = nums_for_100_900[i-1]
nums << c
for j in 1..99 do
nums << c + " " + nums[j]
end
end
 
die = proc{ |msg| puts msg; exit; }
 
x = ARGV[0] or die.call "Usage: ./bignums.rb NUMBER"
 
threes = x.reverse.scan(/\d{1,3}/).map{|x| x.reverse}
 
rod_mult = proc{ |arr|
ans = [arr[2],arr[0],arr[1..1]*3,arr[2..2]*5].flatten
}
 
ok_m = rod_mult.call ["","а","ов"]
ok_z = rod_mult.call ["а","и",""]
threes_names = %w{тысяч миллион миллиард триллион квадриллион квинтиллион секстиллион септиллион
октиллион нониллион дециллион андециллион дуодециллион тредециллион кваттордециллион квиндециллион сексдециллион септемдециллион
октодециллион новемдециллион вигинтиллион анвигинтиллион дуовигинтиллион тревигинтиллион кватторвигинтиллион квинвигинтиллион
сексвигинтиллион септемвигинтиллион октовигинтиллион новемвигинтиллион тригинтиллион антригинтиллион}
 
 
i = -1
ans = threes.map do |s|
i+= 1
n = s.to_i
next if n == 0
if i == 0
nums[n]
elsif i == 1
# тысячи
e = n % 10
d = n % 100
suff = ok_z[e]
suff = ok_z[0] if d > 10 and d < 20
t = nums[n]
if e == 1 or e == 2 and not (d > 10 and d < 20)
# один и два перед тысячами меняются.
# не регексп, чтобы работал и юникод и однобайтные кодировки
t = " " + t + " "
t = t.sub(" один "," одна ").sub(" два "," две ")
t = t[1..99].chop
end
t + (n!=0 ? " " : "") + threes_names[i-1] + suff
else
e = n % 10
d = n % 100
suff = ok_m[e]
suff = ok_m[0] if d > 10 and d < 20
nums[n] + (n!=0 ? " " : "") + threes_names[i-1] + suff
end
end.reverse.compact.join(" ")
 
puts ans</source>
 
Прочитав этот код я ничего не понял. А самый верный способ понять код — провести рефакторинг. Что я и решил сделать:
 
<source lang=ruby>#!/usr/bin/ruby
# Программа для написания чисел на русском языке из цифрового представления
# Версия 0.2
#
# История изменений
# 0.2
# * Проведен глубокий рефакторинг кода. Теперь решение в "одну строчку"
# 0.1.1
# * Убраны лишние пробелы в числах с 00000
#
# Email, JabberID: ru.ruslan@gmail.com
# Email, JabberID: rubynovich@gmail.com
#
# Названия больших чисел взяты из статьи http://mirozdanie.narod.ru/Knowleg.html и могут отличаться от иных источников
#
# Пример использования:
# $ruby bignums.rb 54308428790203478762340052723346983453487023489987231275412390872348475
# => пятьдесят четыре дуовигинтиллиона ......... тысяч четыреста семьдесят пять
 
nums_for_1_9 = %w{один два три четыре пять шесть семь восемь девять}
nums_for_10_19 = %w{десять одиннадцать двенадцать тринадцать четырнадцать пятнадцать шестнадцать семнадцать восемнадцать девятнадцать}
nums_for_20_90 = %w{двадцать тридцать сорок пятьдесят шестьдесят семьдесят восемьдесят девяносто}
nums_for_100_900 = %w{сто двести триста четыреста пятьсот шестьсот семьсот восемьсот девятьсот}
 
nums = nums_for_1_9 + nums_for_10_19
 
nums += nums_for_20_90.zip([nums_for_1_9]*nums_for_20_90.size).map{ |decade,array|
array.map{ |num| [decade,num].join(" ") }.unshift( decade )
}.flatten
 
nums += nums_for_100_900.zip([nums]*nums_for_100_900.size).map{ |hundred,array|
array.map{ |num| [hundred,num].join(" ") }.unshift( hundred )
}.flatten
 
nums.unshift("")
 
ok = { 1 => ["", "а", "и", "и", "и", "", "", "", "", ""] }
ok.default = ["ов", "", "а", "а", "а", "ов", "ов", "ов", "ов", "ов"]
 
threes_names = %w{тысяч миллион миллиард триллион квадриллион квинтиллион секстиллион септиллион
октиллион нониллион дециллион андециллион дуодециллион тредециллион кваттордециллион квиндециллион сексдециллион септемдециллион
октодециллион новемдециллион вигинтиллион анвигинтиллион дуовигинтиллион тревигинтиллион кватторвигинтиллион квинвигинтиллион
сексвигинтиллион септемвигинтиллион октовигинтиллион новемвигинтиллион тригинтиллион антригинтиллион}
 
threes = ARGV[0].reverse.scan(/\d{1,3}/).map{|x| x.reverse} rescue raise("Usage: ./#{$0} NUMBER")
puts (1...threes.size).map{ |i|
threes[i].to_i.instance_eval{ |n|
if [1,2].include?(n % 10)&&!(11...20).include?(n % 100)||(i>1)
nums[n].sub("один","одна").sub("два","две")
else
nums[n]
end + " " + threes_names[i-1] + ok[i][ (11...20).include?(n % 100) ? 0 : n % 10 ] if n.nonzero?
}
}.compact.reverse.pop(nums[threes[0].to_i]).join(" ")</source>
 
Сейчас пока некогда рассказывать как это получилось, но чуть позже опишу свои действия по шагам. [[Участник:Rubynovich|Rubynovich]]
== См. также ==