rotuka-rutils 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,321 @@
1
+ module RuTils
2
+ module Gilenson
3
+ end
4
+ end
5
+
6
+ # Это - прямой порт Тыпографицы от pixelapes.
7
+ # Настройки можно регулировать через методы, т.е.
8
+ #
9
+ # typ = RuTils::Gilenson::Obsolete.new('Эти "так называемые" великие деятели')
10
+ # typ.html = false => "false"
11
+ # typ.dash = true => "true"
12
+ # typ.to_html => 'Эти «так называемые» великие деятели'
13
+ # Ни обновляться ни поддерживаться этот модуль более не будет.
14
+ class RuTils::Gilenson::Obsolete
15
+ def initialize(text, *args)
16
+ @_text = text
17
+ @skip_tags = true;
18
+ @p_prefix = "<p class=typo>";
19
+ @p_postfix = "</p>";
20
+ @a_soft = true;
21
+ @indent_a = "images/z.gif width=25 height=1 border=0 alt=\'\' align=top />" # <->
22
+ @indent_b = "images/z.gif width=50 height=1 border=0 alt=\'\' align=top />" # <-->
23
+ @fixed_size = 80 # максимальная ширина
24
+ @ignore = /notypo/ # regex, который игнорируется. Этим надо воспользоваться для обработки pre и code
25
+
26
+ @de_nobr = true;
27
+
28
+ @phonemasks = [[ /([0-9]{4})\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/,
29
+ /([0-9]{4})\-([0-9]{2})\-([0-9]{2})/,
30
+ /(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
31
+ /(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
32
+ /(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})/,
33
+ /(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{3})/,
34
+ /([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
35
+ /([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
36
+ /([0-9]{1})\-([0-9]{2})\-([0-9]{2})/,
37
+ /([0-9]{2})\-([0-9]{3})/,
38
+ /([0-9]+)\-([0-9]+)/,
39
+ ],[
40
+ '<nobr>\1&ndash;\2&ndash;\3&nbsp;\4:\5:\6</nobr>',
41
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
42
+ '<nobr>\1&nbsp;\2&ndash;\3&ndash;\4</nobr>',
43
+ '<nobr>\1&nbsp;\2&ndash;\3&ndash;\4</nobr>',
44
+ '<nobr>\1&nbsp;\2&ndash;\3</nobr>',
45
+ '<nobr>\1&nbsp;\2&ndash;\3</nobr>',
46
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
47
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
48
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
49
+ '<nobr>\1&ndash;\2</nobr>',
50
+ '<nobr>\1&ndash;\2</nobr>'
51
+ ]]
52
+
53
+ @glueleft = ['рис.', 'табл.', 'см.', 'им.', 'ул.', 'пер.', 'кв.', 'офис', 'оф.', 'г.']
54
+ @glueright = ['руб.', 'коп.', 'у.е.', 'мин.']
55
+
56
+ @settings = {
57
+ "inches" => true, # преобразовывать дюймы в &quot;
58
+ "laquo" => true, # кавычки-ёлочки
59
+ "farlaquo" => false, # кавычки-ёлочки для фара (знаки "больше-меньше")
60
+ "quotes" => true, # кавычки-английские лапки
61
+ "dash" => true, # короткое тире (150)
62
+ "emdash" => true, # длинное тире двумя минусами (151)
63
+ "(c)" => true,
64
+ "(r)" => true,
65
+ "(tm)" => true,
66
+ "(p)" => true,
67
+ "+-" => true, # спецсимволы, какие - понятно
68
+ "degrees" => true, # знак градуса
69
+ "<-->" => true, # отступы $Indent*
70
+ "dashglue" => true, "wordglue" => true, # приклеивание предлогов и дефисов
71
+ "spacing" => true, # запятые и пробелы, перестановка
72
+ "phones" => true, # обработка телефонов
73
+ "fixed" => false, # подгон под фиксированную ширину
74
+ "html" => false # запрет тагов html
75
+ }
76
+ # irrelevant - indentation with images
77
+ @indent_a = "<!--indent-->"
78
+ @indent_b = "<!--indent-->"
79
+
80
+ @mark_tag = "\xF0\xF0\xF0\xF0" # Подстановочные маркеры тегов
81
+ @mark_ignored = "\201" # Подстановочные маркеры неизменяемых групп
82
+ end
83
+
84
+
85
+ # Proxy unknown method calls as setting switches. Methods with = will set settings, methods without - fetch them
86
+ def method_missing(meth, *args) #:nodoc:
87
+ setting = meth.to_s.gsub(/=$/, '')
88
+ super(meth, *args) unless @settings.has_key?(setting) #this will pop the exception if we have no such setting
89
+
90
+ return @settings[meth.to_s] if setting == meth.to_s
91
+ return (@settings[meth.to_s] = args[0])
92
+ end
93
+
94
+
95
+ def to_html(no_paragraph = false)
96
+
97
+ text = @_text
98
+
99
+ # -2. игнорируем ещё регексп
100
+ ignored = []
101
+
102
+
103
+ text.scan(@ignore) do |result|
104
+ ignored << result
105
+ end
106
+
107
+ text.gsub!(@ignore, @mark_ignored) # маркер игнора
108
+
109
+ # -1. запрет тагов html
110
+ text.gsub!(/&/, '&amp;') if @settings["html"]
111
+
112
+
113
+ # 0. Вырезаем таги
114
+ # проблема на самом деле в том, на что похожи таги.
115
+ # вариант 1, простой (закрывающий таг) </abcz>
116
+ # вариант 2, простой (просто таг) <abcz>
117
+ # вариант 3, посложней <abcz href="abcz">
118
+ # вариант 4, простой (просто таг) <abcz />
119
+ # вариант 5, вакка \xA2\xA2...== нафиг нафиг
120
+ # самый сложный вариант - это когда в параметре тага встречается вдруг символ ">"
121
+ # вот он: <abcz href="abcz>">
122
+ # как работает вырезание? введём спецсимвол. Да, да, спецсимвол.
123
+ # нам он ещё вопьётся =)
124
+ # заменим все таги на спец.символ, запоминая одновременно их в массив.
125
+ # и будем верить, что спец.символы в дикой природе не встречаются.
126
+
127
+ tags = []
128
+ if (@skip_tags)
129
+ # re = /<\/?[a-z0-9]+("+ # имя тага
130
+ # "\s+("+ # повторяющая конструкция: хотя бы один разделитель и тельце
131
+ # "[a-z]+("+ # атрибут из букв, за которым может стоять знак равенства и потом
132
+ # "=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+))"+ #
133
+ # ")?"+
134
+ # ")?"+
135
+ # ")*\/?>|\xA2\xA2[^\n]*?==/i;
136
+
137
+ # re = /<\/?[a-z0-9]+(\s+([a-z]+(=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+)))?)?)*\/?>|\xA2\xA2[^\n]*?==/ui
138
+
139
+ re = /(<\/?[a-z0-9]+(\s+([a-z]+(=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+)))?)?)*\/?>)/ui
140
+
141
+ # по-хорошему атрибуты тоже нужно типографить. Или не нужно? бугага...
142
+
143
+ tags = text.scan(re).map{|tag| tag[0] }
144
+ # match = "&lt;" + match if @settings["html"]
145
+ text.gsub!(re, @mark_tag) #маркер тега, мы используем Invalid UTF-sequence для него
146
+
147
+ # puts "matched #{tags.size} tags"
148
+ end
149
+
150
+ # 1. Запятые и пробелы
151
+ if @settings["spacing"]
152
+ text.gsub!( /(\s*)([,]*)/sui, '\2\1');
153
+ text.gsub!( /(\s*)([\.?!]*)(\s*[ЁА-ЯA-Z])/su, '\2\1\3');
154
+ end
155
+
156
+ # 2. Разбиение на строки длиной не более ХХ символов
157
+ # --- для ваки не портировано ---
158
+ # --- для ваки не портировано ---
159
+
160
+ # 3. Спецсимволы
161
+ # 0. дюймы с цифрами
162
+ text.gsub!(/\s([0-9]{1,2}([\.,][0-9]{1,2})?)\"/ui, ' \1&quot;') if @settings["inches"]
163
+
164
+ # 1. лапки
165
+ if (@settings["quotes"])
166
+ text.gsub!( /\"\"/ui, "&quot;&quot;")
167
+ text.gsub!( /\"\.\"/ui, "&quot;.&quot;")
168
+ _text = '""';
169
+ while _text != text do
170
+ _text = text
171
+ text.gsub!( /(^|\s|\201|\xF0\xF0\xF0\xF0|>)\"([0-9A-Za-z\'\!\s\.\?\,\-\&\;\:\_\xF0\xF0\xF0\xF0\201]+(\"|&#148;))/ui, '\1&#147;\2')
172
+ #this doesnt work in-place. somehow.
173
+ 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;')
174
+ end
175
+ end
176
+
177
+ # 2. ёлочки
178
+ if @settings["laquo"]
179
+ text.gsub!( /\"\"/ui, "&quot;&quot;");
180
+ text.gsub!( /(^|\s|\201|\xF0\xF0\xF0\xF0|>|\()\"((\201|\xF0\xF0\xF0\xF0)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1&laquo;\\2");
181
+ # nb: wacko only regexp follows:
182
+ text.gsub!( /(^|\s|\201|\xF0\xF0\xF0\xF0|>|\()\"((\201|\xF0\xF0\xF0\xF0|\/&nbsp;|\/|\!)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1&laquo;\\2")
183
+ _text = "\"\"";
184
+ while (_text != text) do
185
+ _text = text;
186
+ text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\201|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1&raquo;")
187
+ # nb: wacko only regexps follows:
188
+ text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\201|\xF0\xF0\xF0\xF0)*\?(\201|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1&raquo;")
189
+ text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\201|\xF0\xF0\xF0\xF0|\/|\!)*)\"/sui, "\\1&raquo;")
190
+ end
191
+ end
192
+
193
+
194
+ # 2b. одновременно ёлочки и лапки
195
+ if (@settings["quotes"] && (@settings["laquo"] or @settings["farlaquo"]))
196
+ text.gsub!(/(\&\#147;\;(([A-Za-z0-9'!\.?,\-&;:]|\s|\xF0\xF0\xF0\xF0|\201)*)&laquo;(.*)&raquo;)&raquo;/ui,"\\1&#148;");
197
+ end
198
+
199
+
200
+ # 3. тире
201
+ if (@settings["dash"])
202
+ text.gsub!( /(\s|;)\-(\s)/ui, "\\1&ndash;\\2")
203
+ end
204
+
205
+
206
+ # 3a. тире длинное
207
+ if (@settings["emdash"])
208
+ text.gsub!( /(\s|;)\-\-(\s)/ui, "\\1&mdash;\\2")
209
+ # 4. (с)
210
+ text.gsub!(/\([сСcC]\)((?=\w)|(?=\s[0-9]+))/u, "&copy;") if @settings["(c)"]
211
+ # 4a. (r)
212
+ text.gsub!( /\(r\)/ui, "<sup>&#174;</sup>") if @settings["(r)"]
213
+
214
+ # 4b. (tm)
215
+ text.gsub!( /\(tm\)|\(тм\)/ui, "&#153;") if @settings["(tm)"]
216
+ # 4c. (p)
217
+ text.gsub!( /\(p\)/ui, "&#167;") if @settings["(p)"]
218
+ end
219
+
220
+
221
+ # 5. +/-
222
+ text.gsub!(/[^+]\+\-/ui, "&#177;") if @settings["+-"]
223
+
224
+
225
+ # 5a. 12^C
226
+ if @settings["degrees"]
227
+ text.gsub!( /-([0-9])+\^([FCС])/, "&ndash;\\1&#176;\\2")
228
+ text.gsub!( /\+([0-9])+\^([FCС])/, "+\\1&#176;\\2")
229
+ text.gsub!( /\^([FCС])/, "&#176;\\1")
230
+ end
231
+
232
+
233
+ # 6. телефоны
234
+ if @settings["phones"]
235
+ @phonemasks[0].each_with_index do |v, i|
236
+ text.gsub!(v, @phonemasks[1][i])
237
+ end
238
+ end
239
+
240
+
241
+ # 7. Короткие слова и &nbsp;
242
+ if (@settings["wordglue"])
243
+
244
+ text = " " + text + " ";
245
+ _text = " " + text + " ";
246
+ until _text == text
247
+ _text = text
248
+ text.gsub!( /(\s+)([a-zа-яА-Я]{1,2})(\s+)([^\\s$])/ui, '\1\2&nbsp;\4')
249
+ text.gsub!( /(\s+)([a-zа-яА-Я]{3})(\s+)([^\\s$])/ui, '\1\2&nbsp;\4')
250
+ end
251
+
252
+ for i in @glueleft
253
+ text.gsub!( /(\s)(#{i})(\s+)/sui, '\1\2&nbsp;')
254
+ end
255
+
256
+ for i in @glueright
257
+ text.gsub!( /(\s)(#{i})(\s+)/sui, '&nbsp;\2\3')
258
+ end
259
+ end
260
+
261
+
262
+
263
+ # 8. Склейка ласт. Тьфу! дефисов.
264
+ text.gsub!( /([a-zа-яА-Я0-9]+(\-[a-zа-яА-Я0-9]+)+)/ui, '<nobr>\1</nobr>') if @settings["dashglue"]
265
+
266
+
267
+ # 9. Макросы
268
+
269
+
270
+
271
+ # 10. Переводы строк
272
+ # --- для ваки не портировано ---
273
+ # --- для ваки не портировано ---
274
+
275
+
276
+ # БЕСКОНЕЧНОСТЬ. Вставляем таги обратно.
277
+ # if (@skip_tags)
278
+ # text = text.split("\xF0\xF0\xF0\xF0").join
279
+ #
280
+
281
+ tags.each do |tag|
282
+ text.sub!(@mark_tag, tag)
283
+ end
284
+
285
+ # i = 0
286
+ # text.gsub!(@mark_tag) {
287
+ # i + 1
288
+ # tags[i-1]
289
+ # }
290
+
291
+ # text = text.split("\xF0\xF0\xF0\xF0")
292
+ #puts "reinserted #{i} tags"
293
+ #
294
+ # end
295
+
296
+
297
+ #ext.gsub!("a", '')
298
+ # raise "Text still has tag markers!" if text.include?("a")
299
+
300
+ # БЕСКОНЕЧНОСТЬ-2. вставляем ещё сигнорированный регексп
301
+ #
302
+ # if @ignore
303
+ # ignored.each { | tag | text.sub!(@mark_ignored, tag) }
304
+ # end
305
+
306
+ # raise "Text still has ignored markers!" if text.include?("\201")
307
+
308
+ # БОНУС: прокручивание ссылок через A(...)
309
+ # --- для ваки не портировано ---
310
+ # --- для ваки не портировано ---
311
+
312
+ # фуф, закончили.
313
+ # text.gsub!(/<nobr>/, "<span class=\"nobr\">").gsub(/<\/nobr>/, "</span>") if (@de_nobr)
314
+
315
+ # text.gsub!(/<nobr>/, "<span class=\"nobr\">").gsub(/<\/nobr>/, "</span>") if (@de_nobr)
316
+
317
+ text.gsub(/(\s)+$/, "").gsub(/^(\s)+/, "")
318
+
319
+ end
320
+
321
+ end
@@ -0,0 +1,12 @@
1
+ if defined?(BlueCloth) && !BlueCloth.instance_methods.include?("to_html_without_rutils")
2
+ class Object::BlueCloth < String #:nodoc:
3
+ alias_method :to_html_without_rutils, :to_html
4
+ def to_html(*opts)
5
+ if RuTils::overrides_enabled?
6
+ RuTils::Gilenson::Formatter.new(to_html_without_rutils(*opts)).to_html
7
+ else
8
+ to_html_without_rutils(*opts)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,32 @@
1
+ module RuTils
2
+ @@overrides = true
3
+
4
+ # Метод позволяет проверить, включена ли перегрузка функций других модулей.
5
+ # Попутно он спрашивает модуль Locale (если таковой имеется) является ли русский
6
+ # текущим языком, и если является, включает перегрузку функций имплицитно.
7
+ # Это позволяет подчинить настройку перегруженных функций настроенной локали.
8
+ # Модуль Locale можно получить как часть Ruby-Gettext или как отдельный
9
+ # модуль ruby-locale. Мы поддерживаем оба.
10
+ def self.overrides_enabled?
11
+ if defined?(Locale) and Locale.respond_to?(:current)
12
+ return true if Locale.current.to_s.split('_').first == 'ru'
13
+ end
14
+ @@overrides ? true : false
15
+ end
16
+
17
+ # Включает или выключает перегрузки других модулей. Полезно, например, в случае когда нужно рендерить страницу
18
+ # сайта на нескольких языках и нужно отключить русское оформление текста для других языков.
19
+ def self.overrides= (new_override_flag)
20
+ @@overrides = (new_override_flag ? true : false)
21
+ end
22
+
23
+ # Вновь выполняет перегрузку. Делать это надо после того, как в программу импортированы
24
+ # другие модули.
25
+ def self.reload_integrations!
26
+ load File.dirname(__FILE__) + '/blue_cloth_override.rb'
27
+ load File.dirname(__FILE__) + '/red_cloth_override.rb'
28
+ load File.dirname(__FILE__) + '/rails_date_helper_override.rb'
29
+ end
30
+ end
31
+
32
+ RuTils::reload_integrations!
@@ -0,0 +1,113 @@
1
+ if defined?(Object::ActionView)
2
+ module Object::ActionView::Helpers::DateHelper
3
+
4
+ # Заменяет ActionView::Helpers::DateHelper::distance_of_time_in_words на русское сообщение.
5
+ #
6
+ # Целые числа интерпретируются как секунды
7
+ # <tt>distance_of_time_in_words(50)</tt> возвращает "меньше минуты".
8
+
9
+ alias :stock_distance_of_time_in_words :distance_of_time_in_words
10
+ def distance_of_time_in_words(*args)
11
+ RuTils::overrides_enabled? ? RuTils::DateTime::distance_of_time_in_words(*args) : stock_distance_of_time_in_words
12
+ end
13
+
14
+
15
+ # В Rails >= 2.1 3 аргумента у select_month
16
+ args_num = 2
17
+ begin
18
+ class TestClass
19
+ include Object::ActionView::Helpers::DateHelper
20
+ end
21
+ TestClass.new.select_month(Time.now, {}, {}, {}, {}, {}, {})
22
+ rescue ArgumentError => e
23
+ if e.message =~ /wrong number of arguments \(7 for (\d+)\)/
24
+ args_num = $1.to_i
25
+ end
26
+ end
27
+
28
+ case args_num
29
+ when 2
30
+ # Заменяет ActionView::Helpers::DateHelper::select_month меню выбора русских месяцев.
31
+ #
32
+ # select_month(Date.today) # Использует ключи "Январь", "Март"
33
+ # select_month(Date.today, :use_month_numbers => true) # Использует ключи "1", "3"
34
+ # select_month(Date.today, :add_month_numbers => true) # Использует ключи "1 - Январь", "3 - Март"
35
+ def select_month(date, options = {})
36
+ month_options = []
37
+ if RuTils::overrides_enabled?
38
+ month_names = case true
39
+ when options[:use_short_month]
40
+ Date::RU_ABBR_MONTHNAMES
41
+ # использование в контексте date_select с днями требует родительный падеж
42
+ when options[:order] && options[:order].include?(:day)
43
+ Date::RU_INFLECTED_MONTHNAMES
44
+ else
45
+ Date::RU_MONTHNAMES
46
+ end
47
+ else
48
+ month_names = options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES
49
+ end
50
+ 1.upto(12) do |month_number|
51
+ month_name = if options[:use_month_numbers]
52
+ month_number
53
+ elsif options[:add_month_numbers]
54
+ month_number.to_s + ' - ' + month_names[month_number]
55
+ else
56
+ month_names[month_number]
57
+ end
58
+
59
+ month_options << ((date && (date.kind_of?(Fixnum) ? date : date.month) == month_number) ?
60
+ %(<option value="#{month_number}" selected="selected">#{month_name}</option>\n) :
61
+ %(<option value="#{month_number}">#{month_name}</option>\n)
62
+ )
63
+ end
64
+
65
+ select_html(options[:field_name] || 'month', month_options, options)
66
+ end
67
+
68
+ # Заменяет ActionView::Helpers::DateHelper::select_date меню выбора русской даты.
69
+ def select_date(date = Date.today, options = {})
70
+ options[:order] ||= []
71
+ [:day, :month, :year].each { |o| options[:order].push(o) unless options[:order].include?(o) }
72
+
73
+ options[:order].map{ |o| self.send("select_#{o}", date, options) }.join
74
+ end
75
+
76
+ # Заменяет ActionView::Helpers::DateHelper::select_datetime меню выбора русской даты.
77
+ def select_datetime(datetime = Time.now, options = {})
78
+ select_day(datetime, options) + select_month(datetime, options) + select_year(datetime, options) +
79
+ select_hour(datetime, options) + select_minute(datetime, options)
80
+ end
81
+ when 3
82
+ # Rails 2.1
83
+
84
+ # Заменяет ActionView::Helpers::DateHelper::select_month меню выбора русских месяцев.
85
+ #
86
+ # select_month(Date.today) # Использует ключи "Январь", "Март"
87
+ # select_month(Date.today, :use_month_numbers => true) # Использует ключи "1", "3"
88
+ # select_month(Date.today, :add_month_numbers => true) # Использует ключи "1 - Январь", "3 - Март"
89
+ def select_month_with_rutils(date, options = {}, html_options = {})
90
+ if RuTils::overrides_enabled?
91
+ month_names = case true
92
+ when options[:use_short_month]
93
+ Date::RU_ABBR_MONTHNAMES
94
+ # использование в контексте date_select с днями требует родительный падеж
95
+ when options[:order] && options[:order].include?(:day)
96
+ Date::RU_INFLECTED_MONTHNAMES
97
+ else
98
+ Date::RU_MONTHNAMES
99
+ end
100
+ options = options.reverse_merge(:use_month_names => month_names)
101
+ end
102
+ select_month_without_rutils(date, options, html_options)
103
+ end
104
+ alias_method_chain :select_month, :rutils
105
+
106
+ def select_date_with_rutils(date = Date.today, options = {}, html_options = {})
107
+ options = options.reverse_merge(:order => [:day, :month, :year])
108
+ select_date_without_rutils(date, options, html_options)
109
+ end
110
+ alias_method_chain :select_date, :rutils
111
+ end
112
+ end
113
+ end #endif