julik-rutils 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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