Guest User

Untitled

a guest
Jul 21st, 2018
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.48 KB | None | 0 0
  1. # -*- encoding: utf-8 -*-
  2. module RuTils
  3. module Pluralization #:nodoc:
  4. # Выбирает нужный падеж существительного в зависимости от числа
  5. def self.choose_plural(amount, *variants)
  6. variant = (amount%10==1 && amount%100!=11 ? 1 : amount%10>=2 && amount%10<=4 && (amount%100<10 || amount%100>=20) ? 2 : 3)
  7. variants[variant-1]
  8. end
  9.  
  10. # Выводит целое или дробное число как сумму в рублях прописью
  11. def self.rublej(amount)
  12. pts = []
  13.  
  14. pts << RuTils::Pluralization::sum_string(amount.to_i, 1, "рубль", "рубля", "рублей") unless amount.to_i == 0
  15. if amount.kind_of?(Float)
  16. remainder = (amount.divmod(1)[1]*100).round
  17. if (remainder == 100)
  18. pts = [RuTils::Pluralization::sum_string(amount.to_i+1, 1, 'рубль', 'рубля', 'рублей')]
  19. else
  20. pts << RuTils::Pluralization::sum_string(remainder.to_i, 2, 'копейка', 'копейки', 'копеек')
  21. end
  22. end
  23.  
  24. pts.join(' ')
  25. end
  26.  
  27. def self.kopeek(amount)
  28. pts = []
  29. r, k = (amount/100.0).floor, (amount - ((amount/100.0).floor * 100)).to_i
  30. pts << RuTils::Pluralization::sum_string(r, 1, "рубль", "рубля", "рублей") unless r.zero?
  31. pts << RuTils::Pluralization::sum_string(k, 2, 'копейка', 'копейки', 'копеек') unless k.zero?
  32. pts.join(' ')
  33. end
  34.  
  35. # Выполняет преобразование числа из цифрого вида в символьное
  36. # amount - числительное
  37. # gender = 1 - мужской, = 2 - женский, = 3 - средний
  38. # one_item - именительный падеж единственного числа (= 1)
  39. # two_items - родительный падеж единственного числа (= 2-4)
  40. # five_items - родительный падеж множественного числа ( = 5-10)
  41. def self.sum_string(amount, gender, one_item='', two_items='', five_items='')
  42. into = ''
  43. tmp_val ||= 0
  44.  
  45. return "ноль " + five_items if amount == 0
  46.  
  47. tmp_val = amount
  48.  
  49. # единицы
  50. into, tmp_val = sum_string_fn(into, tmp_val, gender, one_item, two_items, five_items)
  51.  
  52. return into if tmp_val == 0
  53.  
  54. # тысячи
  55. into, tmp_val = sum_string_fn(into, tmp_val, 2, "тысяча", "тысячи", "тысяч")
  56.  
  57. return into if tmp_val == 0
  58.  
  59. # миллионы
  60. into, tmp_val = sum_string_fn(into, tmp_val, 1, "миллион", "миллиона", "миллионов")
  61.  
  62. return into if tmp_val == 0
  63.  
  64. # миллиардов
  65. into, tmp_val = sum_string_fn(into, tmp_val, 1, "миллиард", "миллиарда", "миллиардов")
  66. return into
  67. end
  68.  
  69. private
  70. def self.sum_string_fn(into, tmp_val, gender, one_item='', two_items='', five_items='')
  71. rest, rest1, end_word, ones, tens, hundreds = [nil]*6
  72. #
  73. rest = tmp_val % 1000
  74. tmp_val = tmp_val / 1000
  75. if rest == 0
  76. # последние три знака нулевые
  77. into = five_items + " " if into == ""
  78. return [into, tmp_val]
  79. end
  80. #
  81. # начинаем подсчет с Rest
  82. end_word = five_items
  83. # сотни
  84. hundreds = case rest / 100
  85. when 0 then ""
  86. when 1 then "сто "
  87. when 2 then "двести "
  88. when 3 then "триста "
  89. when 4 then "четыреста "
  90. when 5 then "пятьсот "
  91. when 6 then "шестьсот "
  92. when 7 then "семьсот "
  93. when 8 then "восемьсот "
  94. when 9 then "девятьсот "
  95. end
  96.  
  97. # десятки
  98. rest = rest % 100
  99. rest1 = rest / 10
  100. ones = ""
  101. tens = case rest1
  102. when 0 then ""
  103. when 1 # особый случай
  104. case rest
  105. when 10 then "десять "
  106. when 11 then "одиннадцать "
  107. when 12 then "двенадцать "
  108. when 13 then "тринадцать "
  109. when 14 then "четырнадцать "
  110. when 15 then "пятнадцать "
  111. when 16 then "шестнадцать "
  112. when 17 then "семнадцать "
  113. when 18 then "восемнадцать "
  114. when 19 then "девятнадцать "
  115. end
  116. when 2 then "двадцать "
  117. when 3 then "тридцать "
  118. when 4 then "сорок "
  119. when 5 then "пятьдесят "
  120. when 6 then "шестьдесят "
  121. when 7 then "семьдесят "
  122. when 8 then "восемьдесят "
  123. when 9 then "девяносто "
  124. end
  125. #
  126. if rest1 < 1 or rest1 > 1 # единицы
  127. case rest % 10
  128. when 1
  129. ones = case gender
  130. when 1 then "один "
  131. when 2 then "одна "
  132. when 3 then "одно "
  133. end
  134. end_word = one_item
  135. when 2
  136. if gender == 2
  137. ones = "две "
  138. else
  139. ones = "два "
  140. end
  141. end_word = two_items
  142. when 3
  143. ones = "три " if end_word = two_items # TODO - WTF?
  144. when 4
  145. ones = "четыре " if end_word = two_items # TODO - WTF?
  146. when 5
  147. ones = "пять "
  148. when 6
  149. ones = "шесть "
  150. when 7
  151. ones = "семь "
  152. when 8
  153. ones = "восемь "
  154. when 9
  155. ones = "девять "
  156. end
  157. end
  158.  
  159. # сборка строки
  160. plural = [hundreds, tens, ones, end_word, " ", into].join.strip
  161. return [plural, tmp_val]
  162. end
  163.  
  164. # Реализует вывод прописью любого объекта, реализующего Float
  165. module FloatFormatting
  166.  
  167. # Выдает сумму прописью с учетом дробной доли. Дробная доля округляется до миллионной, или (если
  168. # дробная доля оканчивается на нули) до ближайшей доли ( 500 тысячных округляется до 5 десятых).
  169. # Дополнительный аргумент - род существительного (1 - мужской, 2- женский, 3-средний)
  170. def propisju(gender = 2)
  171. raise "Это не число!" if self.nan?
  172.  
  173. st = RuTils::Pluralization::sum_string(self.to_i, gender, "целая", "целых", "целых")
  174.  
  175. remainder = self.to_s.match(/\.(\d+)/)[1]
  176.  
  177. signs = remainder.to_s.size- 1
  178.  
  179. it = [["десятая", "десятых"]]
  180. it << ["сотая", "сотых"]
  181. it << ["тысячная", "тысячных"]
  182. it << ["десятитысячная", "десятитысячных"]
  183. it << ["стотысячная", "стотысячных"]
  184. it << ["миллионная", "милллионных"]
  185. it << ["десятимиллионная", "десятимилллионных", "десятимиллионных"]
  186. it << ["стомиллионная", "стомилллионных", "стомиллионных"]
  187. it << ["миллиардная", "миллиардных", "миллиардных"]
  188. it << ["десятимиллиардная", "десятимиллиардных", "десятимиллиардных"]
  189. it << ["стомиллиардная", "стомиллиардных", "стомиллиардных"]
  190. it << ["триллионная", "триллионных", "триллионных"]
  191.  
  192. while it[signs].nil?
  193. remainder = (remainder/10).round
  194. signs = remainder.to_s.size- 1
  195. end
  196.  
  197. suf1, suf2, suf3 = it[signs][0], it[signs][1], it[signs][2]
  198. st + " " + RuTils::Pluralization::sum_string(remainder.to_i, 2, suf1, suf2, suf2)
  199. end
  200.  
  201. def propisju_items(gender=1, *forms)
  202. if self == self.to_i
  203. return self.to_i.propisju_items(gender, *forms)
  204. else
  205. self.propisju(gender) + " " + forms[1]
  206. end
  207. end
  208.  
  209. end
  210.  
  211. # Реализует вывод прописью любого объекта, реализующего Numeric
  212. module NumericFormatting
  213. # Выбирает корректный вариант числительного в зависимости от рода и числа и оформляет сумму прописью
  214. # 234.propisju => "двести сорок три"
  215. # 221.propisju(2) => "двести двадцать одна"
  216. def propisju(gender = 1)
  217. RuTils::Pluralization::sum_string(self, gender, "")
  218. end
  219.  
  220. def propisju_items(gender=1, *forms)
  221. self.propisju(gender) + " " + RuTils::Pluralization::choose_plural(self.to_i, *forms)
  222. end
  223.  
  224. # Выбирает корректный вариант числительного в зависимости от рода и числа. Например:
  225. # * 4.items("колесо", "колеса", "колес") => "колеса"
  226. def items(one_item, two_items, five_items)
  227. RuTils::Pluralization::choose_plural(self, one_item, two_items, five_items)
  228. end
  229.  
  230. # Выводит сумму в рублях прописью. Например:
  231. # * (15.4).rublej => "пятнадцать рублей сорок копеек"
  232. # * 1.rubl => "один рубль"
  233. # * (3.14).rublja => "три рубля четырнадцать копеек"
  234. def rublej
  235. RuTils::Pluralization::rublej(self)
  236. end
  237. alias :rubl :rublej
  238. alias :rublja :rublej
  239. end
  240.  
  241. module FixnumFormatting
  242. def kopeek
  243. RuTils::Pluralization.kopeek(self)
  244. end
  245. alias :kopeika :kopeek
  246. alias :kopeiki :kopeek
  247. end
  248. end
  249. end
  250.  
  251. class Object::Numeric
  252. include RuTils::Pluralization::NumericFormatting
  253. end
  254.  
  255. class Object::Fixnum
  256. include RuTils::Pluralization::FixnumFormatting
  257. end
  258.  
  259. class Object::Float
  260. include RuTils::Pluralization::FloatFormatting
  261. end
Add Comment
Please, Sign In to add comment