cm-ru_propisju 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5c6ed9fd84239013e1f843a17b8d5e6659438553
4
+ data.tar.gz: 2acb17150b1b40198ef65540f8184490fb252ce1
5
+ SHA512:
6
+ metadata.gz: 034a7a27a9bc876b07fc5ee8337a7bf5b7665eee93ebfdf1cce3e335e2cfbcc1558bd9337c69d5a5d3b0ca36e28ca85900de4e48fac38948d787aa95e6e6e761
7
+ data.tar.gz: aa8aa75b1e4b500e963be6c62a015ce47a61020e194e046c4f504db97f950859c3e95b11f8f3d0b817b5293f73c666a1f4086ebd261b2d913f3b121299097842
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :development do
4
+ gem "jeweler", '1.8.4' # Last one without the stupid nokogiri dependency
5
+ gem "rake"
6
+ gem "test-unit"
7
+ end
@@ -0,0 +1,61 @@
1
+ === 2.4.0
2
+
3
+ * Добавлен творительный падеж (только для русской локали) (https://github.com/julik/ru_propisju/pull/15)
4
+
5
+ === 2.3.0
6
+
7
+ * Добавлена поддержка казахстанского тенге - nodkz
8
+
9
+ === 2.2.3
10
+
11
+ * Более строгое форматирование долей (https://github.com/julik/ru_propisju/pull/12)
12
+
13
+ === 2.2.2
14
+
15
+ * Форматирование долей могло вызвать ошибку (https://github.com/julik/ru_propisju/issues/10)
16
+
17
+ === 2.2.1
18
+
19
+ * Опечатка в украинских числительных (https://github.com/julik/ru_propisju/pull/9)
20
+
21
+ === 2.2.0
22
+
23
+ * Добавлены методы rublej_extended_format, digit_rublej
24
+
25
+ === 2.1.4
26
+
27
+ * Правильная обработка нулей в суммах
28
+
29
+ === 2.1.3
30
+
31
+ * Починен порядок тысячных долей на ruby 1.8x
32
+
33
+ === 2.1.2
34
+
35
+ * Починено https://github.com/julik/ru_propisju/issues/5
36
+
37
+ === 2.1.1
38
+
39
+ * Починено https://github.com/julik/ru_propisju/issues/3
40
+
41
+ === 2.1.0
42
+
43
+ * Восстановлен старый API для choose_plural
44
+ * Добавлено исключение UnknownLocale
45
+
46
+ === 2.0.0
47
+
48
+ * Добавлена поддержка украинского языка - iz65535
49
+
50
+ === 1.2.0
51
+
52
+ * Добавлена поддержка И Еще Нескольких Валют (тм) - terraplane
53
+
54
+ === 1.1.0
55
+
56
+ * На самом деле количество копеек пишется цифрами
57
+
58
+ === 1.0.0
59
+
60
+ * Модуль вынут из RuTils
61
+
@@ -0,0 +1,52 @@
1
+ = ru_propisju
2
+
3
+ * http://github.com/julik/ru_propisju
4
+
5
+ == DESCRIPTION:
6
+
7
+ Выводит сумму прописью и суммы копеек, рублей и гривен. Помогает в выборе правильного числительного.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ Прекрасность.
12
+
13
+ == SYNOPSIS:
14
+
15
+ RuPropisju.rublej(123.78) #=> "сто двадцать три рубля 78 копеек"
16
+ RuPropisju.propisju_shtuk(212.40, 2, ["сволочь", "сволочи", "сволочей"]) #=> "двести двенадцать целых четыре десятых сволочи"
17
+ RuPropisju.rublej_extended_format(1000, :ru, fraction_formatter: '%02d', integrals_formatter: '+ %d', integrals_delimiter: ' ', always_show_fraction: true) #=> "+ 1 000 рублей 00 копеек (одна тысяча рублей 00 копеек)"
18
+
19
+ 'Продается в ' + RuPropisju.propisju_shtuk(147, 1, ["городе", "городах", "городах"], :ru_in) #=> "Продается в ста сорока семи городах"
20
+
21
+ == REQUIREMENTS:
22
+
23
+ * Прямые руки
24
+
25
+ == INSTALL:
26
+
27
+ sudo gem install ru_propisju
28
+
29
+ == LICENSE:
30
+
31
+ (The MIT License)
32
+
33
+ Copyright (c) 2011 me@julik.nl
34
+
35
+ Permission is hereby granted, free of charge, to any person obtaining
36
+ a copy of this software and associated documentation files (the
37
+ 'Software'), to deal in the Software without restriction, including
38
+ without limitation the rights to use, copy, modify, merge, publish,
39
+ distribute, sublicense, and/or sell copies of the Software, and to
40
+ permit persons to whom the Software is furnished to do so, subject to
41
+ the following conditions:
42
+
43
+ The above copyright notice and this permission notice shall be
44
+ included in all copies or substantial portions of the Software.
45
+
46
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
47
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
48
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
49
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
50
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
51
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
52
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # -*- ruby -*-
3
+ $KCODE = 'u' if RUBY_VERSION < '1.9.0'
4
+
5
+ require 'rubygems'
6
+ require 'jeweler'
7
+ require './lib/ru_propisju'
8
+
9
+ Jeweler::Tasks.new do |gem|
10
+ gem.version = RuPropisju::VERSION
11
+ gem.name = "ru_propisju"
12
+ gem.summary = "Cумма прописью"
13
+ gem.email = "me@julik.nl"
14
+ gem.homepage = "http://github.com/julik/ru_propisju"
15
+ gem.authors = ["Julik Tarkhanov"]
16
+ gem.license = 'MIT'
17
+
18
+ # Do not package invisibles
19
+ gem.files.exclude ".*"
20
+ end
21
+ Jeweler::RubygemsDotOrgTasks.new
22
+
23
+ require 'rake/testtask'
24
+ desc "Run all tests"
25
+ Rake::TestTask.new("test") do |t|
26
+ t.libs << "test"
27
+ t.pattern = 'test/**/test_*.rb'
28
+ t.verbose = true
29
+ end
30
+
31
+ task :default => [ :test ]
32
+
33
+ # vim: syntax=ruby
@@ -0,0 +1,50 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{cm-ru_propisju}
8
+ s.version = "2.4.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Julik Tarkhanov"]
12
+ s.date = %q{2015-04-13}
13
+ s.email = %q{me@julik.nl}
14
+ s.extra_rdoc_files = [
15
+ "README.rdoc"
16
+ ]
17
+ s.files = [
18
+ "Gemfile",
19
+ "History.txt",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "lib/ru_propisju.rb",
23
+ "cm-ru_propisju.gemspec",
24
+ "test/test_ru_propisju.rb"
25
+ ]
26
+ s.homepage = %q{http://github.com/julik/ru_propisju}
27
+ s.licenses = ["MIT"]
28
+ s.require_paths = ["lib"]
29
+ s.rubygems_version = %q{1.6.2}
30
+ s.summary = %q{Cумма прописью}
31
+
32
+ if s.respond_to? :specification_version then
33
+ s.specification_version = 3
34
+
35
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
36
+ s.add_development_dependency(%q<jeweler>, ["= 1.8.4"])
37
+ s.add_development_dependency(%q<rake>, [">= 0"])
38
+ s.add_development_dependency(%q<test-unit>, [">= 0"])
39
+ else
40
+ s.add_dependency(%q<jeweler>, ["= 1.8.4"])
41
+ s.add_dependency(%q<rake>, [">= 0"])
42
+ s.add_dependency(%q<test-unit>, [">= 0"])
43
+ end
44
+ else
45
+ s.add_dependency(%q<jeweler>, ["= 1.8.4"])
46
+ s.add_dependency(%q<rake>, [">= 0"])
47
+ s.add_dependency(%q<test-unit>, [">= 0"])
48
+ end
49
+ end
50
+
@@ -0,0 +1,766 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $KCODE = 'u' if RUBY_VERSION < '1.9.0'
3
+
4
+ # Самый лучший, прекрасный, кривой и неотразимый суперпечататель суммы прописью для Ruby.
5
+ #
6
+ # RuPropisju.rublej(123) # "сто двадцать три рубля"
7
+ module RuPropisju
8
+
9
+ VERSION = '2.4.0'
10
+
11
+ # http://www.xe.com/symbols.php
12
+ # (лица, приближенные форексам и всяким там валютам и курсам)
13
+ # говорят, что код валюты российского рубля - rub
14
+ CURRENCIES = {
15
+ "rur" => :rublej,
16
+ "rub" => :rublej,
17
+ "usd" => :dollarov,
18
+ "uah" => :griven,
19
+ "eur" => :evro,
20
+ "kzt" => :tenge,
21
+ }
22
+
23
+ SUPPORTED_CURRENCIES = CURRENCIES.keys.join ','
24
+
25
+ TRANSLATIONS = {
26
+ 'ru' => {
27
+ 0 => "",
28
+ '0' => "ноль",
29
+ :thousands => ["тысяча", "тысячи", "тысяч"],
30
+ :millions => ["миллион", "миллиона", "миллионов"],
31
+ :billions => ["миллиард", "миллиарда", "миллиардов"],
32
+ 100 => "сто",
33
+ 200 => "двести",
34
+ 300 => "триста",
35
+ 400 => "четыреста",
36
+ 500 => "пятьсот",
37
+ 600 => "шестьсот",
38
+ 700 => "семьсот",
39
+ 800 => "восемьсот",
40
+ 900 => "девятьсот",
41
+
42
+ 10 => "десять",
43
+ 11 => "одиннадцать",
44
+ 12 => "двенадцать",
45
+ 13 => "тринадцать",
46
+ 14 => "четырнадцать",
47
+ 15 => "пятнадцать",
48
+ 16 => "шестнадцать",
49
+ 17 => "семнадцать",
50
+ 18 => "восемнадцать",
51
+ 19 => "девятнадцать",
52
+ 20 => "двадцать",
53
+ 30 => "тридцать",
54
+ 40 => "сорок",
55
+ 50 => "пятьдесят",
56
+ 60 => "шестьдесят",
57
+ 70 => "семьдесят",
58
+ 80 => "восемьдесят",
59
+ 90 => "девяносто",
60
+ # единицы, местами - c учетом рода
61
+ 1 => {1 => "один", 2 => 'одна', 3 => 'одно'},
62
+ 2 => {1 => "два", 2 => 'две', 3 => 'два'},
63
+ 3 => "три",
64
+ 4 => "четыре",
65
+ 5 => "пять",
66
+ 6 => "шесть",
67
+ 7 => "семь",
68
+ 8 => "восемь",
69
+ 9 => "девять",
70
+ :rub_integral => ["рубль", "рубля", "рублей"],
71
+ :rub_fraction => ['копейка', 'копейки', 'копеек'],
72
+ :uah_integral => ["гривна", "гривны", "гривен"],
73
+ :uah_fraction => ['копейка', 'копейки', 'копеек'],
74
+ :kzt_integral => ["тенге", "тенге", "тенге"],
75
+ :kzt_fraction => ['тиын', 'тиына', 'тиынов'],
76
+ :eur_integral => ["евро", "евро", "евро"],
77
+ # по опыту моей прошлой работы в банке
78
+ # центами называют дробную часть доллара
79
+ # а дробную часть евро называют евроцентом
80
+ :eur_fraction => ["цент", "цента", "центов"],
81
+ :usd_integral => ["доллар", "доллара", "долларов"],
82
+ :usd_fraction => ['цент', 'цента', 'центов'],
83
+ },
84
+ 'ru_in' => { # Предложный падеж, например в 2 городах
85
+ 0 => "",
86
+ '0' => "нуле",
87
+ :thousands => ["тысяче", "тысячах", "тысячах"],
88
+ :millions => ["миллионе", "миллионах", "миллионах"],
89
+ :billions => ["миллиарде", "миллиардах", "миллиардах"],
90
+ 100 => "ста",
91
+ 200 => "двухстах",
92
+ 300 => "трёхстах",
93
+ 400 => "четырёхстах",
94
+ 500 => "пятистах",
95
+ 600 => "шестистах",
96
+ 700 => "семистах",
97
+ 800 => "восьмистах",
98
+ 900 => "девятистах",
99
+
100
+ 10 => "десяти",
101
+ 11 => "одиннадцати",
102
+ 12 => "двенадцати",
103
+ 13 => "тринадцати",
104
+ 14 => "четырнадцати",
105
+ 15 => "пятнадцати",
106
+ 16 => "шестнадцати",
107
+ 17 => "семнадцати",
108
+ 18 => "восемнадцати",
109
+ 19 => "девятнадцати",
110
+ 20 => "двадцати",
111
+ 30 => "тридцати",
112
+ 40 => "сорока",
113
+ 50 => "пятидесяти",
114
+ 60 => "шестидесяти",
115
+ 70 => "семидесяти",
116
+ 80 => "восьмидесяти",
117
+ 90 => "девяноста",
118
+ # единицы, местами - c учетом рода
119
+ 1 => { 1 => 'одном', 2 => 'одной', 3 => 'одном' },
120
+ 2 => { 1 => 'двух', 2 => 'двух', 3 => 'двух' },
121
+ 3 => "трёх",
122
+ 4 => "четырёх",
123
+ 5 => "пяти",
124
+ 6 => "шести",
125
+ 7 => "семи",
126
+ 8 => "восьми",
127
+ 9 => "девяти",
128
+ :rub_integral => %w[рубле рублях рублях],
129
+ :rub_fraction => %w[копейке копейках копейках],
130
+ :uah_integral => %w[гривне гривнах гривнах],
131
+ :uah_fraction => %w[копейке копейках копейках],
132
+ :kzt_integral => %w[тенге тенге тенге],
133
+ :kzt_fraction => %w[тиыне тиынах тиынах],
134
+ :eur_integral => %w[евро евро евро],
135
+ # по опыту моей прошлой работы в банке
136
+ # центами называют дробную часть доллара
137
+ # а дробную часть евро называют евроцентом
138
+ :eur_fraction => %w[центе центах центах],
139
+ :usd_integral => %w[долларе долларах долларах],
140
+ :usd_fraction => %w[центе центах центах],
141
+ },
142
+ 'ru_gen' => { # Родительный падеж, например в течение одного рабочего дня, пяти ночей (нуля рабочих дней)
143
+ 0 => '',
144
+ '0' => 'нуля',
145
+ :thousands => %w[тысячи тысяч тысяч],
146
+ :millions => %w[миллиона миллионов миллионов],
147
+ :billions => %w[миллиарда миллиардов миллиардов],
148
+ 100 => 'ста',
149
+ 200 => 'двухсот',
150
+ 300 => 'трёхсот',
151
+ 400 => 'четырёхсот',
152
+ 500 => 'пятисот',
153
+ 600 => 'шестисот',
154
+ 700 => 'семисот',
155
+ 800 => 'восьмисот',
156
+ 900 => 'девятисот',
157
+
158
+ 10 => 'десяти',
159
+ 11 => 'одиннадцати',
160
+ 12 => 'двенадцати',
161
+ 13 => 'тринадцати',
162
+ 14 => 'четырнадцати',
163
+ 15 => 'пятнадцати',
164
+ 16 => 'шестнадцати',
165
+ 17 => 'семнадцати',
166
+ 18 => 'восемнадцати',
167
+ 19 => 'девятнадцати',
168
+ 20 => 'двадцати',
169
+ 30 => 'тридцати',
170
+ 40 => 'сорока',
171
+ 50 => 'пятидесяти',
172
+ 60 => 'шестидесяти',
173
+ 70 => 'семидесяти',
174
+ 80 => 'восьмидесяти',
175
+ 90 => 'девяноста',
176
+ # единицы, местами - c учетом рода
177
+ 1 => { 1 => 'одного', 2 => 'одной', 3 => 'одного' },
178
+ 2 => { 1 => 'двух', 2 => 'двух', 3 => 'двух' },
179
+ 3 => 'трёх',
180
+ 4 => 'четырёх',
181
+ 5 => 'пяти',
182
+ 6 => 'шести',
183
+ 7 => 'семи',
184
+ 8 => 'восьми',
185
+ 9 => 'девяти',
186
+ :rub_integral => %w[рубля рублей рублей],
187
+ :rub_fraction => %w[копейки копеек копеек],
188
+ :uah_integral => %w[гривны гривен гривен],
189
+ :uah_fraction => %w[копейки копеек копеек],
190
+ :kzt_integral => %w[тенге тенге тенге],
191
+ :kzt_fraction => %w[тиына тиынов тиынов],
192
+ :eur_integral => %w[евро евро евро],
193
+ # TODO: решить как же всё-таки звать дробную часть евро: "цент" или "евроцент"
194
+ :eur_fraction => %w[цента центов центов],
195
+ :usd_integral => %w[доллара долларов долларов],
196
+ :usd_fraction => %w[цента центов центов],
197
+ },
198
+ 'ru_from' => {
199
+ 0 => "",
200
+ '0' => "нулём",
201
+ :thousands => ["тысячю", "тысячами", "тысячами"],
202
+ :millions => ["миллионом", "миллионами", "миллионами"],
203
+ :billions => ["миллиардом", "миллиардами", "миллиардами"],
204
+ 100 => "ста",
205
+ 200 => "двумястами",
206
+ 300 => "тремястами",
207
+ 400 => "четырьмястами",
208
+ 500 => "пятьюстами",
209
+ 600 => "шестьюстами",
210
+ 700 => "семьюстами",
211
+ 800 => "восьмьюстами",
212
+ 900 => "девятьюстами",
213
+
214
+ 10 => "десятью",
215
+ 11 => "одиннадцатью",
216
+ 12 => "двенадцатью",
217
+ 13 => "тринадцатью",
218
+ 14 => "четырнадцатью",
219
+ 15 => "пятнадцатью",
220
+ 16 => "шестнадцатью",
221
+ 17 => "семнадцатью",
222
+ 18 => "восемнадцатью",
223
+ 19 => "девятнадцатью",
224
+ 20 => "двадцатью",
225
+ 30 => "тридцатью",
226
+ 40 => "сорока",
227
+ 50 => "пятьюдесятью",
228
+ 60 => "шестьюдесятью",
229
+ 70 => "семьюдесятью",
230
+ 80 => "восьмьюдесятью",
231
+ 90 => "девяноста",
232
+ # единицы, местами - c учетом рода
233
+ 1 => {1 => "одним", 2 => 'одной', 3 => 'одним'},
234
+ 2 => {1 => "двумя", 2 => 'двумя', 3 => 'двумя'},
235
+ 3 => "тремя",
236
+ 4 => "четырьмя",
237
+ 5 => "пятью",
238
+ 6 => "шестью",
239
+ 7 => "семью",
240
+ 8 => "восьмью",
241
+ 9 => "девятью",
242
+ :rub_integral => ["рублём", "рублями", "рублями"],
243
+ :rub_fraction => ['копейкой', 'копейками', 'копейками'],
244
+ :uah_integral => ["гривной", "гривнами", "гривнами"],
245
+ :uah_fraction => ['копейкой', 'копейками', 'копейками'],
246
+ :kzt_integral => ["тенге", "тенге", "тенге"],
247
+ :kzt_fraction => ['тиыной', 'тиынами', 'тиынами'],
248
+ :eur_integral => ["евро", "евро", "евро"],
249
+ # по опыту моей прошлой работы в банке
250
+ # центами называют дробную часть доллара
251
+ # а дробную часть евро называют евроцентом
252
+ :eur_fraction => ["центом", "центами", "центами"],
253
+ :usd_integral => ["долларом", "долларами", "долларами"],
254
+ :usd_fraction => ['центом', 'центами', 'центами'],
255
+ },
256
+ 'ua' => {
257
+ 0 => "",
258
+ '0' => "нуль",
259
+ :thousands => ["тисяча", "тисячі", "тисяч"],
260
+ :millions => ["мільйон", "мільйона", "мільйонів"],
261
+ :billions => ["мільярд", "мільярда", "мільярдів"],
262
+ 100 => "сто",
263
+ 200 => "двісті",
264
+ 300 => "триста",
265
+ 400 => "чотириста",
266
+ 500 => "п'ятьсот",
267
+ 600 => "шістсот",
268
+ 700 => "сімсот",
269
+ 800 => "вісімсот",
270
+ 900 => "дев'ятсот",
271
+
272
+ 10 => "десять",
273
+ 11 => "одинадцять",
274
+ 12 => "дванадцять",
275
+ 13 => "тринадцять",
276
+ 14 => "чотирнадцять",
277
+ 15 => "п'ятнадцять",
278
+ 16 => "шістнадцять",
279
+ 17 => "сімнадцять",
280
+ 18 => "вісімнадцять",
281
+ 19 => "дев'ятнадцять",
282
+ 20 => "двадцять",
283
+ 30 => "тридцять",
284
+ 40 => "сорок",
285
+ 50 => "п'ятьдесят",
286
+ 60 => "шістдесят",
287
+ 70 => "сімдесят",
288
+ 80 => "вісімдесят",
289
+ 90 => "дев'яносто",
290
+ # единицы, местами - c учетом рода
291
+ 1 => {1 => "один", 2 => 'одна', 3 => 'одне'},
292
+ 2 => {1 => "два", 2 => 'дві', 3 => 'два'},
293
+ 3 => "три",
294
+ 4 => "чотири",
295
+ 5 => "п'ять",
296
+ 6 => "шість",
297
+ 7 => "сім",
298
+ 8 => "вісім",
299
+ 9 => "дев'ять",
300
+ :rub_integral => ["рубль", "рубля", "рублів"],
301
+ :rub_fraction => ['копійка', 'копійки', 'копійок'],
302
+ :uah_integral => ["гривня", "гривні", "гривень"],
303
+ :uah_fraction => ["копійка", "копійки", "копійок"],
304
+ :kzt_integral => ["тенге", "тенге", "тенге"],
305
+ :kzt_fraction => ['тиын', 'тиына', 'тиынов'],
306
+ :eur_integral => ["євро", "євро", "євро"],
307
+ :eur_fraction => ["євроцент", "євроцента", "євроцентів"],
308
+ :usd_integral => ["долар", "долара", "доларів"],
309
+ :usd_fraction => ['цент', 'цента', 'центів'],
310
+ }
311
+ }
312
+ # Переименовал предложный падеж из _in в _pre (prepositional)
313
+ # Оставил 'ru_in' для обратной совместимости
314
+ TRANSLATIONS['ru_pre'] = TRANSLATIONS['ru_in']
315
+
316
+ MONEY_GENDERS = {
317
+ :rub => 1,
318
+ :usd => 1,
319
+ :uah => 2,
320
+ :eur => 1,
321
+ :kzt => 1,
322
+ }
323
+
324
+
325
+ # Кидается при запросе неизвестной валюты
326
+ class UnknownCurrency < ArgumentError
327
+ end
328
+
329
+ # Кидается при запросе неизвестного языка
330
+ class UnknownLocale < ArgumentError
331
+ end
332
+
333
+ # Выбирает нужный падеж существительного в зависимости от числа
334
+ #
335
+ # choose_plural(3, "штука", "штуки", "штук") #=> "штуки"
336
+ def choose_plural(amount, *variants)
337
+ variants = variants.flatten
338
+
339
+ mod_ten = amount % 10
340
+ mod_hundred = amount % 100
341
+ variant = if (mod_ten == 1 && mod_hundred != 11)
342
+ 1
343
+ else
344
+ if mod_ten >= 2 && mod_ten <= 4 && (mod_hundred <10 || mod_hundred % 100>=20)
345
+ 2
346
+ else
347
+ 3
348
+ end
349
+ end
350
+ variants[variant-1]
351
+ end
352
+
353
+ # Выводит сумму прописью в зависимости от выбранной валюты.
354
+ # Поддерживаемые валюты: rur, usd, uah, eur
355
+ #
356
+ # amount_in_words(345.2, 'rur') #=> "триста сорок пять рублей 20 копеек"
357
+ def amount_in_words(amount, currency, locale = :ru, options = {})
358
+ currency = currency.to_s.downcase
359
+ unless CURRENCIES.has_key? currency
360
+ raise UnknownCurrency, "Unsupported currency #{currency}, the following are supported: #{SUPPORTED_CURRENCIES}"
361
+ end
362
+ method(CURRENCIES[currency]).call(amount, locale, options)
363
+ end
364
+
365
+ # Выводит целое или дробное число как сумму в рублях прописью
366
+ #
367
+ # rublej(345.2) #=> "триста сорок пять рублей 20 копеек"
368
+ #
369
+ def rublej(amount, locale = :ru, options = {})
370
+ integrals_key = :rub_integral
371
+ fractions_key = :rub_fraction
372
+ money_gender = MONEY_GENDERS[:rub]
373
+
374
+ money(amount, locale, integrals_key, fractions_key, money_gender, true, false, options)
375
+ end
376
+
377
+ # Выводит целое или дробное число как сумму в расширенном формате
378
+ #
379
+ # rublej_extended_format(345.2) #=> "345 рублей 20 копеек (триста сорок пять рублей 20 копеек)"
380
+ #
381
+ def rublej_extended_format(amount, locale = :ru, options = {})
382
+ "#{digit_rublej(amount, locale, options)} (#{rublej(amount, locale, options)})"
383
+ end
384
+
385
+ # Выводит целое или дробное число как сумму в рублях и копейках не прописью
386
+ #
387
+ # digit_rublej(345.2) #=> "345 рублей 20 копеек"
388
+ #
389
+
390
+ def digit_rublej(amount, locale = :ru, options = {})
391
+ integrals_key = :rub_integral
392
+ fractions_key = :rub_fraction
393
+ money_gender = MONEY_GENDERS[:rub]
394
+
395
+ money(amount, locale, integrals_key, fractions_key, money_gender, true, true, options)
396
+ end
397
+ # Выбирает корректный вариант числительного в зависимости от рода и числа и оформляет сумму прописью
398
+ #
399
+ # propisju(243, 1) => "двести сорок три"
400
+ # propisju(221, 2) => "двести двадцать одна"
401
+ def propisju(amount, gender, locale = :ru)
402
+ if amount.is_a?(Integer) || amount.is_a?(Bignum)
403
+ propisju_int(amount, gender, [], locale)
404
+ else # также сработает для Decimal, дробные десятичные числительные в долях поэтому женского рода
405
+ propisju_float(amount, locale)
406
+ end
407
+ end
408
+
409
+ # Выводит целое или дробное число как сумму в гривнах прописью
410
+ #
411
+ # griven(32) #=> "тридцать две гривны"
412
+ def griven(amount, locale = :ru, options = {})
413
+ integrals_key = :uah_integral
414
+ fractions_key = :uah_fraction
415
+ money_gender = MONEY_GENDERS[:uah]
416
+
417
+ money(amount, locale, integrals_key, fractions_key, money_gender, false, false, options)
418
+ end
419
+
420
+ # Выводит целое или дробное число как сумму в долларах прописью
421
+ #
422
+ # dollarov(32) #=> "тридцать два доллара"
423
+ def dollarov(amount, locale = :ru, options = {})
424
+ integrals_key = :usd_integral
425
+ fractions_key = :usd_fraction
426
+ money_gender = MONEY_GENDERS[:usd]
427
+
428
+ money(amount, locale, integrals_key, fractions_key, money_gender, false, false, options)
429
+ end
430
+
431
+ # Выводит целое или дробное число как сумму в евро прописью
432
+ #
433
+ # evro(32) #=> "тридцать два евро"
434
+ def evro(amount, locale = :ru, options = {})
435
+ integrals_key = :eur_integral
436
+ fractions_key = :eur_fraction
437
+ money_gender = MONEY_GENDERS[:eur]
438
+
439
+ money(amount, locale, integrals_key, fractions_key, money_gender, false, false, options)
440
+ end
441
+
442
+ # Выводит целое или дробное число как сумму в тенге прописью
443
+ #
444
+ # tenge(32) #=> "тридцать два тенге"
445
+ def tenge(amount, locale = :ru, options = {})
446
+ integrals_key = :kzt_integral
447
+ fractions_key = :kzt_fraction
448
+ money_gender = MONEY_GENDERS[:kzt]
449
+
450
+ money(amount, locale, integrals_key, fractions_key, money_gender, false, false, options)
451
+ end
452
+
453
+ # Выводит сумму прописью в рублях по количеству копеек
454
+ #
455
+ # kopeek(343) #=> "три рубля 43 копейки"
456
+ def kopeek(amount, locale = :ru, options = {})
457
+ rublej(amount / 100.0, locale, options)
458
+ end
459
+
460
+ # Выводит сумму данного существительного прописью и выбирает правильное число и падеж
461
+ #
462
+ # RuPropisju.propisju_shtuk(21, 3, "колесо", "колеса", "колес") #=> "двадцать одно колесо"
463
+ # RuPropisju.propisju_shtuk(21, 1, "мужик", "мужика", "мужиков") #=> "двадцать один мужик"
464
+ def propisju_shtuk(items, gender, forms, locale = :ru)
465
+ elements = if (items == items.to_i)
466
+ [propisju(items, gender, locale), choose_plural(items, forms)]
467
+ else
468
+ [propisju(items, gender, locale), forms[1]]
469
+ end
470
+
471
+ elements.join(" ")
472
+ end
473
+
474
+ def money(amount, locale, integrals_key, fractions_key, money_gender, fraction_as_number = false, integrals_as_number = false, options = {})
475
+
476
+ options[:integrals_formatter] ||= '%d'
477
+ options[:fraction_formatter] ||= '%d'
478
+ options[:integrals_delimiter] ||= ''
479
+ options[:always_show_fraction] ||= false
480
+
481
+ locale_data = pick_locale(TRANSLATIONS, locale)
482
+ integrals = locale_data[integrals_key]
483
+ fractions = locale_data[fractions_key]
484
+ return zero(locale_data, integrals, fractions, fraction_as_number, integrals_as_number, options) if amount.zero?
485
+ parts = []
486
+
487
+ unless amount.to_i == 0
488
+ if integrals_as_number
489
+ parts << format_integral(amount.to_i, options) << choose_plural(amount.to_i, integrals)
490
+ else
491
+ parts << propisju_int(amount.to_i, money_gender, integrals, locale)
492
+ end
493
+ end
494
+
495
+ if amount.kind_of?(Float)
496
+ remainder = (amount.divmod(1)[1]*100).round
497
+ if remainder == 100
498
+ parts = [propisju_int(amount.to_i + 1, money_gender, integrals, locale)]
499
+ parts << format(options[:fraction_formatter], 0) << choose_plural(0, fractions) if options[:always_show_fraction]
500
+ else
501
+ if fraction_as_number
502
+ kop = remainder.to_i
503
+ if (!kop.zero? || options[:always_show_fraction])
504
+ parts << format(options[:fraction_formatter], kop) << choose_plural(kop, fractions)
505
+ end
506
+ else
507
+ parts << propisju_int(remainder.to_i, money_gender, fractions, locale)
508
+ end
509
+ end
510
+ else
511
+ parts << format(options[:fraction_formatter], 0) << choose_plural(0, fractions) if options[:always_show_fraction]
512
+ end
513
+
514
+ parts.join(' ')
515
+ end
516
+
517
+ private
518
+
519
+ def zero(locale_data, integrals, fractions, fraction_as_number, integrals_as_number, options)
520
+ integ = integrals_as_number ? format(options[:integrals_formatter], 0) : locale_data['0']
521
+ frac = fraction_as_number ? format(options[:fraction_formatter], 0) : locale_data['0']
522
+ parts = [integ , integrals[-1], frac, fractions[-1]]
523
+ parts.join(' ')
524
+ end
525
+
526
+ # Cоставляет число прописью для чисел до тысячи
527
+
528
+ def compose_ordinal(remaining_amount_or_nil, gender, item_forms = [], locale = :ru)
529
+
530
+ remaining_amount = remaining_amount_or_nil.to_i
531
+
532
+ locale = locale.to_s
533
+
534
+ # Ноль чего-то
535
+ # return "ноль %s" % item_forms[3] if remaining_amount_or_nil.zero?
536
+
537
+ rest, rest1, chosen_ordinal, ones, tens, hundreds = [nil]*6
538
+
539
+ rest = remaining_amount % 1000
540
+ remaining_amount = remaining_amount / 1000
541
+ if rest.zero?
542
+ # последние три знака нулевые
543
+ return item_forms[2]
544
+ end
545
+
546
+ locale_root = pick_locale(TRANSLATIONS, locale)
547
+
548
+ # начинаем подсчет с Rest
549
+ # сотни
550
+ hundreds = locale_root[(rest / 100).to_i * 100]
551
+
552
+ # десятки
553
+ rest = rest % 100
554
+ rest1 = rest / 10
555
+
556
+ # единички
557
+ ones = ""
558
+ tens = locale_root[rest1 == 1 ? rest : rest1 * 10]
559
+
560
+ # индекс выбранной формы
561
+ chosen_ordinal = 2
562
+ if rest1 < 1 || rest1 > 1 # единицы
563
+ value = locale_root[rest % 10]
564
+ # если попался хэш, делаем выбор согласно рода
565
+ value = value[gender] if value.kind_of? Hash
566
+ ones = value
567
+ case rest % 10
568
+ when 1 then chosen_ordinal = 0 # индекс формы меняется
569
+ when 2..4 then chosen_ordinal = 1 # индекс формы меняется
570
+ end
571
+ end
572
+ plural = [
573
+ hundreds,
574
+ tens,
575
+ ones,
576
+ item_forms[chosen_ordinal],
577
+ ].compact.reject(&:empty?).join(' ').strip
578
+
579
+ return plural
580
+ end
581
+
582
+ DECIMALS = {
583
+ 'ru' =>{
584
+ :source_words => [
585
+ 'целая',
586
+ 'десятая',
587
+ 'сотая',
588
+ 'тысячная',
589
+ 'десятитысячная',
590
+ 'стотысячная',
591
+ 'миллионная',
592
+ 'десятимиллионная',
593
+ 'стомиллионная',
594
+ 'миллиардная',
595
+ 'десятимиллиардная',
596
+ 'стомиллиардная',
597
+ 'триллионная'
598
+ ],
599
+ :prefix => ["ая", 'ых'],
600
+ },
601
+ 'ru_in' =>{
602
+ :source_words => [
603
+ 'целой',
604
+ 'десятой',
605
+ 'сотой',
606
+ 'тысячной',
607
+ 'десятитысячной',
608
+ 'стотысячной',
609
+ 'миллионной',
610
+ 'десятимиллионной',
611
+ 'стомиллионной',
612
+ 'миллиардной',
613
+ 'десятимиллиардной',
614
+ 'стомиллиардной',
615
+ 'триллионной'
616
+ ],
617
+ :prefix => ["ой", 'ых'],
618
+ },
619
+ 'ru_from' =>{
620
+ :source_words => [
621
+ 'целой',
622
+ 'десятой',
623
+ 'сотой',
624
+ 'тысячной',
625
+ 'десятитысячной',
626
+ 'стотысячной',
627
+ 'миллионной',
628
+ 'десятимиллионной',
629
+ 'стомиллионной',
630
+ 'миллиардной',
631
+ 'десятимиллиардной',
632
+ 'стомиллиардной',
633
+ 'триллионной'
634
+ ],
635
+ :prefix => ["ой", 'ыми'],
636
+ },
637
+ 'ua' => {
638
+ :source_words => [
639
+ 'ціла',
640
+ 'десята',
641
+ 'сота',
642
+ 'тисячна',
643
+ 'десятитисячна',
644
+ 'стотисячна',
645
+ 'мільйонна',
646
+ 'десятимільйонна',
647
+ 'стомільйонна',
648
+ 'мільярдна',
649
+ 'десятимільярдна',
650
+ 'стомільярдна',
651
+ 'трильонна'
652
+ ],
653
+ :prefix => ["а", 'их'],
654
+ },
655
+ }
656
+ # Добавляем новый префикс для предложного падежа и новые значения для родительного (совпадающие с предложным)
657
+ DECIMALS['ru_pre'] = DECIMALS['ru_in']
658
+ DECIMALS['ru_gen'] = DECIMALS['ru_in']
659
+
660
+ # Выдает сумму прописью с учетом дробной доли. Дробная доля округляется до миллионной, или (если
661
+ # дробная доля оканчивается на нули) до ближайшей доли или точки ( 500 тысячных округляется до 5 десятых, 30.0000 до 30).
662
+ def propisju_float(num, locale = :ru)
663
+ locale_root = pick_locale(DECIMALS, locale)
664
+ source_expression = locale_root[:prefix][0]
665
+ target_prefix = locale_root[:prefix][1]
666
+ words = locale_root[:source_words].map do |e|
667
+ [
668
+ e,
669
+ e.gsub(/#{source_expression}$/, target_prefix),
670
+ e.gsub(/#{source_expression}$/, target_prefix),
671
+ ]
672
+ end.freeze
673
+
674
+ # Укорачиваем до триллионной доли
675
+ formatted = num.to_s[/^\d+(\.\d{0,#{words.length - 1}})?/].gsub(/0+$/, '')
676
+ wholes, decimals = formatted.split(".")
677
+
678
+ return propisju_int(wholes.to_i, 1, [], locale) if decimals.to_i.zero?
679
+
680
+ whole_st = propisju_shtuk(wholes.to_i, 2, words[0], locale)
681
+
682
+ rem_st = propisju_shtuk(decimals.to_i, 2, words[decimals.length], locale)
683
+ [whole_st, rem_st].compact.join(" ")
684
+ end
685
+
686
+ # Выполняет преобразование числа из цифрого вида в символьное
687
+ #
688
+ # amount - числительное
689
+ # gender = 1 - мужской, = 2 - женский, = 3 - средний
690
+ # one_item - именительный падеж единственного числа (= 1)
691
+ # two_items - родительный падеж единственного числа (= 2-4)
692
+ # five_items - родительный падеж множественного числа ( = 5-10)
693
+ #
694
+ # Примерно так:
695
+ # propisju(42, 1, ["сволочь", "сволочи", "сволочей"]) # => "сорок две сволочи"
696
+ def propisju_int(amount, gender = 1, item_forms = [], locale = :ru)
697
+
698
+ locale_root = pick_locale(TRANSLATIONS, locale)
699
+
700
+ # zero!
701
+ if amount.zero?
702
+ return [locale_root['0'], item_forms[-1]].compact.join(' ')
703
+ end
704
+
705
+ fractions = [
706
+ [:trillions, 1_000_000_000_000],
707
+ [:billions, 1_000_000_000],
708
+ [:millions, 1_000_000],
709
+ [:thousands, 1_000],
710
+ ]
711
+
712
+ parts = fractions.map do | name, multiplier |
713
+ [name, fraction = (amount / multiplier) % 1000]
714
+ end
715
+
716
+ # Единицы обрабатываем отдельно
717
+ ones = amount % 1000
718
+
719
+ # Составляем простые тысячные доли
720
+ parts_in_writing = parts.reject do | part |
721
+ part[1].zero?
722
+ end.map do | name, fraction |
723
+ thousandth_gender = (name == :thousands) ? 2 : 1
724
+ compose_ordinal(fraction, thousandth_gender, locale_root[name], locale)
725
+ end
726
+
727
+ # И только единицы обрабатываем с переданными параметрами
728
+ parts_in_writing.push(compose_ordinal(ones, gender, item_forms, locale))
729
+
730
+ parts_in_writing.compact.join(' ')
731
+ end
732
+
733
+ def format_integral(number, options)
734
+ formatted_number = format(options[:integrals_formatter], number)
735
+ delimited_number(formatted_number, options[:integrals_delimiter])
736
+ end
737
+
738
+ def delimited_number(number, delimiter)
739
+ return number.to_s if delimiter == ''
740
+
741
+ number.to_s.gsub!(/(\d)(?=(\d\d\d)+(?!\d))/) do |digit_to_delimit|
742
+ "#{digit_to_delimit}#{delimiter}"
743
+ end || number.to_s
744
+ end
745
+
746
+ def pick_locale(from_hash, locale)
747
+ return from_hash[locale.to_s] if from_hash.has_key?(locale.to_s)
748
+ raise UnknownLocale, "Unknown locale #{locale.inspect}"
749
+ end
750
+
751
+ alias_method :rublja, :rublej
752
+ alias_method :rubl, :rublej
753
+
754
+ alias_method :kopeika, :kopeek
755
+ alias_method :kopeiki, :kopeek
756
+
757
+ alias_method :grivna, :griven
758
+ alias_method :grivny, :griven
759
+
760
+ alias_method :dollar, :dollarov
761
+ alias_method :dollary, :dollarov
762
+
763
+ public_instance_methods(true).map{|m| module_function(m) }
764
+
765
+ module_function :zero, :propisju_int, :propisju_float, :compose_ordinal, :pick_locale, :format_integral, :delimited_number
766
+ end