rutils 0.2.1 → 0.2.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.
- data/CHANGELOG +6 -0
- data/bin/rutilize +2 -2
- data/lib/gilenson/gilenson.rb +520 -495
- data/lib/rutils.rb +1 -1
- data/test/t_datetime.rb +2 -1
- data/test/t_gilenson.rb +43 -2
- metadata +8 -8
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
Версия 0.2.2 - 24.09.2007
|
2
|
+
* Gilenson - обрабатываем акронимы по принципу Textile (zajats, julik)
|
3
|
+
* Gilenson - отформатирован под 2 пробела (julik)
|
4
|
+
* В тестах пользуйтесь assert_equal_cp (julik)
|
5
|
+
* Welcome to subversion (julik)
|
6
|
+
|
1
7
|
Версия 0.2.1 - 02.04.2007
|
2
8
|
* Восстановлен в gemspec gilenson.rb (Сергей Барабаш)
|
3
9
|
|
data/bin/rutilize
CHANGED
data/lib/gilenson/gilenson.rb
CHANGED
@@ -80,6 +80,9 @@ end
|
|
80
80
|
# "copypaste" - замена непечатных и "специальных" юникодных символов на entities
|
81
81
|
# "(c)" - обрабатывать знак копирайта
|
82
82
|
# "(r)", "(tm)", "(p)", "+-" - спецсимволы, какие - понятно
|
83
|
+
# "acronyms" - сворачивание пояснений к аббревиатурам (пояснение - в скобках после аббревиатуры
|
84
|
+
# без пробела). В текстовой версии пояснение будет "приклеено" к аббревиатуре
|
85
|
+
# полукруглой шпацией
|
83
86
|
# "degrees" - знак градуса
|
84
87
|
# "dashglue", "wordglue" - приклеивание предлогов и дефисов
|
85
88
|
# "spacing" - запятые и пробелы, перестановка
|
@@ -89,511 +92,533 @@ end
|
|
89
92
|
# "raw_output" - (по умолчанию false) - при true вместо entities выводятся UTF-символы
|
90
93
|
# "skip_attr" - (по умолчанию false) - при true не отрабатывать типографику в атрибутах тегов (title, alt)
|
91
94
|
# "skip_code" - (по умолчанию true) - при true не отрабатывать типографику внутри <code/>, <tt/>, CDATA
|
92
|
-
|
93
95
|
class RuTils::Gilenson::Formatter
|
94
|
-
|
96
|
+
attr_accessor :glyph
|
97
|
+
attr_accessor :settings
|
95
98
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
:quot => """, # quotation mark
|
123
|
-
:amp => "&", # ampersand
|
124
|
-
:apos => "'", # apos
|
125
|
-
:gt => ">", # greater-than sign
|
126
|
-
:lt => "<", # less-than sign
|
127
|
-
:nbsp => " ", # non-breaking space
|
128
|
-
:sect => "§", # section sign
|
129
|
-
:copy => "©", # copyright sign
|
130
|
-
:laquo => "«", # left-pointing double angle quotation mark = left pointing guillemet
|
131
|
-
:reg => "®", # registered sign = registered trade mark sign
|
132
|
-
:deg => "°", # degree sign
|
133
|
-
:plusmn => "±", # plus-minus sign = plus-or-minus sign
|
134
|
-
:para => "¶", # pilcrow sign = paragraph sign
|
135
|
-
:middot => "·", # middle dot = Georgian comma = Greek middle dot
|
136
|
-
:raquo => "»", # right-pointing double angle quotation mark = right pointing guillemet
|
137
|
-
:ndash => "–", # en dash
|
138
|
-
:mdash => "—", # em dash
|
139
|
-
:lsquo => "‘", # left single quotation mark
|
140
|
-
:rsquo => "’", # right single quotation mark
|
141
|
-
:ldquo => "“", # left double quotation mark
|
142
|
-
:rdquo => "”", # right double quotation mark
|
143
|
-
:bdquo => "„", # double low-9 quotation mark
|
144
|
-
:bull => "•", # bullet = black small circle
|
145
|
-
:hellip => "…", # horizontal ellipsis = three dot leader
|
146
|
-
:numero => "№", # numero
|
147
|
-
:trade => "™", # trade mark sign
|
148
|
-
:minus => "−", # minus sign
|
149
|
-
:inch => "″", # inch/second sign (u0x2033) (не путать с кавычками!)
|
150
|
-
:thinsp => " ", # полукруглая шпация (тонкий пробел)
|
151
|
-
:nob_open => '<nobr>', # открывающий блок без переноса слов
|
152
|
-
:nob_close => '</nobr>', # открывающий блок без переноса слов
|
153
|
-
} #:nodoc:
|
99
|
+
SETTINGS = {
|
100
|
+
"inches" => true, # преобразовывать дюймы в знак дюйма;
|
101
|
+
"laquo" => true, # кавычки-ёлочки
|
102
|
+
"quotes" => true, # кавычки-английские лапки
|
103
|
+
"dash" => true, # короткое тире (150)
|
104
|
+
"emdash" => true, # длинное тире двумя минусами (151)
|
105
|
+
"initials" => true, # тонкие шпации в инициалах
|
106
|
+
"copypaste" => false, # замена непечатных и "специальных" юникодных символов на entities
|
107
|
+
"(c)" => true, # обрабатывать знак копирайта
|
108
|
+
"(r)" => true,
|
109
|
+
"(tm)" => true,
|
110
|
+
"(p)" => true,
|
111
|
+
"acronyms" => true, # Акронимы с пояснениями - ЖЗЛ(Жизнь Замечатльных Людей)
|
112
|
+
"+-" => true, # спецсимволы, какие - понятно
|
113
|
+
"degrees" => true, # знак градуса
|
114
|
+
"dashglue" => true, "wordglue" => true, # приклеивание предлогов и дефисов
|
115
|
+
"spacing" => true, # запятые и пробелы, перестановка
|
116
|
+
"phones" => true, # обработка телефонов
|
117
|
+
"html" => true, # разрешение использования тагов html
|
118
|
+
"de_nobr" => false, # при true все <nobr/> заменяются на <span class="nobr"/>
|
119
|
+
"raw_output" => false, # выводить UTF-8 вместо entities
|
120
|
+
"skip_attr" => false, # при true не отрабатывать типографику в атрибутах тегов
|
121
|
+
"skip_code" => true, # при true не отрабатывать типографику внутри <code/>, <tt/>, CDATA
|
122
|
+
} #:nodoc:
|
123
|
+
|
124
|
+
SETTINGS.freeze
|
154
125
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
126
|
+
# Глифы, использующиеся в подстановках по-умолчанию
|
127
|
+
GLYPHS = {
|
128
|
+
:quot => """, # quotation mark
|
129
|
+
:amp => "&", # ampersand
|
130
|
+
:apos => "'", # apos
|
131
|
+
:gt => ">", # greater-than sign
|
132
|
+
:lt => "<", # less-than sign
|
133
|
+
:nbsp => " ", # non-breaking space
|
134
|
+
:sect => "§", # section sign
|
135
|
+
:copy => "©", # copyright sign
|
136
|
+
:laquo => "«", # left-pointing double angle quotation mark = left pointing guillemet
|
137
|
+
:reg => "®", # registered sign = registered trade mark sign
|
138
|
+
:deg => "°", # degree sign
|
139
|
+
:plusmn => "±", # plus-minus sign = plus-or-minus sign
|
140
|
+
:para => "¶", # pilcrow sign = paragraph sign
|
141
|
+
:middot => "·", # middle dot = Georgian comma = Greek middle dot
|
142
|
+
:raquo => "»", # right-pointing double angle quotation mark = right pointing guillemet
|
143
|
+
:ndash => "–", # en dash
|
144
|
+
:mdash => "—", # em dash
|
145
|
+
:lsquo => "‘", # left single quotation mark
|
146
|
+
:rsquo => "’", # right single quotation mark
|
147
|
+
:ldquo => "“", # left double quotation mark
|
148
|
+
:rdquo => "”", # right double quotation mark
|
149
|
+
:bdquo => "„", # double low-9 quotation mark
|
150
|
+
:bull => "•", # bullet = black small circle
|
151
|
+
:hellip => "…", # horizontal ellipsis = three dot leader
|
152
|
+
:numero => "№", # numero
|
153
|
+
:trade => "™", # trade mark sign
|
154
|
+
:minus => "−", # minus sign
|
155
|
+
:inch => "″", # inch/second sign (u0x2033) (не путать с кавычками!)
|
156
|
+
:thinsp => " ", # полукруглая шпация (тонкий пробел)
|
157
|
+
:nob_open => '<nobr>', # открывающий блок без переноса слов
|
158
|
+
:nob_close => '</nobr>', # открывающий блок без переноса слов
|
159
|
+
} #:nodoc:
|
160
|
+
|
161
|
+
GLYPHS.freeze
|
162
|
+
# Нормальные "типографские" символы в UTF-виде. Браузерами обрабатываются плохонько, поэтому
|
163
|
+
# лучше заменять их на entities.
|
164
|
+
VERBATIM_GLYPHS = {
|
165
|
+
' ' => :nbsp,# alt+0160 (NBSP here)
|
166
|
+
'«' => :laquo,
|
167
|
+
'»' => :raquo,
|
168
|
+
'§' => :sect,
|
169
|
+
'©' => :copy,
|
170
|
+
'®' => :reg,
|
171
|
+
'°' => :deg,
|
172
|
+
'±' => :plusmn,
|
173
|
+
'¶' => :para,
|
174
|
+
'·' => :middot,
|
175
|
+
'–' => :ndash,
|
176
|
+
'—' => :mdash,
|
177
|
+
'‘' => :lsquo,
|
178
|
+
'’' => :rsquo,
|
179
|
+
'“' => :ldquo,
|
180
|
+
'”' => :rdquo,
|
181
|
+
'„' => :bdquo,
|
182
|
+
'•' => :bull,
|
183
|
+
'…' => :hellip,
|
184
|
+
'№' => :numero,
|
185
|
+
'™' => :trade,
|
186
|
+
'−' => :minus,
|
187
|
+
' ' => :thinsp,
|
188
|
+
'″' => :inch,
|
189
|
+
}
|
190
|
+
VERBATIM_GLYPHS.freeze #:nodoc:
|
183
191
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
192
|
+
# Для маркера мы применяем UTF-BOM чтобы его НЕЛЬЗЯ было перепутать с частью
|
193
|
+
# любого другого мультибайтного глифа. Thanks to huNter.
|
194
|
+
REPLACEMENT_MARKER = RuTils::SUBSTITUTION_MARKER.freeze #:nodoc:
|
195
|
+
|
196
|
+
# Кто придумал “? Не учите людей плохому...
|
197
|
+
# Привет А.Лебедеву http://www.artlebedev.ru/kovodstvo/62/
|
198
|
+
# Используем символы, потом берем по символам из glyphs форматтера.
|
199
|
+
# Молодец mash!
|
200
|
+
FORBIDDEN_NUMERIC_ENTITIES = {
|
201
|
+
'132' => :bdquo,
|
202
|
+
'133' => :hellip,
|
203
|
+
'146' => :apos,
|
204
|
+
'147' => :ldquo,
|
205
|
+
'148' => :rdquo,
|
206
|
+
'149' => :bull,
|
207
|
+
'150' => :ndash,
|
208
|
+
'151' => :mdash,
|
209
|
+
'153' => :trade,
|
210
|
+
}
|
211
|
+
FORBIDDEN_NUMERIC_ENTITIES.freeze #:nodoc:
|
212
|
+
|
213
|
+
PROTECTED_SETTINGS = [ :raw_output ] #:nodoc:
|
205
214
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
# Настраивает форматтер ассоциированным хешем
|
213
|
-
# formatter.configure!(:dash=>true, :wordglue=>false)
|
214
|
-
def configure!(*config)
|
215
|
-
accept_configuration_arguments!(config.last) if config.last.is_a?(Hash)
|
216
|
-
end
|
217
|
-
|
218
|
-
alias :configure :configure! #Дружественный API
|
219
|
-
|
220
|
-
# Неизвестные методы - настройки. С = - установка ключа, без - получение значения
|
221
|
-
def method_missing(meth, *args) #:nodoc:
|
222
|
-
setting = meth.to_s.gsub(/=$/, '')
|
223
|
-
super(meth, *args) unless @settings.has_key?(setting) #this will pop the exception if we have no such setting
|
215
|
+
def initialize(*args)
|
216
|
+
@_text = args[0].is_a?(String) ? args[0] : ''
|
217
|
+
setup_default_settings!
|
218
|
+
accept_configuration_arguments!(args.last) if args.last.is_a?(Hash)
|
219
|
+
end
|
224
220
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
221
|
+
# Настраивает форматтер ассоциированным хешем
|
222
|
+
# formatter.configure!(:dash=>true, :wordglue=>false)
|
223
|
+
def configure!(*config)
|
224
|
+
accept_configuration_arguments!(config.last) if config.last.is_a?(Hash)
|
225
|
+
end
|
226
|
+
|
227
|
+
alias :configure :configure! #Дружественный API
|
228
|
+
|
229
|
+
# Неизвестные методы - настройки. С = - установка ключа, без - получение значения
|
230
|
+
def method_missing(meth, *args) #:nodoc:
|
231
|
+
setting = meth.to_s.gsub(/=$/, '')
|
232
|
+
super(meth, *args) unless @settings.has_key?(setting) #this will pop the exception if we have no such setting
|
233
|
+
|
234
|
+
return (@settings[setting] = args[0])
|
235
|
+
end
|
236
|
+
|
237
|
+
# Обрабатывает text_to_process с сохранением настроек, присвоенных обьекту-форматтеру
|
238
|
+
# Дополнительные аргументы передаются как параметры форматтера и не сохраняются после прогона.
|
239
|
+
def process(text_to_process, *args)
|
240
|
+
@_text = text_to_process
|
241
|
+
if args.last.is_a?(Hash)
|
242
|
+
with_configuration(args.last) { self.to_html }
|
243
|
+
else
|
244
|
+
self.to_html
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# Обрабатывает текст, присвоенный форматтеру при создании и возвращает результат обработки.
|
249
|
+
def to_html()
|
250
|
+
return '' unless @_text
|
251
|
+
|
252
|
+
text = @_text.strip
|
253
|
+
|
254
|
+
# -4. запрет тагов html
|
255
|
+
process_escape_html(text) unless @settings["html"]
|
256
|
+
|
257
|
+
# -3. Никогда (вы слышите?!) не пущать лабуду &#not_correct_number;
|
258
|
+
FORBIDDEN_NUMERIC_ENTITIES.dup.each_pair do | key, rep |
|
259
|
+
text.gsub!(/&##{key};/, glyph[rep])
|
260
|
+
end
|
261
|
+
|
262
|
+
# -2. Чистим copy&paste
|
263
|
+
process_copy_paste_clearing(text) if @settings['copypaste']
|
264
|
+
|
265
|
+
# -1. Замена &entity_name; на входе (' ' => ' ' и т.д.)
|
266
|
+
process_html_entities(text)
|
267
|
+
|
268
|
+
# 0. Вырезаем таги
|
269
|
+
tags = lift_ignored_elements(text) if @skip_tags
|
270
|
+
|
271
|
+
# 1. Запятые и пробелы
|
272
|
+
process_spacing(text) if @settings["spacing"]
|
273
|
+
|
274
|
+
# 3. Спецсимволы
|
275
|
+
# 0. дюймы с цифрами
|
276
|
+
# заменено на инчи
|
277
|
+
process_inches(text) if @settings["inches"]
|
278
|
+
|
279
|
+
# 1. лапки
|
280
|
+
process_quotes(text) if @settings["quotes"]
|
281
|
+
|
282
|
+
# 2. ёлочки
|
283
|
+
process_laquo(text) if @settings["laquo"]
|
284
|
+
|
285
|
+
# 2b. одновременно ёлочки и лапки
|
286
|
+
process_compound_quotes(text) if (@settings["quotes"] && @settings["laquo"])
|
287
|
+
|
288
|
+
# 3. тире
|
289
|
+
process_dash(text) if @settings["dash"]
|
290
|
+
|
291
|
+
# 3a. тире длинное
|
292
|
+
process_emdash(text) if @settings["emdash"]
|
293
|
+
|
294
|
+
# 5. +/-
|
295
|
+
process_plusmin(text) if @settings["+-"]
|
296
|
+
|
297
|
+
# 5a. 12^C
|
298
|
+
process_degrees(text) if @settings["degrees"]
|
299
|
+
|
300
|
+
# 6. телефоны
|
301
|
+
process_phones(text) if @settings["phones"]
|
302
|
+
|
303
|
+
# 7. Короткие слова и
|
304
|
+
process_wordglue(text) if @settings["wordglue"]
|
305
|
+
|
306
|
+
# 8. Склейка ласт. Тьфу! дефисов.
|
307
|
+
process_dashglue(text) if @settings["dashglue"]
|
308
|
+
|
309
|
+
# 8a. Инициалы
|
310
|
+
process_initials(text) if @settings['initials']
|
311
|
+
|
312
|
+
# 8b. Троеточия
|
313
|
+
process_ellipsises(text) if @settings["wordglue"]
|
314
|
+
|
315
|
+
# 9. Акронимы от Текстиля
|
316
|
+
process_acronyms(text) if @settings["acronyms"]
|
317
|
+
|
318
|
+
# БЕСКОНЕЧНОСТЬ. Вставляем таги обратно.
|
319
|
+
reinsert_fragments(text, tags) if @skip_tags
|
320
|
+
|
321
|
+
# фуф, закончили.
|
322
|
+
process_span_instead_of_nobr(text) if @settings["de_nobr"]
|
323
|
+
|
324
|
+
# заменяем entities на истинные символы
|
325
|
+
process_raw_output(text) if @settings["raw_output"]
|
326
|
+
|
327
|
+
text.strip
|
328
|
+
end
|
329
|
+
|
318
330
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
331
|
+
# Применяет отдельный фильтр к text и возвращает результат. Например:
|
332
|
+
# formatter.apply(:wordglue, "Вот так") => "Вот так"
|
333
|
+
# Удобно применять когда вам нужно задействовать отдельный фильтр Гиленсона, но не нужна остальная механика
|
334
|
+
# Последний аргумент определяет, нужно ли при применении фильтра сохранить в неприкосновенности таги и другие
|
335
|
+
# игнорируемые фрагменты текста (по умолчанию они сохраняются).
|
336
|
+
def apply(filter, text, lift_ignored_elements = true)
|
337
|
+
copy = text.dup
|
338
|
+
unless lift_ignored_elements
|
339
|
+
self.send("process_#{filter}".to_sym, copy)
|
340
|
+
else
|
341
|
+
lifting_fragments(copy) { self.send("process_#{filter}".to_sym, copy) }
|
342
|
+
end
|
343
|
+
copy
|
344
|
+
end
|
333
345
|
|
334
|
-
|
335
|
-
|
336
|
-
def setup_default_settings!
|
337
|
-
@skip_tags = true;
|
338
|
-
@ignore = /notypo/ # regex, который игнорируется. Этим надо воспользоваться для обработки pre и code
|
339
|
-
|
340
|
-
@glueleft = ['рис.', 'табл.', 'см.', 'им.', 'ул.', 'пер.', 'кв.', 'офис', 'оф.', 'г.']
|
341
|
-
@glueright = ['руб.', 'коп.', 'у.е.', 'мин.']
|
342
|
-
|
343
|
-
# Установки можно менять в каждом экземпляре
|
344
|
-
@settings = SETTINGS.dup
|
345
|
-
|
346
|
-
@mark_tag = REPLACEMENT_MARKER
|
347
|
-
# Глифы можено подменять в экземпляре форматтера поэтому копируем их из константы
|
348
|
-
@glyph = GLYPHS.dup
|
349
|
-
|
350
|
-
@phonemasks = [[ /([0-9]{4})\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/,
|
351
|
-
/([0-9]{4})\-([0-9]{2})\-([0-9]{2})/,
|
352
|
-
/(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
|
353
|
-
/(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
|
354
|
-
/(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})/,
|
355
|
-
/(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{3})/,
|
356
|
-
/([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
|
357
|
-
/([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
|
358
|
-
/([0-9]{1})\-([0-9]{2})\-([0-9]{2})/,
|
359
|
-
/([0-9]{2})\-([0-9]{3})/,
|
360
|
-
/([0-9]+)\-([0-9]+)/,
|
361
|
-
],[
|
362
|
-
':nob_open\1:ndash\2:ndash\3:nbsp\4:\5:\6:nob_close',
|
363
|
-
':nob_open\1:ndash\2:ndash\3:nob_close',
|
364
|
-
':nob_open\1:nbsp\2:ndash\3:ndash\4:nob_close',
|
365
|
-
':nob_open\1:nbsp\2:ndash\3:ndash\4:nob_close',
|
366
|
-
':nob_open\1:nbsp\2:ndash\3:nob_close',
|
367
|
-
':nob_open\1:nbsp\2:ndash\3:nob_close',
|
368
|
-
':nob_open\1:ndash\2:ndash\3:nob_close',
|
369
|
-
':nob_open\1:ndash\2:ndash\3:nob_close',
|
370
|
-
':nob_open\1:ndash\2:ndash\3:nob_close',
|
371
|
-
':nob_open\1:ndash\2:nob_close',
|
372
|
-
':nob_open\1:ndash\2:nob_close'
|
373
|
-
]]
|
374
|
-
end
|
346
|
+
private
|
375
347
|
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
# Выполняет блок, временно включая настройки переданные в +hash+
|
391
|
-
def with_configuration(hash, &block)
|
392
|
-
old_settings, old_glyphs = @settings.dup, @glyph.dup
|
393
|
-
accept_configuration_arguments!(hash)
|
394
|
-
txt = yield
|
395
|
-
@settings, @glyph = old_settings, old_glyphs
|
396
|
-
|
397
|
-
return txt
|
398
|
-
end
|
348
|
+
def setup_default_settings!
|
349
|
+
@skip_tags = true;
|
350
|
+
@ignore = /notypo/ # regex, который игнорируется. Этим надо воспользоваться для обработки pre и code
|
351
|
+
|
352
|
+
@glueleft = ['рис.', 'табл.', 'см.', 'им.', 'ул.', 'пер.', 'кв.', 'офис', 'оф.', 'г.']
|
353
|
+
@glueright = ['руб.', 'коп.', 'у.е.', 'мин.']
|
354
|
+
|
355
|
+
# Установки можно менять в каждом экземпляре
|
356
|
+
@settings = SETTINGS.dup
|
357
|
+
|
358
|
+
@mark_tag = REPLACEMENT_MARKER
|
359
|
+
# Глифы можено подменять в экземпляре форматтера поэтому копируем их из константы
|
360
|
+
@glyph = GLYPHS.dup
|
399
361
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
362
|
+
@phonemasks = [[ /([0-9]{4})\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/,
|
363
|
+
/([0-9]{4})\-([0-9]{2})\-([0-9]{2})/,
|
364
|
+
/(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
|
365
|
+
/(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
|
366
|
+
/(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})/,
|
367
|
+
/(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{3})/,
|
368
|
+
/([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
|
369
|
+
/([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
|
370
|
+
/([0-9]{1})\-([0-9]{2})\-([0-9]{2})/,
|
371
|
+
/([0-9]{2})\-([0-9]{3})/,
|
372
|
+
/([0-9]+)\-([0-9]+)/,
|
373
|
+
],[
|
374
|
+
':nob_open\1:ndash\2:ndash\3:nbsp\4:\5:\6:nob_close',
|
375
|
+
':nob_open\1:ndash\2:ndash\3:nob_close',
|
376
|
+
':nob_open\1:nbsp\2:ndash\3:ndash\4:nob_close',
|
377
|
+
':nob_open\1:nbsp\2:ndash\3:ndash\4:nob_close',
|
378
|
+
':nob_open\1:nbsp\2:ndash\3:nob_close',
|
379
|
+
':nob_open\1:nbsp\2:ndash\3:nob_close',
|
380
|
+
':nob_open\1:ndash\2:ndash\3:nob_close',
|
381
|
+
':nob_open\1:ndash\2:ndash\3:nob_close',
|
382
|
+
':nob_open\1:ndash\2:ndash\3:nob_close',
|
383
|
+
':nob_open\1:ndash\2:nob_close',
|
384
|
+
':nob_open\1:ndash\2:nob_close'
|
385
|
+
]]
|
386
|
+
end
|
387
|
+
|
388
|
+
# Позволяет получить процедуру, при вызове возвращающую значение глифа
|
389
|
+
def lookup(glyph_to_lookup)
|
390
|
+
return Proc.new { self.glyph[glyph_to_lookup] }
|
391
|
+
end
|
392
|
+
|
393
|
+
# Подставляет "символы" (двоеточие + имя глифа) на нужное значение глифа заданное в данном форматтере
|
394
|
+
def substitute_glyphs_in_string(str)
|
395
|
+
re = str.dup
|
396
|
+
@glyph.each_pair do | key, subst |
|
397
|
+
re.gsub!(":#{key.to_s}", subst)
|
398
|
+
end
|
399
|
+
re
|
400
|
+
end
|
401
|
+
|
402
|
+
# Выполняет блок, временно включая настройки переданные в +hash+
|
403
|
+
def with_configuration(hash, &block)
|
404
|
+
old_settings, old_glyphs = @settings.dup, @glyph.dup
|
405
|
+
accept_configuration_arguments!(hash)
|
406
|
+
txt = yield
|
407
|
+
@settings, @glyph = old_settings, old_glyphs
|
408
|
+
|
409
|
+
return txt
|
410
|
+
end
|
411
|
+
|
412
|
+
def accept_configuration_arguments!(args_hash)
|
413
|
+
|
414
|
+
# Специальный случай - :all=>true|false
|
415
|
+
if args_hash.has_key?(:all)
|
416
|
+
if args_hash[:all]
|
417
|
+
@settings.each_pair {|k, v| @settings[k] = true unless PROTECTED_SETTINGS.include?(k.to_sym)}
|
418
|
+
else
|
419
|
+
@settings.each_pair {|k, v| @settings[k] = false unless PROTECTED_SETTINGS.include?(k.to_sym)}
|
420
|
+
end
|
421
|
+
else
|
422
|
+
|
423
|
+
# Кинуть ошибку если настройка нам неизвестна
|
424
|
+
unknown_settings = args_hash.keys.collect{|k|k.to_s} - @settings.keys.collect { |k| k.to_s }
|
425
|
+
raise RuTils::Gilenson::UnknownSetting, unknown_settings if unknown_settings.any?
|
426
|
+
|
427
|
+
args_hash.each_pair do | key, value |
|
428
|
+
@settings[key.to_s] = (value ? true : false)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
# Вынимает игнорируемые фрагменты и заменяет их маркером, выполняет переданный блок и вставляет вынутое на место
|
434
|
+
def lifting_fragments(text, &block)
|
435
|
+
lifted = lift_ignored_elements(text)
|
436
|
+
yield
|
437
|
+
reinsert_fragments(text, lifted)
|
438
|
+
end
|
439
|
+
|
440
|
+
#Вынимает фрагменты из текста и возвращает массив с фрагментами
|
441
|
+
def lift_ignored_elements(text)
|
442
|
+
# re = /<\/?[a-z0-9]+("+ # имя тага
|
443
|
+
# "\s+("+ # повторяющая конструкция: хотя бы один разделитель и тельце
|
444
|
+
# "[a-z]+("+ # атрибут из букв, за которым может стоять знак равенства и потом
|
445
|
+
# "=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+))"+ #
|
446
|
+
# ")?"+
|
447
|
+
# ")?"+
|
448
|
+
# ")*\/?>|\xA2\xA2[^\n]*?==/i;
|
449
|
+
|
450
|
+
re_skipcode = '((<(code|tt)[ >](.*?)<\/(code|tt)>)|(<!\[CDATA\[(.*?)\]\]>))|' if @settings['skip_code']
|
451
|
+
re = /(#{re_skipcode}<\/?[a-z0-9]+(\s+([a-z]+(=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+)))?)?)*\/?>)/uim
|
452
|
+
tags = text.scan(re).map{ |tag| tag[0] } # первая группа!
|
453
|
+
text.gsub!(re, @mark_tag) #маркер тега, мы используем Invalid UTF-sequence для него
|
454
|
+
return tags
|
455
|
+
end
|
456
|
+
|
457
|
+
def reinsert_fragments(text, fragments)
|
458
|
+
fragments.each do |fragment|
|
459
|
+
fragment.gsub!(/ (href|src|data)=((?:(\')([^\']*)(\'))|(?:(\")([^\"]*)(\")))/uim) do
|
460
|
+
" #{$1}=" + $2.gsub(/&(?!(#0*38)|(amp);)/, self.glyph[:amp])
|
461
|
+
end # unless @settings['raw_output'] -- делать это надо всегда (mash)
|
462
|
+
|
463
|
+
unless @settings['skip_attr']
|
464
|
+
fragment.gsub!(/ (title|alt)=((?:(\')([^\']*)(\'))|(?:(\")([^\"]*)(\")))/uim) do
|
465
|
+
" #{$1}=#{$3}" + self.process($4.to_s) + "#{$5}#{$6}" + self.process($7.to_s) + "#{$8}"
|
466
|
+
end
|
467
|
+
end
|
468
|
+
text.sub!(@mark_tag, fragment)
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
### Имплементации фильтров
|
473
|
+
def process_html_entities(text)
|
474
|
+
self.glyph.each { |key, value| text.gsub!(/&#{key};/, value)}
|
475
|
+
end
|
476
|
+
|
477
|
+
def process_initials(text)
|
478
|
+
initials = /([А-Я])[\.]{1,2}[\s]*?([А-Я])[\.]*[\s]*?([А-Я])([а-я])/u
|
479
|
+
replacement = substitute_glyphs_in_string('\1.\2.:thinsp\3\4')
|
480
|
+
text.gsub!(initials, replacement)
|
481
|
+
end
|
482
|
+
|
483
|
+
def process_copy_paste_clearing(text)
|
484
|
+
VERBATIM_GLYPHS.each {|key,value| text.gsub!(/#{key}/, glyph[value]) }
|
485
|
+
end
|
486
|
+
|
487
|
+
def process_spacing(text)
|
488
|
+
text.gsub!( /(\s*)([,]*)/sui, '\2\1');
|
489
|
+
text.gsub!( /(\s*)([\.?!]*)(\s*[ЁА-ЯA-Z])/su, '\2\1\3');
|
490
|
+
end
|
491
|
+
|
492
|
+
def process_dashglue(text)
|
493
|
+
text.gsub!( /([a-zа-яА-Я0-9]+(\-[a-zа-яА-Я0-9]+)+)/ui, glyph[:nob_open]+'\1'+glyph[:nob_close])
|
494
|
+
end
|
495
|
+
|
496
|
+
def process_escape_html(text)
|
497
|
+
text.gsub!(/&/, glyph[:amp])
|
498
|
+
text.gsub!(/</, glyph[:lt])
|
499
|
+
text.gsub!(/>/, glyph[:gt])
|
500
|
+
end
|
501
|
+
|
502
|
+
def process_span_instead_of_nobr(text)
|
503
|
+
text.gsub!(/<nobr>/, '<span class="nobr">')
|
504
|
+
text.gsub!(/<\/nobr>/, '</span>')
|
505
|
+
end
|
506
|
+
|
507
|
+
def process_dash(text)
|
508
|
+
text.gsub!( /(\s|;)\-(\s)/ui, '\1'+self.glyph[:ndash]+'\2')
|
509
|
+
end
|
510
|
+
|
511
|
+
def process_emdash(text)
|
512
|
+
text.gsub!( /(\s|;)\-\-(\s)/ui, '\1'+self.glyph[:mdash]+'\2')
|
513
|
+
# 4. (с)
|
514
|
+
text.gsub!(/\([сСcC]\)((?=\w)|(?=\s[0-9]+))/u, self.glyph[:copy]) if @settings["(c)"]
|
515
|
+
# 4a. (r)
|
516
|
+
text.gsub!( /\(r\)/ui, '<sup>'+self.glyph[:reg]+'</sup>') if @settings["(r)"]
|
517
|
+
|
518
|
+
# 4b. (tm)
|
519
|
+
text.gsub!( /\(tm\)|\(тм\)/ui, self.glyph[:trade]) if @settings["(tm)"]
|
520
|
+
# 4c. (p)
|
521
|
+
text.gsub!( /\(p\)/ui, self.glyph[:sect]) if @settings["(p)"]
|
522
|
+
end
|
523
|
+
|
524
|
+
def process_ellipsises(text)
|
525
|
+
text.gsub!( '...', self.glyph[:hellip])
|
526
|
+
end
|
527
|
+
|
528
|
+
def process_laquo(text)
|
529
|
+
text.gsub!( /\"\"/ui, self.glyph[:quot]*2);
|
530
|
+
text.gsub!( /(^|\s|#{@mark_tag}|>|\()\"((#{@mark_tag})*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, '\1'+self.glyph[:laquo]+'\2');
|
531
|
+
_text = '""';
|
532
|
+
until _text == text do
|
533
|
+
_text = text;
|
534
|
+
text.gsub!( /(#{self.glyph[:laquo]}([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/\?\!](#{@mark_tag})*)\"/sui,
|
535
|
+
'\1'+self.glyph[:raquo])
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
def process_quotes(text)
|
540
|
+
text.gsub!( /\"\"/ui, self.glyph[:quot]*2)
|
541
|
+
text.gsub!( /\"\.\"/ui, self.glyph[:quot]+"."+self.glyph[:quot])
|
542
|
+
_text = '""';
|
543
|
+
until _text == text do
|
544
|
+
_text = text.dup
|
545
|
+
text.gsub!( /(^|\s|#{@mark_tag}|>)\"([0-9A-Za-z\'\!\s\.\?\,\-\&\;\:\_\#{@mark_tag}]+(\"|#{self.glyph[:rdquo]}))/ui, '\1'+self.glyph[:ldquo]+'\2')
|
546
|
+
#this doesnt work in-place. somehow.
|
547
|
+
text.gsub!( /(#{self.glyph[:ldquo]}([A-Za-z0-9\'\!\s\.\?\,\-\&\;\:\#{@mark_tag}\_]*).*[A-Za-z0-9][\#{@mark_tag}\?\.\!\,]*)\"/ui, '\1'+self.glyph[:rdquo])
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
def process_compound_quotes(text)
|
552
|
+
text.gsub!(/(#{self.glyph[:ldquo]}(([A-Za-z0-9'!\.?,\-&;:]|\s|#{@mark_tag})*)#{self.glyph[:laquo]}(.*)#{self.glyph[:raquo]})#{self.glyph[:raquo]}/ui,'\1'+self.glyph[:rdquo]);
|
553
|
+
end
|
554
|
+
|
555
|
+
def process_degrees(text)
|
556
|
+
text.gsub!( /-([0-9])+\^([FCС])/, self.glyph[:ndash]+'\1'+self.glyph[:deg]+'\2') #deg
|
557
|
+
text.gsub!( /\+([0-9])+\^([FCС])/, '+\1'+self.glyph[:deg]+'\2')
|
558
|
+
text.gsub!( /\^([FCС])/, self.glyph[:deg]+'\1')
|
559
|
+
end
|
560
|
+
|
561
|
+
def process_wordglue(text)
|
562
|
+
text.replace(" " + text + " ")
|
563
|
+
_text = " " + text + " "
|
564
|
+
|
565
|
+
until _text == text
|
566
|
+
_text = text
|
567
|
+
text.gsub!( /(\s+)([a-zа-яА-Я]{1,2})(\s+)([^\\s$])/ui, '\1\2' + glyph[:nbsp]+'\4')
|
568
|
+
text.gsub!( /(\s+)([a-zа-яА-Я]{3})(\s+)([^\\s$])/ui, '\1\2' + glyph[:nbsp]+'\4')
|
569
|
+
end
|
570
|
+
|
571
|
+
text.gsub!(/(\s+)([a-zа-яА-Я]{1,2}[\)\]\!\?,\.;]{0,3}\s$)/ui, glyph[:nbsp]+'\2')
|
572
|
+
|
573
|
+
@glueleft.each { | i | text.gsub!( /(\s)(#{i})(\s+)/sui, '\1\2' + glyph[:nbsp]) }
|
574
|
+
|
575
|
+
@glueright.each { | i | text.gsub!( /(\s)(#{i})(\s+)/sui, glyph[:nbsp]+'\2\3') }
|
576
|
+
|
577
|
+
text.strip!
|
578
|
+
end
|
579
|
+
|
580
|
+
def process_phones(text)
|
581
|
+
@phonemasks[0].each_with_index do |pattern, i|
|
582
|
+
replacement = substitute_glyphs_in_string(@phonemasks[1][i])
|
583
|
+
text.gsub!(pattern, replacement)
|
596
584
|
end
|
585
|
+
end
|
586
|
+
|
587
|
+
def process_acronyms(text)
|
588
|
+
acronym = /\b([A-ZА-Я][A-ZА-Я0-9]{2,})\b(?:[(]([^)]*)[)])/u
|
589
|
+
if @settings["raw_output"]
|
590
|
+
text.gsub!(acronym, '\1%s(\2)' % glyph[:thinsp])
|
591
|
+
else
|
592
|
+
text.gsub!(acronym) do
|
593
|
+
expl = $2.to_s; process_escape_html(expl)
|
594
|
+
"<acronym title=\"#{expl}\">#{$1}</acronym>"
|
595
|
+
end
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
def process_inches(text)
|
600
|
+
text.gsub!(/\s([0-9]{1,2}([\.,][0-9]{1,2})?)\"/ui, ' \1'+self.glyph[:inch])
|
601
|
+
end
|
602
|
+
|
603
|
+
def process_plusmin(text)
|
604
|
+
text.gsub!(/[^+]\+\-/ui, self.glyph[:plusmn])
|
605
|
+
end
|
606
|
+
|
607
|
+
# Подменяет все юникодные entities в тексте на истинные UTF-8-символы
|
608
|
+
def process_raw_output(text)
|
609
|
+
# Все глифы
|
610
|
+
@glyph.values.each do | entity |
|
611
|
+
next unless entity =~ /^&#(\d+);/
|
612
|
+
text.gsub!(/#{entity}/, entity_to_raw_utf8(entity))
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
# Конвертирует юникодные entities в UTF-8-codepoints
|
617
|
+
def entity_to_raw_utf8(entity)
|
618
|
+
entity =~ /^&#(\d+);/
|
619
|
+
$1 ? [$1.to_i].pack("U") : entity
|
620
|
+
end
|
621
|
+
|
597
622
|
end #end Gilenson
|
598
623
|
|
599
624
|
# Выбрасывается если форматтеру задается неизвестная настройка
|
@@ -614,4 +639,4 @@ module RuTils::Gilenson::StringFormatting
|
|
614
639
|
end
|
615
640
|
end
|
616
641
|
|
617
|
-
Object::String.send(:include, RuTils::Gilenson::StringFormatting)
|
642
|
+
Object::String.send(:include, RuTils::Gilenson::StringFormatting)
|
data/lib/rutils.rb
CHANGED
data/test/t_datetime.rb
CHANGED
@@ -25,7 +25,8 @@ class StrftimeRuTest < Test::Unit::TestCase
|
|
25
25
|
|
26
26
|
date = Date.new(2005, 12, 31)
|
27
27
|
assert_equal "дек декабрь сб суббота", "#{Date::RU_ABBR_MONTHNAMES[date.mon]} #{Date::RU_MONTHNAMES[date.mon]} #{Date::RU_ABBR_DAYNAMES[date.wday]} #{Date::RU_DAYNAMES[date.wday]}"
|
28
|
-
|
28
|
+
# We do not support strftime on date at this point
|
29
|
+
# assert_equal "сб, суббота, дек, декабрь", date.strftime("%a, %A, %b, %B")
|
29
30
|
|
30
31
|
RuTils::overrides = false
|
31
32
|
assert_equal "Sat, Saturday, Dec, December", Time.local(2005,"dec",31).strftime("%a, %A, %b, %B")
|
data/test/t_gilenson.rb
CHANGED
@@ -34,6 +34,26 @@ class GilensonOwnTest < Test::Unit::TestCase
|
|
34
34
|
assert_equal '<nobr>725–01–10</nobr>', '725-01-10'.gilensize
|
35
35
|
end
|
36
36
|
|
37
|
+
def test_acronyms_with_html_output
|
38
|
+
assert_equal '<acronym title="Большая советская энциклопедия">БСЭ</acronym>', 'БСЭ(Большая советская энциклопедия)'.gilensize
|
39
|
+
assert_equal '<acronym title="Advanced Micro Devices">AMD</acronym>',
|
40
|
+
'AMD(Advanced Micro Devices)'.gilensize
|
41
|
+
assert_equal '<acronym title="Расширяемый язык разметки">XML</acronym>',
|
42
|
+
'XML(Расширяемый язык разметки)'.gilensize
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_acronyms_should_escape_entities
|
46
|
+
@gilenson.configure(:raw_output => false)
|
47
|
+
assert_equal '<acronym title="Знак <">БВГ</acronym>', 'БВГ(Знак <)'.gilensize
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_acronyms_with_text_output
|
51
|
+
@gilenson.configure(:raw_output => true)
|
52
|
+
thin_space = [8201].pack("U")
|
53
|
+
assert_equal_cp "так утверждает БСЭ#{thin_space}(Большая советская энциклопедия)",
|
54
|
+
@gilenson.process('так утверждает БСЭ(Большая советская энциклопедия)')
|
55
|
+
end
|
56
|
+
|
37
57
|
def test_address
|
38
58
|
assert_equal 'табл. 2, рис. 2.10', 'табл. 2, рис. 2.10'.gilensize
|
39
59
|
assert_equal 'офис 415, оф.340, д.5, ул. Народной Воли, пл. Малышева', 'офис 415, оф.340, д.5, ул. Народной Воли, пл. Малышева'.gilensize
|
@@ -243,6 +263,28 @@ class GilensonOwnTest < Test::Unit::TestCase
|
|
243
263
|
@gilenson.process("<a href='test?test15=15&pp;test16=16'>test&</a>")
|
244
264
|
|
245
265
|
end
|
266
|
+
|
267
|
+
private
|
268
|
+
# Проверить равны ли строки, и если нет то обьяснить какой кодпойнт отличается.
|
269
|
+
# Совершенно необходимо для работы с различными пробелами.
|
270
|
+
def assert_equal_cp(reference, actual, msg = nil)
|
271
|
+
(assert(true, msg); return) if (reference == actual)
|
272
|
+
|
273
|
+
reference_cp, actual_cp = [reference, actual].map{|t| t.unpack("U*") }
|
274
|
+
reference_cp.each_with_index do | ref_codepoint, idx |
|
275
|
+
next unless actual_cp[idx] != ref_codepoint
|
276
|
+
beg, fin = idx - 2, idx + 2
|
277
|
+
beg = 0 if (beg < 0)
|
278
|
+
conflicting_piece = actual_cp[beg..fin].pack("U*")
|
279
|
+
msg = []
|
280
|
+
msg << "Expected #{actual.inspect} to be equal to #{reference.inspect}, but they were not, " +
|
281
|
+
"in fragment '#{beg > 0 ? '...' : ''}#{conflicting_piece}...'"
|
282
|
+
msg << "Non-matching codepoint #{actual[idx]} at offset #{idx}, " +
|
283
|
+
"expected codepoint #{ref_codepoint} instead"
|
284
|
+
flunk msg.join("\n"); return
|
285
|
+
end
|
286
|
+
raise "We should never get here"
|
287
|
+
end
|
246
288
|
end
|
247
289
|
|
248
290
|
|
@@ -306,7 +348,6 @@ class GilensonConfigurationTest < Test::Unit::TestCase
|
|
306
348
|
assert @gilenson.configure(:raw_output=>true)
|
307
349
|
assert @gilenson.configure!(:raw_output=>true)
|
308
350
|
end
|
309
|
-
|
310
351
|
end
|
311
352
|
|
312
353
|
# class TypograficaTrakoEntries < Test::Unit::TestCase
|
@@ -321,4 +362,4 @@ end
|
|
321
362
|
# def test_paths # http://pixel-apes.com/typografica/trako/13
|
322
363
|
# assert_equal '«c:\www\sites\»', '"c:\www\sites\"'.gilensize
|
323
364
|
# end
|
324
|
-
# end
|
365
|
+
# end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: rutils
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.2.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.2.2
|
7
|
+
date: 2007-09-24 00:00:00 +02:00
|
8
8
|
summary: Simple processing of russian strings
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -40,21 +40,21 @@ files:
|
|
40
40
|
- test/t_transliteration.rb
|
41
41
|
- test/t_typografica.rb
|
42
42
|
- lib/countries
|
43
|
-
- lib/datetime
|
44
|
-
- lib/gilenson
|
45
|
-
- lib/integration
|
46
|
-
- lib/pluralizer
|
47
|
-
- lib/rutils.rb
|
48
|
-
- lib/transliteration
|
49
43
|
- lib/countries/countries.rb
|
44
|
+
- lib/datetime
|
50
45
|
- lib/datetime/datetime.rb
|
46
|
+
- lib/gilenson
|
51
47
|
- lib/gilenson/gilenson.rb
|
52
48
|
- lib/gilenson/gilenson_port.rb
|
49
|
+
- lib/integration
|
53
50
|
- lib/integration/blue_cloth_override.rb
|
54
51
|
- lib/integration/integration.rb
|
55
52
|
- lib/integration/rails_date_helper_override.rb
|
56
53
|
- lib/integration/red_cloth_override.rb
|
54
|
+
- lib/pluralizer
|
57
55
|
- lib/pluralizer/pluralizer.rb
|
56
|
+
- lib/rutils.rb
|
57
|
+
- lib/transliteration
|
58
58
|
- lib/transliteration/bidi.rb
|
59
59
|
- lib/transliteration/simple.rb
|
60
60
|
- lib/transliteration/transliteration.rb
|