julik-rutils 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. data/History.txt +162 -0
  2. data/Manifest.txt +42 -0
  3. data/README.txt +234 -0
  4. data/Rakefile.rb +41 -0
  5. data/TODO.txt +6 -0
  6. data/WHAT_HAS_CHANGED.txt +44 -0
  7. data/bin/gilensize +22 -0
  8. data/bin/rutilize +38 -0
  9. data/init.rb +27 -0
  10. data/lib/countries/countries.rb +1773 -0
  11. data/lib/datetime/datetime.rb +83 -0
  12. data/lib/gilenson/bluecloth_extra.rb +7 -0
  13. data/lib/gilenson/gilenson.rb +665 -0
  14. data/lib/gilenson/helper.rb +34 -0
  15. data/lib/gilenson/maruku_extra.rb +19 -0
  16. data/lib/gilenson/rdiscount_extra.rb +7 -0
  17. data/lib/gilenson/redcloth_extra.rb +42 -0
  18. data/lib/integration/integration.rb +1 -0
  19. data/lib/integration/rails_date_helper_override.rb +127 -0
  20. data/lib/integration/rails_pre_filter.rb +4 -0
  21. data/lib/pluralizer/pluralizer.rb +261 -0
  22. data/lib/rutils.rb +54 -0
  23. data/lib/transliteration/bidi.rb +21 -0
  24. data/lib/transliteration/simple.rb +75 -0
  25. data/lib/transliteration/transliteration.rb +53 -0
  26. data/lib/version.rb +5 -0
  27. data/test/extras/integration_bluecloth.rb +13 -0
  28. data/test/extras/integration_maruku.rb +15 -0
  29. data/test/extras/integration_rails_filter.rb +29 -0
  30. data/test/extras/integration_rails_gilenson_helpers.rb +80 -0
  31. data/test/extras/integration_rails_helpers.rb +85 -0
  32. data/test/extras/integration_rdiscount.rb +15 -0
  33. data/test/extras/integration_redcloth3.rb +18 -0
  34. data/test/extras/integration_redcloth4.rb +19 -0
  35. data/test/run_tests.rb +4 -0
  36. data/test/test_datetime.rb +145 -0
  37. data/test/test_gilenson.rb +396 -0
  38. data/test/test_integration.rb +22 -0
  39. data/test/test_integration_flag.rb +18 -0
  40. data/test/test_pluralize.rb +84 -0
  41. data/test/test_rutils_base.rb +11 -0
  42. data/test/test_transliteration.rb +53 -0
  43. metadata +121 -0
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Включается на правах хелпера в Rails-приложение
3
+ module RuTils::Gilenson::Helper
4
+
5
+ # Возвращает текст обработанный Гиленсоном
6
+ def gilensize(text, options = {})
7
+ return "" if text.blank?
8
+ f = RuTils::Gilenson::Formatter.new
9
+ f.configure!(options)
10
+ f.process(text)
11
+ end
12
+
13
+ # Возвращает текст обработанный Текстилем и Гиленсоном
14
+ # <i>Метод доступен только при включенном RedCloth</i>
15
+ def textilize(text)
16
+ return "" if text.blank?
17
+ if RuTils.overrides_enabled?
18
+ RuTils::Gilenson::RedClothExtra.new(text, [ :hard_breaks ]).to_html
19
+ else
20
+ super(text)
21
+ end
22
+ end
23
+
24
+ # Возвращает текст с кодом Markdown превращенным в HTML, попутно обработанный Гиленсоном
25
+ # <i>Метод доступен только при наличии BlueCloth</i>.
26
+ def markdown(text)
27
+ return "" if text.blank?
28
+ if RuTils.overrides_enabled?
29
+ RuTils::Gilenson::BlueClothExtra.new(text).to_html
30
+ else
31
+ super(text)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Maruku с поддержкой Gilenson
3
+ class RuTils::Gilenson::MarukuExtra < Maruku
4
+ def to_html(*anything)
5
+ suspended = super
6
+
7
+ # Return quotes to original state
8
+ [187, 171, 8220, 8221].map do |e|
9
+ suspended.gsub! /&\##{e};/, '"'
10
+ end
11
+
12
+ # Return spaces to original state
13
+ [160].map do |e|
14
+ suspended.gsub! /&\##{e};/, ' '
15
+ end
16
+
17
+ suspended.gilensize
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # RDiscount с поддержкой Gilenson
3
+ class RuTils::Gilenson::RDiscountExtra < RDiscount
4
+ def to_html(*opts)
5
+ RuTils::Gilenson::Formatter.new(super(*opts)).to_html
6
+ end
7
+ end
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+ if RedCloth.class == Module
3
+ # RedCloth 4 - частичная поддержка
4
+ class RuTils::Gilenson::RedClothExtra < RedCloth::TextileDoc
5
+ def to_html(*anything)
6
+ suspended = super(*anything)
7
+
8
+ # Return quotes to original state
9
+ [187, 171, 8220, 8221].map do |e|
10
+ suspended.gsub! /&\##{e};/, '"'
11
+ end
12
+
13
+ # Return spaces to original state
14
+ [160].map do |e|
15
+ suspended.gsub! /&\##{e};/, ' '
16
+ end
17
+
18
+ suspended.gilensize
19
+ end
20
+ end
21
+ else
22
+ # RedCloth 3 - RuTils выполняет перегрузку Textile Glyphs в RedCloth, перенося форматирование спецсимволов на Gilenson.
23
+ # Применять как стандартный RedCloth
24
+ # RuTils::Gilenson::RedClothExtra.new(some_text).to_html
25
+ class RuTils::Gilenson::RedClothExtra < RedCloth
26
+ # Этот метод в RedCloth при наличии Гиленсона становится заглушкой
27
+ def htmlesc(text, mode=0)
28
+ text
29
+ end
30
+
31
+ # А этот метод обрабатывает Textile Glyphs - ту самую типографицу.
32
+ # Вместо того чтобы влезать в чужие таблицы мы просто заменим Textile Glyphs на Gilenson - и все будут рады.
33
+ def pgl(text) #:nodoc:
34
+ # Подвешиваем пробелы в начале и в конце каждого блока. Тряпка требует чтобы эти пробелы приехали
35
+ # назад нетронутыми.
36
+ spaces = Array.new(2,'')
37
+ text.gsub!(/\A([\s]+)/) { spaces[0] = $1; '' }
38
+ text.gsub!(/(\s+)\Z/) { spaces[1] = $1; '' }
39
+ text.replace(spaces[0].to_s + RuTils::Gilenson::Formatter.new(text).to_html + spaces[1].to_s)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/rails_date_helper_override' if defined?(ActionView)
@@ -0,0 +1,127 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Object::ActionView::Helpers::DateHelper
3
+ # Несколько хаков для корректной работы модуля с Rails 1.2--2.0 одновременно с Rails 2.1 и выше.
4
+
5
+ # Хелперы DateHelper принимают параметр <tt>html_options</tt> (идет последним) начиная с Rails 2.1.
6
+ # Нужно понять, имеем ли мы дело с Rails 2.1+, для этого проверяем наличие классметода helper_modules у
7
+ # ActionView::Base, который появился как раз в версии 2.1.
8
+ DATE_HELPERS_RECEIVE_HTML_OPTIONS = ActionView::Base.respond_to?(:helper_modules) #:nodoc:
9
+
10
+ # В Rails Edge (2.1+) определяется <tt>Time.current</tt> для работы с временными зонами.
11
+ unless Time.respond_to? :current
12
+ class << ::Time # :nodoc:
13
+ def current; now; end
14
+ end
15
+ end
16
+
17
+ # В Rails Edge (2.1+) определяется <tt>Date.current</tt> для работы с временными зонами.
18
+ unless Date.respond_to? :current
19
+ class << ::Date # :nodoc:
20
+ def current; now; end
21
+ end
22
+ end
23
+
24
+ # Заменяет <tt>ActionView::Helpers::DateHelper::distance_of_time_in_words</tt> на русское сообщение.
25
+ #
26
+ # Целые числа интерпретируются как секунды.
27
+ # <tt>distance_of_time_in_words(50)</tt> возвращает "меньше минуты".
28
+ alias :stock_distance_of_time_in_words :distance_of_time_in_words
29
+ def distance_of_time_in_words(*args)
30
+ RuTils::overrides_enabled? ? RuTils::DateTime::distance_of_time_in_words(*args) : stock_distance_of_time_in_words
31
+ end
32
+
33
+ # Заменяет ActionView::Helpers::DateHelper::select_month меню выбора русских месяцев.
34
+ #
35
+ # select_month(Date.today) # Использует ключи "Январь", "Март"
36
+ # select_month(Date.today, :use_month_numbers => true) # Использует ключи "1", "3"
37
+ # select_month(Date.today, :add_month_numbers => true) # Использует ключи "1 - Январь", "3 - Март"
38
+ def select_month(date, options = {}, html_options = {})
39
+ locale = options[:locale] unless RuTils::overrides_enabled?
40
+
41
+ val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
42
+ if options[:use_hidden]
43
+ if self.class.private_instance_methods.include? "_date_hidden_html"
44
+ _date_hidden_html(options[:field_name] || 'month', val, options)
45
+ else
46
+ hidden_html(options[:field_name] || 'month', val, options)
47
+ end
48
+ else
49
+ month_options = []
50
+ if RuTils::overrides_enabled?
51
+ month_names = case true
52
+ when options[:use_short_month]
53
+ Date::RU_ABBR_MONTHNAMES
54
+ # использование в контексте date_select с днями требует родительный падеж
55
+ when options[:order] && options[:order].include?(:day)
56
+ Date::RU_INFLECTED_MONTHNAMES
57
+ else
58
+ Date::RU_MONTHNAMES
59
+ end
60
+ else
61
+ if defined? I18n
62
+ month_names = options[:use_month_names] || begin
63
+ key = options[:use_short_month] ? :'date.abbr_month_names' : :'date.month_names'
64
+ I18n.translate key, :locale => locale
65
+ end
66
+ else
67
+ month_names = options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES
68
+ end
69
+ end
70
+ month_names.unshift(nil) if month_names.size < 13
71
+
72
+ 1.upto(12) do |month_number|
73
+ month_name = if options[:use_month_numbers]
74
+ month_number
75
+ elsif options[:add_month_numbers]
76
+ month_number.to_s + ' - ' + month_names[month_number]
77
+ else
78
+ month_names[month_number]
79
+ end
80
+
81
+ month_options << ((val == month_number) ?
82
+ content_tag(:option, month_name, :value => month_number, :selected => "selected") :
83
+ content_tag(:option, month_name, :value => month_number)
84
+ )
85
+ month_options << "\n"
86
+ end
87
+
88
+ if DATE_HELPERS_RECEIVE_HTML_OPTIONS
89
+ if self.class.private_instance_methods.include? "_date_select_html"
90
+ _date_select_html(options[:field_name] || 'month', month_options.join, options, html_options)
91
+ else
92
+ select_html(options[:field_name] || 'month', month_options.join, options, html_options)
93
+ end
94
+ else
95
+ select_html(options[:field_name] || 'month', month_options.join, options)
96
+ end
97
+ end
98
+ end
99
+
100
+ alias :stock_select_date :select_date
101
+ # Заменяет ActionView::Helpers::DateHelper::select_date меню выбора русской даты.
102
+ def select_date(date = Date.current, options = {}, html_options = {})
103
+ options[:order] ||= [:day, :month, :year]
104
+ if DATE_HELPERS_RECEIVE_HTML_OPTIONS
105
+ stock_select_date(date, options, html_options)
106
+ else
107
+ stock_select_date(date, options)
108
+ end
109
+ end
110
+ end
111
+
112
+ module Object::ActionView::Helpers
113
+ if defined?(InstanceTag) && InstanceTag.private_method_defined?(:date_or_time_select)
114
+ class InstanceTag #:nodoc:
115
+ private
116
+ alias :stock_date_or_time_select :date_or_time_select
117
+ def date_or_time_select(options, html_options = {})
118
+ options[:order] ||= [:day, :month, :year]
119
+ if DATE_HELPERS_RECEIVE_HTML_OPTIONS
120
+ stock_date_or_time_select(options, html_options)
121
+ else
122
+ stock_date_or_time_select(options)
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
2
+ class ActionController::Base
3
+ before_filter { RuTils::overrides = true }
4
+ end
@@ -0,0 +1,261 @@
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