rutils 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,332 @@
1
+ module RuTils
2
+
3
+ module GilensonMixin
4
+ # Форматирует строку с помощью Gilensize
5
+ def gilensize(*args)
6
+ RuTils::Gilenson.new(self, *args).to_html
7
+ end
8
+ end
9
+
10
+ # Это - прямой порт Тыпографицы от pixelapes.
11
+ # Настройки можно регулировать через методы, т.е.
12
+ #
13
+ # typ = Typografica.new('Эти "так называемые" великие деятели')
14
+ # typ.html = false => "false"
15
+ # typ.dash = true => "true"
16
+ # typ.to_html => 'Эти «так называемые» великие деятели'
17
+ class Gilenson
18
+ def initialize(text, *args)
19
+ @_text = text
20
+ @skip_tags = true;
21
+ @p_prefix = "<p class=typo>";
22
+ @p_postfix = "</p>";
23
+ @a_soft = true;
24
+ @indent_a = "images/z.gif width=25 height=1 border=0 alt=\'\' align=top />" # <->
25
+ @indent_b = "images/z.gif width=50 height=1 border=0 alt=\'\' align=top />" # <-->
26
+ @fixed_size = 80 # максимальная ширина
27
+ @ignore = /notypo/ # regex, который игнорируется. Этим надо воспользоваться для обработки pre и code
28
+
29
+ @de_nobr = true;
30
+
31
+ @phonemasks = [[ /([0-9]{4})\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/,
32
+ /([0-9]{4})\-([0-9]{2})\-([0-9]{2})/,
33
+ /(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
34
+ /(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
35
+ /(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})/,
36
+ /(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{3})/,
37
+ /([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
38
+ /([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
39
+ /([0-9]{1})\-([0-9]{2})\-([0-9]{2})/,
40
+ /([0-9]{2})\-([0-9]{3})/,
41
+ /([0-9]+)\-([0-9]+)/,
42
+ ],[
43
+ '<nobr>\1&ndash;\2&ndash;\3&nbsp;\4:\5:\6</nobr>',
44
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
45
+ '<nobr>\1&nbsp;\2&ndash;\3&ndash;\4</nobr>',
46
+ '<nobr>\1&nbsp;\2&ndash;\3&ndash;\4</nobr>',
47
+ '<nobr>\1&nbsp;\2&ndash;\3</nobr>',
48
+ '<nobr>\1&nbsp;\2&ndash;\3</nobr>',
49
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
50
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
51
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
52
+ '<nobr>\1&ndash;\2</nobr>',
53
+ '<nobr>\1&ndash;\2</nobr>'
54
+ ]]
55
+
56
+ @glueleft = ['рис.', 'табл.', 'см.', 'им.', 'ул.', 'пер.', 'кв.', 'офис', 'оф.', 'г.']
57
+ @glueright = ['руб.', 'коп.', 'у.е.', 'мин.']
58
+
59
+ @settings = {
60
+ "inches" => true, # преобразовывать дюймы в &quot;
61
+ "laquo" => true, # кавычки-ёлочки
62
+ "farlaquo" => false, # кавычки-ёлочки для фара (знаки "больше-меньше")
63
+ "quotes" => true, # кавычки-английские лапки
64
+ "dash" => true, # короткое тире (150)
65
+ "emdash" => true, # длинное тире двумя минусами (151)
66
+ "(c)" => true,
67
+ "(r)" => true,
68
+ "(tm)" => true,
69
+ "(p)" => true,
70
+ "+-" => true, # спецсимволы, какие - понятно
71
+ "degrees" => true, # знак градуса
72
+ "<-->" => true, # отступы $Indent*
73
+ "dashglue" => true, "wordglue" => true, # приклеивание предлогов и дефисов
74
+ "spacing" => true, # запятые и пробелы, перестановка
75
+ "phones" => true, # обработка телефонов
76
+ "fixed" => false, # подгон под фиксированную ширину
77
+ "html" => false # запрет тагов html
78
+ }
79
+ # irrelevant - indentation with images
80
+ @indent_a = "<!--indent-->"
81
+ @indent_b = "<!--indent-->"
82
+
83
+ @mark_tag = "\xF0\xF0\xF0\xF0" # Подстановочные маркеры тегов
84
+ @mark_ignored = "\201" # Подстановочные маркеры неизменяемых групп
85
+ end
86
+
87
+
88
+ # Proxy unknown method calls as setting switches. Methods with = will set settings, methods without - fetch them
89
+ def method_missing(meth, *args) #:nodoc:
90
+ setting = meth.to_s.gsub(/=$/, '')
91
+ super(meth, *args) unless @settings.has_key?(setting) #this will pop the exception if we have no such setting
92
+
93
+ return @settings[meth.to_s] if setting == meth.to_s
94
+ return (@settings[meth.to_s] = args[0])
95
+ end
96
+
97
+
98
+ def to_html(no_paragraph = false)
99
+
100
+ text = @_text
101
+
102
+ # -2. игнорируем ещё регексп
103
+ ignored = []
104
+
105
+
106
+ text.scan(@ignore) do |result|
107
+ ignored << result
108
+ end
109
+
110
+ text.gsub!(@ignore, @mark_ignored) # маркер игнора
111
+
112
+ # -1. запрет тагов html
113
+ text.gsub!(/&/, '&amp;') if @settings["html"]
114
+
115
+
116
+ # 0. Вырезаем таги
117
+ # проблема на самом деле в том, на что похожи таги.
118
+ # вариант 1, простой (закрывающий таг) </abcz>
119
+ # вариант 2, простой (просто таг) <abcz>
120
+ # вариант 3, посложней <abcz href="abcz">
121
+ # вариант 4, простой (просто таг) <abcz />
122
+ # вариант 5, вакка \xA2\xA2...== нафиг нафиг
123
+ # самый сложный вариант - это когда в параметре тага встречается вдруг символ ">"
124
+ # вот он: <abcz href="abcz>">
125
+ # как работает вырезание? введём спецсимвол. Да, да, спецсимвол.
126
+ # нам он ещё вопьётся =)
127
+ # заменим все таги на спец.символ, запоминая одновременно их в массив.
128
+ # и будем верить, что спец.символы в дикой природе не встречаются.
129
+
130
+ tags = []
131
+ if (@skip_tags)
132
+ # re = /<\/?[a-z0-9]+("+ # имя тага
133
+ # "\s+("+ # повторяющая конструкция: хотя бы один разделитель и тельце
134
+ # "[a-z]+("+ # атрибут из букв, за которым может стоять знак равенства и потом
135
+ # "=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+))"+ #
136
+ # ")?"+
137
+ # ")?"+
138
+ # ")*\/?>|\xA2\xA2[^\n]*?==/i;
139
+
140
+ # re = /<\/?[a-z0-9]+(\s+([a-z]+(=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+)))?)?)*\/?>|\xA2\xA2[^\n]*?==/ui
141
+
142
+ re = /(<\/?[a-z0-9]+(\s+([a-z]+(=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+)))?)?)*\/?>)/ui
143
+
144
+ # по-хорошему атрибуты тоже нужно типографить. Или не нужно? бугага...
145
+
146
+ tags = text.scan(re).map{|tag| tag[0] }
147
+ # match = "&lt;" + match if @settings["html"]
148
+ text.gsub!(re, @mark_tag) #маркер тега, мы используем Invalid UTF-sequence для него
149
+
150
+ # puts "matched #{tags.size} tags"
151
+ end
152
+
153
+ # 1. Запятые и пробелы
154
+ if @settings["spacing"]
155
+ text.gsub!( /(\s*)([,]*)/sui, '\2\1');
156
+ text.gsub!( /(\s*)([\.?!]*)(\s*[ЁА-ЯA-Z])/su, '\2\1\3');
157
+ end
158
+
159
+ # 2. Разбиение на строки длиной не более ХХ символов
160
+ # --- для ваки не портировано ---
161
+ # --- для ваки не портировано ---
162
+
163
+ # 3. Спецсимволы
164
+ # 0. дюймы с цифрами
165
+ text.gsub!(/\s([0-9]{1,2}([\.,][0-9]{1,2})?)\"/ui, ' \1&quot;') if @settings["inches"]
166
+
167
+ # 1. лапки
168
+ if (@settings["quotes"])
169
+ text.gsub!( /\"\"/ui, "&quot;&quot;")
170
+ text.gsub!( /\"\.\"/ui, "&quot;.&quot;")
171
+ _text = '""';
172
+ while _text != text do
173
+ _text = text
174
+ text.gsub!( /(^|\s|\201|\xF0\xF0\xF0\xF0|>)\"([0-9A-Za-z\'\!\s\.\?\,\-\&\;\:\_\xF0\xF0\xF0\xF0\201]+(\"|&#148;))/ui, '\1&#147;\2')
175
+ #this doesnt work in-place. somehow.
176
+ text = text.gsub( /(\&\#147\;([A-Za-z0-9\'\!\s\.\?\,\-\&\;\:\xF0\xF0\xF0\xF0\201\_]*).*[A-Za-z0-9][\xF0\xF0\xF0\xF0\201\?\.\!\,]*)\"/ui, '\1&#148;')
177
+ end
178
+ end
179
+
180
+ # 2. ёлочки
181
+ if @settings["laquo"]
182
+ text.gsub!( /\"\"/ui, "&quot;&quot;");
183
+ text.gsub!( /(^|\s|\201|\xF0\xF0\xF0\xF0|>|\()\"((\201|\xF0\xF0\xF0\xF0)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1&laquo;\\2");
184
+ # nb: wacko only regexp follows:
185
+ text.gsub!( /(^|\s|\201|\xF0\xF0\xF0\xF0|>|\()\"((\201|\xF0\xF0\xF0\xF0|\/&nbsp;|\/|\!)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1&laquo;\\2")
186
+ _text = "\"\"";
187
+ while (_text != text) do
188
+ _text = text;
189
+ text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\201|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1&raquo;")
190
+ # nb: wacko only regexps follows:
191
+ text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\201|\xF0\xF0\xF0\xF0)*\?(\201|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1&raquo;")
192
+ text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\201|\xF0\xF0\xF0\xF0|\/|\!)*)\"/sui, "\\1&raquo;")
193
+ end
194
+ end
195
+
196
+
197
+ # 2b. одновременно ёлочки и лапки
198
+ if (@settings["quotes"] && (@settings["laquo"] or @settings["farlaquo"]))
199
+ text.gsub!(/(\&\#147\;(([A-Za-z0-9'!\.?,\-&;:]|\s|\xF0\xF0\xF0\xF0|\201)*)&laquo;(.*)&raquo;)&raquo;/ui,"\\1&#148;");
200
+ end
201
+
202
+
203
+ # 3. тире
204
+ if (@settings["dash"])
205
+ text.gsub!( /(\s|;)\-(\s)/ui, "\\1&ndash;\\2")
206
+ end
207
+
208
+
209
+ # 3a. тире длинное
210
+ if (@settings["emdash"])
211
+ text.gsub!( /(\s|;)\-\-(\s)/ui, "\\1&mdash;\\2")
212
+ # 4. (с)
213
+ text.gsub!(/\([сСcC]\)((?=\w)|(?=\s[0-9]+))/u, "&copy;") if @settings["(c)"]
214
+ # 4a. (r)
215
+ text.gsub!( /\(r\)/ui, "<sup>&#174;</sup>") if @settings["(r)"]
216
+
217
+ # 4b. (tm)
218
+ text.gsub!( /\(tm\)|\(тм\)/ui, "&#153;") if @settings["(tm)"]
219
+ # 4c. (p)
220
+ text.gsub!( /\(p\)/ui, "&#167;") if @settings["(p)"]
221
+ end
222
+
223
+
224
+ # 5. +/-
225
+ text.gsub!(/[^+]\+\-/ui, "&#177;") if @settings["+-"]
226
+
227
+
228
+ # 5a. 12^C
229
+ if @settings["degrees"]
230
+ text.gsub!( /-([0-9])+\^([FCС])/, "&ndash;\\1&#176\\2")
231
+ text.gsub!( /\+([0-9])+\^([FCС])/, "+\\1&#176\\2")
232
+ text.gsub!( /\^([FCС])/, "&#176\\1")
233
+ end
234
+
235
+
236
+ # 6. телефоны
237
+ if @settings["phones"]
238
+ @phonemasks[0].each_with_index do |v, i|
239
+ text.gsub!(v, @phonemasks[1][i])
240
+ end
241
+ end
242
+
243
+
244
+ # 7. Короткие слова и &nbsp;
245
+ if (@settings["wordglue"])
246
+
247
+ text = " " + text + " ";
248
+ _text = " " + text + " ";
249
+ until _text == text
250
+ _text = text
251
+ text.gsub!( /(\s+)([a-zа-яА-Я]{1,2})(\s+)([^\\s$])/ui, '\1\2&nbsp;\4')
252
+ text.gsub!( /(\s+)([a-zа-яА-Я]{3})(\s+)([^\\s$])/ui, '\1\2&nbsp;\4')
253
+ end
254
+
255
+ for i in @glueleft
256
+ text.gsub!( /(\s)(#{i})(\s+)/sui, '\1\2&nbsp;')
257
+ end
258
+
259
+ for i in @glueright
260
+ text.gsub!( /(\s)(#{i})(\s+)/sui, '&nbsp;\2\3')
261
+ end
262
+ end
263
+
264
+
265
+
266
+ # 8. Склейка ласт. Тьфу! дефисов.
267
+ text.gsub!( /([a-zа-яА-Я0-9]+(\-[a-zа-яА-Я0-9]+)+)/ui, '<nobr>\1</nobr>') if @settings["dashglue"]
268
+
269
+
270
+ # 9. Макросы
271
+
272
+
273
+
274
+ # 10. Переводы строк
275
+ # --- для ваки не портировано ---
276
+ # --- для ваки не портировано ---
277
+
278
+
279
+ # БЕСКОНЕЧНОСТЬ. Вставляем таги обратно.
280
+ # if (@skip_tags)
281
+ # text = text.split("\xF0\xF0\xF0\xF0").join
282
+ #
283
+
284
+ tags.each do |tag|
285
+ text.sub!(@mark_tag, tag)
286
+ end
287
+
288
+ # i = 0
289
+ # text.gsub!(@mark_tag) {
290
+ # i + 1
291
+ # tags[i-1]
292
+ # }
293
+
294
+ # text = text.split("\xF0\xF0\xF0\xF0")
295
+ #puts "reinserted #{i} tags"
296
+ #
297
+ # end
298
+
299
+
300
+ #ext.gsub!("a", '')
301
+ # raise "Text still has tag markers!" if text.include?("a")
302
+
303
+ # БЕСКОНЕЧНОСТЬ-2. вставляем ещё сигнорированный регексп
304
+ #
305
+ # if @ignore
306
+ # ignored.each { | tag | text.sub!(@mark_ignored, tag) }
307
+ # end
308
+
309
+ # raise "Text still has ignored markers!" if text.include?("\201")
310
+
311
+ # БОНУС: прокручивание ссылок через A(...)
312
+ # --- для ваки не портировано ---
313
+ # --- для ваки не портировано ---
314
+
315
+ # фуф, закончили.
316
+ # text.gsub!(/<nobr>/, "<span class=\"nobr\">").gsub(/<\/nobr>/, "</span>") if (@de_nobr)
317
+
318
+ # text.gsub!(/<nobr>/, "<span class=\"nobr\">").gsub(/<\/nobr>/, "</span>") if (@de_nobr)
319
+
320
+ text.gsub(/(\s)+$/, "").gsub(/^(\s)+/, "")
321
+
322
+ end
323
+
324
+ private
325
+
326
+ end
327
+
328
+ end #end RuTils
329
+
330
+ class String
331
+ include RuTils::GilensonMixin
332
+ end
@@ -0,0 +1,8 @@
1
+ if defined?(BlueCloth)
2
+ class BlueCloth < String #:nodoc:
3
+ alias_method :old_to_html, :to_html
4
+ def to_html(*opts)
5
+ RuTils::overrides_enabled? ? RuTils::Gilenson.new(old_to_html(*opts)).to_html : old_to_html(*opts)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ load File.dirname(__FILE__) + '/blue_cloth_override.rb'
2
+ load File.dirname(__FILE__) + '/red_cloth_override.rb'
3
+ load File.dirname(__FILE__) + '/rails_date_helper_override.rb'
4
+
5
+ module RuTils
6
+ @@overrides = true
7
+
8
+ # Метод позволяет проверить, включена ли перегрузка функций других модулей.
9
+ # Попутно он спрашивает модуль Locale (если таковой имеется) является ли русский
10
+ # текущим языком, и если является, включает перегрузку функций имплицитно.
11
+ # Модуль Locale можно скачать и скомпилировать а можно получить как часть Multilingual Rails.
12
+ def self.overrides_enabled?
13
+ if defined?(Locale) and Locale.respond_to?(:current)
14
+ return true if Locale.current.split('_').first == 'ru'
15
+ end
16
+ @@overrides ? true : false
17
+ end
18
+
19
+ # Включает или выключает перегрузки других модулей. Полезно, например, в случае когда нужно рендерить страницу
20
+ # сайта на нескольких языках и нужно отключить русское оформление текста для других языков.
21
+ def self.overrides= (new_override_flag)
22
+ @@overrides = (new_override_flag ? true : false)
23
+ end
24
+ end
@@ -0,0 +1,66 @@
1
+ if defined?(ActionView``)
2
+ module ActionView #:nodoc:
3
+ module Helpers #:nodoc:
4
+ module DateHelper #:nodoc:
5
+
6
+ # Reports the approximate distance in time between two Time objects or integers.
7
+ # For example, if the distance is 47 minutes, it'll return
8
+ # "about 1 hour". See the source for the complete wording list.
9
+ #
10
+ # Integers are interpreted as seconds. So,
11
+ # <tt>distance_of_time_in_words(50)</tt> returns "less than a minute".
12
+ #
13
+ # Set <tt>include_seconds</tt> to true if you want more detailed approximations if distance < 1 minute
14
+
15
+ alias :distance_of_time_in_words :stock_distance_of_time_in_words
16
+ def distance_of_time_in_words(*args)
17
+ RuTils::overrides_enabled? ? RuTils::DateTime::distance_of_time_in_words(*args) : stock_distance_of_time_in_words
18
+ end
19
+
20
+ # Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
21
+ def time_ago_in_words(from_time, include_seconds = false)
22
+ distance_of_time_in_words(from_time, Time.now, include_seconds)
23
+ end
24
+
25
+ # Returns a select tag with options for each of the months January through December with the current month selected.
26
+ # The month names are presented as keys (what's shown to the user) and the month numbers (1-12) are used as values
27
+ # (what's submitted to the server). It's also possible to use month numbers for the presentation instead of names --
28
+ # set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you want both numbers and names,
29
+ # set the <tt>:add_month_numbers</tt> key in +options+ to true. Examples:
30
+ #
31
+ # select_month(Date.today) # Will use keys like "January", "March"
32
+ # select_month(Date.today, :use_month_numbers => true) # Will use keys like "1", "3"
33
+ # select_month(Date.today, :add_month_numbers => true) # Will use keys like "1 - January", "3 - March"
34
+ #
35
+ # Override the field name using the <tt>:field_name</tt> option, 'month' by default.
36
+ #
37
+ # If you would prefer to show month names as abbreviations, set the
38
+ # <tt>:use_short_month</tt> key in +options+ to true.
39
+ def select_month(date, options = {})
40
+ month_options = []
41
+ if RuTils::overrides_enabled?
42
+ month_names = options[:use_short_month] ? RuTils::DateTime::ABBR_MONTHNAMES : RuTils::DateTime::MONTHNAMES
43
+ else
44
+ month_names = options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES
45
+ end
46
+ 1.upto(12) do |month_number|
47
+ month_name = if options[:use_month_numbers]
48
+ month_number
49
+ elsif options[:add_month_numbers]
50
+ month_number.to_s + ' - ' + month_names[month_number]
51
+ else
52
+ month_names[month_number]
53
+ end
54
+
55
+ month_options << ((date && (date.kind_of?(Fixnum) ? date : date.month) == month_number) ?
56
+ %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
57
+ %(<option value="#{month_number}">#{month_name}</option>\n)
58
+ )
59
+ end
60
+
61
+ select_html(options[:field_name] || 'month', month_options, options[:prefix], options[:include_blank], options[:discard_type], options[:disabled])
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end #endif
@@ -0,0 +1,17 @@
1
+ if defined?(RedCloth)
2
+ # RuTils выполняет перегрузку Textile Glyphs в RedCloth, перенося форматирование спецсимволов на Gilenson.
3
+ class RedCloth < String #:nodoc:
4
+ # Этот метод в RedCloth эскейпит слишком много HTML, нам ничего не оставляет :-)
5
+ def htmlesc(text, mode=0) #:nodoc:
6
+ text
7
+ end
8
+
9
+ # А этот метод обрабатывает Textile Glyphs - ту самую типографицу.
10
+ # Вместо того чтобы влезать в таблицы мы просто заменим Textile Glyphs - и все будут рады.
11
+ alias_method :stock_pgl, :pgl
12
+ def pgl(text) #:nodoc:
13
+ # RuTils::overrides_enabled? ? text.replace(RuTils::Gilenson.new(text).to_html) : stock_pgl(text)
14
+ text.replace(RuTils::Gilenson.new(text).to_html)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,208 @@
1
+ module RuTils
2
+ module Pluralization
3
+ # Выбирает нужный падеж существительного в зависимости от числа
4
+ def self.choose_plural(amount, *variants)
5
+ variant = (amount%10==1 && amount%100!=11 ? 1 : amount%10>=2 && amount%10<=4 && (amount%100<10 || amount%100>=20) ? 2 : 3)
6
+ variants[variant-1]
7
+ end
8
+
9
+ # Выполняет преобразование числа из цифрого вида в символьное
10
+ # amount - числительное
11
+ # gender = 1 - мужской, = 2 - женский, = 3 - средний
12
+ # one_item - именительный падеж единственного числа (= 1)
13
+ # two_items - родительный падеж единственного числа (= 2-4)
14
+ # five_items - родительный падеж множественного числа ( = 5-10)
15
+ def self.sum_string(amount, gender, one_item='', two_items='', five_items='')
16
+ into = ''
17
+ tmp_val ||= 0
18
+
19
+ return "ноль " + five_items if amount == 0
20
+
21
+ tmp_val = amount
22
+
23
+ # единицы
24
+ into, tmp_val = sum_string_fn(into, tmp_val, gender, one_item, two_items, five_items)
25
+
26
+ return into if tmp_val == 0
27
+
28
+ # тысячи
29
+ into, tmp_val = sum_string_fn(into, tmp_val, 2, "тысяча", "тысячи", "тысяч")
30
+
31
+ return into if tmp_val == 0
32
+
33
+ # миллионы
34
+ into, tmp_val = sum_string_fn(into, tmp_val, 1, "миллион", "миллиона", "миллионов")
35
+
36
+ return into if tmp_val == 0
37
+
38
+ # миллиардов
39
+ into, tmp_val = sum_string_fn(into, tmp_val, 1, "миллиард", "миллиарда", "миллиардов")
40
+ return into
41
+ end
42
+
43
+ private
44
+ def self.sum_string_fn(into, tmp_val, gender, one_item='', two_items='', five_items='')
45
+ rest, rest1, end_word, ones, tens, hundreds = [nil]*6
46
+ #
47
+ rest = tmp_val % 1000
48
+ tmp_val = tmp_val / 1000
49
+ if rest == 0
50
+ # последние три знака нулевые
51
+ into = five_items + " " if into == ""
52
+ return [into, tmp_val]
53
+ end
54
+ #
55
+ # начинаем подсчет с Rest
56
+ end_word = five_items
57
+ # сотни
58
+ case rest / 100
59
+ when 0 then hundreds = ""
60
+ when 1 then hundreds = "сто "
61
+ when 2 then hundreds = "двести "
62
+ when 3 then hundreds = "триста "
63
+ when 4 then hundreds = "четыреста "
64
+ when 5 then hundreds = "пятьсот "
65
+ when 6 then hundreds = "шестьсот "
66
+ when 7 then hundreds = "семьсот "
67
+ when 8 then hundreds = "восемьсот "
68
+ when 9 then hundreds = "девятьсот "
69
+ end
70
+
71
+ # десятки
72
+ rest = rest % 100
73
+ rest1 = rest / 10
74
+ ones = ""
75
+ case rest1
76
+ when 0 then tens = ""
77
+ when 1 # особый случай
78
+ case rest
79
+ when 10 then tens = "десять "
80
+ when 11 then tens = "одиннадцать "
81
+ when 12 then tens = "двенадцать "
82
+ when 13 then tens = "тринадцать "
83
+ when 14 then tens = "четырнадцать "
84
+ when 15 then tens = "пятнадцать "
85
+ when 16 then tens = "шестнадцать "
86
+ when 17 then tens = "семнадцать "
87
+ when 18 then tens = "восемнадцать "
88
+ when 19 then tens = "девятнадцать "
89
+ end
90
+ when 2: tens = "двадцать "
91
+ when 3: tens = "тридцать "
92
+ when 4: tens = "сорок "
93
+ when 5: tens = "пятьдесят "
94
+ when 6: tens = "шестьдесят "
95
+ when 7: tens = "семьдесят "
96
+ when 8: tens = "восемьдесят "
97
+ when 9: tens = "девяносто "
98
+ end
99
+ #
100
+ if rest1 < 1 or rest1 > 1 # единицы
101
+ case rest % 10
102
+ when 1
103
+ case gender
104
+ when 1
105
+ ones = "один "
106
+ when 2
107
+ ones = "одна "
108
+ when 3
109
+ ones = "одно "
110
+ end
111
+ end_word = one_item
112
+ when 2
113
+ if gender == 2
114
+ ones = "две "
115
+ else
116
+ ones = "два "
117
+ end
118
+ end_word = two_items
119
+ when 3
120
+ ones = "три " if end_word = two_items
121
+ when 4
122
+ ones = "четыре " if end_word = two_items
123
+ when 5
124
+ ones = "пять "
125
+ when 6
126
+ ones = "шесть "
127
+ when 7
128
+ ones = "семь "
129
+ when 8
130
+ ones = "восемь "
131
+ when 9
132
+ ones = "девять "
133
+ end
134
+ end
135
+
136
+ # сборка строки
137
+ return [(hundreds + tens + ones + end_word + " " + into).strip, tmp_val]
138
+ end
139
+
140
+ # Реализует вывод прописью любого объекта, реализующего Float
141
+ module FloatFormatting
142
+
143
+ # Выдает сумму прописью с учетом дробной доли. Дробная доля округляется до миллионной, или (если
144
+ # дробная доля оканчивается на нули) до ближайшей доли ( 500 тысячных округляется до 5 десятых).
145
+ # Дополнительный аргумент - род существительного (1 - мужской, 2- женский, 3-средний)
146
+ def propisju(gender = 2)
147
+ raise "NaN propisju eto ne propis!" if self.nan?
148
+
149
+ st = RuTils::Pluralization::sum_string(self.to_i, gender, "целая", "целых", "целых")
150
+ it = []
151
+
152
+ rmdr = self.to_s.match(/\.(\d+)/)[1]
153
+
154
+ signs = rmdr.to_s.size- 1
155
+
156
+ it << ["десятая", "десятых"]
157
+ it << ["сотая", "сотых"]
158
+ it << ["тысячная", "тысячных"]
159
+ it << ["десятитысячная", "десятитысячных"]
160
+ it << ["стотысячная", "стотысячных"]
161
+ it << ["миллионная", "милллионных"]
162
+ # it << ["десятимиллионная", "десятимилллионных", "десятимиллионных"]
163
+ # it << ["стомиллионная", "стомилллионных", "стомиллионных"]
164
+ # it << ["миллиардная", "миллиардных", "миллиардных"]
165
+ # it << ["десятимиллиардная", "десятимиллиардных", "десятимиллиардных"]
166
+ # it << ["стомиллиардная", "стомиллиардных", "стомиллиардных"]
167
+ # it << ["триллионная", "триллионных", "триллионных"]
168
+
169
+ while it[signs].nil?
170
+ rmdr = (rmdr/10).round
171
+ signs = rmdr.to_s.size- 1
172
+ end
173
+
174
+ suf1, suf2, suf3 = it[signs][0], it[signs][1], it[signs][2]
175
+ st + " " + RuTils::Pluralization::sum_string(rmdr.to_i, 2, suf1, suf2, suf2)
176
+ end
177
+ end
178
+
179
+ # Реализует вывод прописью любого объекта, реализующего Numeric
180
+ module NumericFormatting
181
+ # Выбирает корректный вариант числительного в зависимости от рода и числа и оформляет сумму прописью
182
+ # 234.propisju => "двести сорок три"
183
+ # 221.propisju(2) => "двести двадцать одна"
184
+ def propisju(gender = 1)
185
+ RuTils::Pluralization::sum_string(self, gender, "")
186
+ end
187
+
188
+ def propisju_items(gender=1, *forms)
189
+ RuTils::Pluralization::sum_string(self, gender, "") + " " + RuTils::Pluralization::choose_plural(self, *forms)
190
+ end
191
+
192
+ # Выбирает корректный вариант числительного в зависимости от рода и числа. Например:
193
+ # * 4.items("колесо", "колеса", "колес") => "колеса"
194
+ def items(one_item, two_items, five_items)
195
+ RuTils::Pluralization::choose_plural(self, one_item, two_items, five_items)
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ class Numeric
202
+ include RuTils::Pluralization::NumericFormatting
203
+ end
204
+
205
+
206
+ class Float
207
+ include RuTils::Pluralization::FloatFormatting
208
+ end
data/lib/rutils.rb ADDED
@@ -0,0 +1,14 @@
1
+ $KCODE = 'u'
2
+ require 'jcode'
3
+
4
+ # Главный контейнер модуля
5
+ module RuTils
6
+ VERSION = '0.0.3'
7
+ end
8
+
9
+ require File.dirname(__FILE__) + '/pluralizer/pluralizer'
10
+ require File.dirname(__FILE__) + '/gilenson/gilenson_port' #Предельно идентичный порт Тыпографицы
11
+ #require File.dirname(__FILE__) + '/gilenson/gilenson' #Гиленсон, рефакторенный нами - todo
12
+ require File.dirname(__FILE__) + '/datetime/datetime' # Дата и время без локалей
13
+ require File.dirname(__FILE__) + '/transliteration/transliteration' # Транслит
14
+ require File.dirname(__FILE__) + '/integration/integration' # Интеграция с rails, textile и тд