rutils 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +4 -3
- data/lib/datetime/datetime.rb +10 -6
- data/lib/gilenson/gilenson.rb +263 -264
- data/lib/integration/blue_cloth_override.rb +6 -6
- data/lib/integration/integration.rb +4 -4
- data/lib/integration/rails_date_helper_override.rb +4 -4
- data/lib/integration/red_cloth_override.rb +13 -14
- data/lib/pluralizer/pluralizer.rb +12 -3
- data/lib/rutils.rb +4 -1
- data/test/t_datetime.rb +2 -1
- data/test/t_pluralize.rb +4 -2
- metadata +3 -2
data/README
CHANGED
@@ -12,7 +12,7 @@ Gilenson работает медленнее).
|
|
12
12
|
|
13
13
|
Это версия RuTils
|
14
14
|
|
15
|
-
$Revision: 1.
|
15
|
+
$Revision: 1.7 $
|
16
16
|
|
17
17
|
Пожалуйста упоминайте версию при сообщении ошибок.
|
18
18
|
|
@@ -23,7 +23,7 @@ Gilenson работает медленнее).
|
|
23
23
|
|
24
24
|
Если вы используете RuTils для сайта под mod_ruby воспользуйтесь директивой RubyKanjiCode в своем httpd.conf.
|
25
25
|
|
26
|
-
== Cумма прописью
|
26
|
+
== Cумма прописью и выбор числительного
|
27
27
|
|
28
28
|
RuTils реализует сумму прописью для целых и дробных чисел, с дополнительным учетом рода. Например:
|
29
29
|
|
@@ -74,7 +74,8 @@ RuTils автоматически будет обрабатывать типог
|
|
74
74
|
|
75
75
|
В принципе если вы пользуетесь RedCloth или BlueCloth все что ими обрабатывается будет автоматически
|
76
76
|
обрабатываться и Gilenson'ом тоже. В случае с RedCloth Glienson автоматически заменяет стандартные для
|
77
|
-
Textile английские кавычки и типографские знаки на свои - русские.
|
77
|
+
Textile английские кавычки и типографские знаки на свои - русские. В случае BlueCloth Gilenson используется
|
78
|
+
как "декоратор" Markdown.
|
78
79
|
|
79
80
|
Перегрузку всех функций (RedCloth, BlueCloth и компоненты Rails) можно включать и отключать в любое время
|
80
81
|
с помощью метода overrides= модуля RuTils. Когда перегрузка выключена, все сторонние библиотеки будут работать
|
data/lib/datetime/datetime.rb
CHANGED
@@ -18,19 +18,23 @@ module RuTils
|
|
18
18
|
return (distance_in_minutes==0) ? 'меньше минуты' : '1 минуту' unless include_seconds
|
19
19
|
|
20
20
|
case distance_in_seconds
|
21
|
-
when 0..5 then 'менее
|
22
|
-
when 6..10 then 'менее
|
23
|
-
when 11..20 then 'менее
|
21
|
+
when 0..5 then 'менее 5 секунд'
|
22
|
+
when 6..10 then 'менее 10 секунд'
|
23
|
+
when 11..20 then 'менее 20 секунд'
|
24
24
|
when 21..40 then 'пол-минуты'
|
25
25
|
when 41..59 then 'меньше минуты'
|
26
26
|
else '1 минуту'
|
27
27
|
end
|
28
28
|
|
29
|
-
when 2..45 then distance_in_minutes.
|
29
|
+
when 2..45 then distance_in_minutes.to_s +
|
30
|
+
" " + distance_in_minutes.items("минута", "минуты", "минут")
|
30
31
|
when 46..90 then 'около часа'
|
31
|
-
|
32
|
+
# исключение, сдвигаем на один влево чтобы соответствовать падежу
|
33
|
+
when 90..1440 then "около " + (distance_in_minutes.to_f / 60.0).round.to_s +
|
34
|
+
" " + (distance_in_minutes.to_f / 60.0).round.items("часа", "часов", nil)
|
32
35
|
when 1441..2880 then '1 день'
|
33
|
-
else (distance_in_minutes / 1440).round.
|
36
|
+
else (distance_in_minutes / 1440).round.to_s +
|
37
|
+
" " + (distance_in_minutes / 1440).round.items("день", "дня", "дней")
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
data/lib/gilenson/gilenson.rb
CHANGED
@@ -1,280 +1,279 @@
|
|
1
|
-
|
2
|
-
class Gilenson::New < String #:nodoc:
|
1
|
+
class RuTils::Gilenson::New < String #:nodoc:
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
3
|
+
def initialize(*args)
|
4
|
+
# Задача (вкратце) состоит в том чтобы все ступени разработки развести в отдельные методы
|
5
|
+
# и тестировать их отдельно друг от друга (а также иметь возможность их по-одному включать и выключать).
|
6
|
+
# Фильтры, которые начинаются с lift работают с блоком (например - вытащить таги, провести обработку
|
7
|
+
# текста и вернуть все назад)
|
8
|
+
|
9
|
+
# Фильтры обрабатываются именно в таком порядке. Этот массив стравнивается с настройками, и если настройки
|
10
|
+
# для конкретного фильтра установлены в false этот фильтр обработан не будет.
|
11
|
+
# Каждый фильтр должен именоваться process_{filter}, принимать аргументом текст для обработки и возвращать его же!
|
12
|
+
# После того как фильтр включен в массив order_of_filters и для него написан метод фильтр по лумолчанию включается,
|
13
|
+
# и его настройку можно поменять с помощью аксессора с соотв. именем. Это делается автоматом.
|
14
|
+
# Главный обработчик должен сам понимать, использовать ли блок (если метод-делегат начинается с lift_)
|
15
|
+
# или просто process.
|
16
|
+
|
17
|
+
# Аксессор само собой генерируется автоматом.
|
18
|
+
|
19
|
+
@@order_of_filters = [
|
20
|
+
:inches,
|
21
|
+
:dashes,
|
22
|
+
:emdashes,
|
23
|
+
:specials,
|
24
|
+
:spacing,
|
25
|
+
:dashglue,
|
26
|
+
:nonbreakables,
|
27
|
+
:plusmin,
|
28
|
+
:degrees,
|
29
|
+
:phones,
|
30
|
+
:simple_quotes,
|
31
|
+
:typographer_quotes,
|
32
|
+
:compound_quotes,
|
33
|
+
]
|
34
|
+
|
35
|
+
# Символы, используемые в подстановках. Меняются через substitute_set(subst_name, subst_content)
|
36
|
+
# Нужно потому как ващето недопустим в XML, равно как и всякие mdash.
|
37
|
+
@@spec_chars = {
|
38
|
+
:laquo=>'«', #left acute
|
39
|
+
:raquo=>'»', #right acute
|
40
|
+
:ndash=>'–', #en dash
|
41
|
+
:mdash=>'—', #en dash
|
42
|
+
:inch=>'"', #en dash
|
43
|
+
:nbsp=>' ', #non-breakable
|
44
|
+
}
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
46
|
+
@@phonemasks = [[ /([0-9]{4})\-([0-9]{2})\-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/,
|
47
|
+
/([0-9]{4})\-([0-9]{2})\-([0-9]{2})/,
|
48
|
+
/(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
|
49
|
+
/(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
|
50
|
+
/(\([0-9\+\-]+\)) ?([0-9]{3})\-([0-9]{2})/,
|
51
|
+
/(\([0-9\+\-]+\)) ?([0-9]{2})\-([0-9]{3})/,
|
52
|
+
/([0-9]{3})\-([0-9]{2})\-([0-9]{2})/,
|
53
|
+
/([0-9]{2})\-([0-9]{2})\-([0-9]{2})/,
|
54
|
+
/([0-9]{1})\-([0-9]{2})\-([0-9]{2})/,
|
55
|
+
/([0-9]{2})\-([0-9]{3})/,
|
56
|
+
/([0-9]+)\-([0-9]+)/,
|
57
|
+
],[
|
58
|
+
'<nobr>\1–\2–\3 \4:\5:\6</nobr>',
|
59
|
+
'<nobr>\1–\2–\3</nobr>',
|
60
|
+
'<nobr>\1 \2–\3–\4</nobr>',
|
61
|
+
'<nobr>\1 \2–\3–\4</nobr>',
|
62
|
+
'<nobr>\1 \2–\3</nobr>',
|
63
|
+
'<nobr>\1 \2–\3</nobr>',
|
64
|
+
'<nobr>\1–\2–\3</nobr>',
|
65
|
+
'<nobr>\1–\2–\3</nobr>',
|
66
|
+
'<nobr>\1–\2–\3</nobr>',
|
67
|
+
'<nobr>\1–\2</nobr>',
|
68
|
+
'<nobr>\1–\2</nobr>'
|
69
|
+
]]
|
70
|
+
|
71
|
+
@@glueleft = ['рис.', 'табл.', 'см.', 'им.', 'ул.', 'пер.', 'кв.', 'офис', 'оф.', 'г.']
|
72
|
+
@@glueright = ['руб.', 'коп.', 'у.е.', 'мин.']
|
73
73
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
74
|
+
@@settings = {
|
75
|
+
"inches" => true, # преобразовывать дюймы в "
|
76
|
+
"laquo" => true, # кавычки-ёлочки
|
77
|
+
"farlaquo" => false, # кавычки-ёлочки для фара (знаки "больше-меньше")
|
78
|
+
"quotes" => true, # кавычки-английские лапки
|
79
|
+
"dash" => true, # короткое тире (150)
|
80
|
+
"emdash" => true, # длинное тире двумя минусами (151)
|
81
|
+
"(c)" => true,
|
82
|
+
"(r)" => true,
|
83
|
+
"(tm)" => true,
|
84
|
+
"(p)" => true,
|
85
|
+
"+-" => true, # спецсимволы, какие - понятно
|
86
|
+
"degrees" => true, # знак градуса
|
87
|
+
"<-->" => true, # отступы $Indent*
|
88
|
+
"dashglue" => true, "wordglue" => true, # приклеивание предлогов и дефисов
|
89
|
+
"spacing" => true, # запятые и пробелы, перестановка
|
90
|
+
"phones" => true, # обработка телефонов
|
91
|
+
"fixed" => false, # подгон под фиксированную ширину
|
92
|
+
"html" => false # запрет тагов html
|
93
|
+
}
|
94
|
+
# irrelevant - indentation with images
|
95
|
+
@@indent_a = "<!--indent-->"
|
96
|
+
@@indent_b = "<!--indent-->"
|
97
|
+
|
98
|
+
@@mark_tag = "\xF0\xF0\xF0\xF0" # Подстановочные маркеры тегов - BOM
|
99
|
+
@@mark_ignored = "\xFF\xFF\xFF\xFF" # Подстановочные маркеры неизменяемых групп - BOM+ =)
|
100
|
+
|
101
|
+
@@ignore = /notypo/ # regex, который игнорируется. Этим надо воспользоваться для обработки pre и code
|
102
102
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
103
|
+
self.methods.each do | m |
|
104
|
+
next unless m.include?("process_")
|
105
|
+
raise NoMethodError, "No hook for " + m unless @@order_of_filters.include?(m.gsub(/process_/, '').to_sym)
|
106
|
+
end
|
107
|
+
|
108
|
+
@@order_of_filters.each do |filter|
|
109
|
+
raise NoMethodError, "No process method for " + filter unless self.methods.include?("process_#{filter}".to_sym)
|
110
|
+
end
|
111
111
|
|
112
|
-
|
112
|
+
super(*args)
|
113
113
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
def to_html(*opts)
|
118
|
-
text = self.to_s.clone
|
119
|
-
lift_tags(text) do | text |
|
120
|
-
# lift_ignored(text) do |text|
|
121
|
-
for filter in @@order_of_filters
|
122
|
-
raise "UnknownFilter #process_#{filter} in filterlist!" unless self.respond_to?("process_#{filter}".to_sym)
|
123
|
-
self.send("process_#{filter}".to_sym, text) # if @settings[filter.to_sym] # вызываем конкретный фильтр
|
124
|
-
end
|
125
|
-
# end
|
126
|
-
end
|
127
|
-
text
|
128
|
-
end
|
129
|
-
|
130
|
-
# Вытаскивает теги из текста, выполняет переданный блок и возвращает теги на место.
|
131
|
-
# Теги в процессе заменяются на специальный маркер
|
132
|
-
def lift_tags(text, marker="\xF0\xF0\xF0\xF0", &block)
|
133
|
-
|
134
|
-
# Выцепляем таги
|
135
|
-
# re = /<\/?[a-z0-9]+("+ # имя тага
|
136
|
-
# "\s+("+ # повторяющая конструкция: хотя бы один разделитель и тельце
|
137
|
-
# "[a-z]+("+ # атрибут из букв, за которым может стоять знак равенства и потом
|
138
|
-
# "=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+))"+ #
|
139
|
-
# ")?"+
|
140
|
-
# ")?"+
|
141
|
-
# ")*\/?>|\xA2\xA2[^\n]*?==/i;
|
114
|
+
end
|
142
115
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
116
|
+
|
117
|
+
def to_html(*opts)
|
118
|
+
text = self.to_s.clone
|
119
|
+
lift_tags(text) do | text |
|
120
|
+
# lift_ignored(text) do |text|
|
121
|
+
for filter in @@order_of_filters
|
122
|
+
raise "UnknownFilter #process_#{filter} in filterlist!" unless self.respond_to?("process_#{filter}".to_sym)
|
123
|
+
self.send("process_#{filter}".to_sym, text) # if @settings[filter.to_sym] # вызываем конкретный фильтр
|
124
|
+
end
|
125
|
+
# end
|
126
|
+
end
|
127
|
+
text
|
128
|
+
end
|
129
|
+
|
130
|
+
# Вытаскивает теги из текста, выполняет переданный блок и возвращает теги на место.
|
131
|
+
# Теги в процессе заменяются на специальный маркер
|
132
|
+
def lift_tags(text, marker="\xF0\xF0\xF0\xF0", &block)
|
133
|
+
|
134
|
+
# Выцепляем таги
|
135
|
+
# re = /<\/?[a-z0-9]+("+ # имя тага
|
136
|
+
# "\s+("+ # повторяющая конструкция: хотя бы один разделитель и тельце
|
137
|
+
# "[a-z]+("+ # атрибут из букв, за которым может стоять знак равенства и потом
|
138
|
+
# "=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+))"+ #
|
139
|
+
# ")?"+
|
140
|
+
# ")?"+
|
141
|
+
# ")*\/?>|\xA2\xA2[^\n]*?==/i;
|
151
142
|
|
152
|
-
|
143
|
+
re = /(<\/?[a-z0-9]+(\s+([a-z]+(=((\'[^\']*\')|(\"[^\"]*\")|([0-9@\-_a-z:\/?&=\.]+)))?)?)*\/?>)/ui
|
144
|
+
|
145
|
+
tags = text.scan(re).inject([]) { | ar, match | ar << match[0] }
|
146
|
+
text.gsub!(re, "\xF0\xF0\xF0\xF0") #маркер тега
|
147
|
+
|
148
|
+
yield(text, marker) if block_given? #делаем все что надо сделать без тегов
|
149
|
+
|
150
|
+
tags.each { | tag | text.sub!(marker, tag) } # Вставляем таги обратно.
|
153
151
|
|
154
|
-
|
155
|
-
# без этих символов а затем вставляет их на место
|
156
|
-
def lift_ignored(text, marker = "\xFF\xFF\xFF\xFF", &block)
|
157
|
-
ignored = text.scan(@ignore)
|
158
|
-
text.gsub!(@ignore, marker)
|
159
|
-
|
160
|
-
# обрабатываем текст
|
161
|
-
yield(text, marker) if block_given?
|
162
|
-
|
163
|
-
# возвращаем игнорированные символы
|
164
|
-
ignored.each { | tag | text.sub!(marker, tag) }
|
165
|
-
end
|
152
|
+
end
|
166
153
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
# Кавычки - елочки
|
181
|
-
def process_typographer_quotes(text)
|
182
|
-
# 2. ёлочки
|
183
|
-
text.gsub!( /\"\"/ui, """");
|
184
|
-
text.gsub!( /(^|\s|\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|>|\()\"((\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1«\\2");
|
185
|
-
# nb: wacko only regexp follows:
|
186
|
-
text.gsub!( /(^|\s|\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|>|\()\"((\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|\/ |\/|\!)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1«\\2")
|
187
|
-
_text = "\"\"";
|
188
|
-
while (_text != text) do
|
189
|
-
_text = text;
|
190
|
-
text.gsub!( /(\«\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1»")
|
191
|
-
# nb: wacko only regexps follows:
|
192
|
-
text.gsub!( /(\«\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*\?(\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1»")
|
193
|
-
text.gsub!( /(\«\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|\/|\!)*)\"/sui, "\\1»")
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
# Cложные кавычки
|
198
|
-
def process_compound_quotes(text)
|
199
|
-
text.gsub!(/(\&\#147\;(([A-Za-z0-9'!\.?,\-&;:]|\s|\xF0\xF0\xF0\xF0|\xFF\xFF\xFF\xFF)*)«(.*)»)»/ui,"\\1”");
|
200
|
-
end
|
154
|
+
# Выцепляет игнорированные символы, выполняет блок с текстом
|
155
|
+
# без этих символов а затем вставляет их на место
|
156
|
+
def lift_ignored(text, marker = "\xFF\xFF\xFF\xFF", &block)
|
157
|
+
ignored = text.scan(@ignore)
|
158
|
+
text.gsub!(@ignore, marker)
|
159
|
+
|
160
|
+
# обрабатываем текст
|
161
|
+
yield(text, marker) if block_given?
|
162
|
+
|
163
|
+
# возвращаем игнорированные символы
|
164
|
+
ignored.each { | tag | text.sub!(marker, tag) }
|
165
|
+
end
|
201
166
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
167
|
+
# Кавычки - лапки
|
168
|
+
def process_simple_quotes(text)
|
169
|
+
text.gsub!( /\"\"/ui, """")
|
170
|
+
text.gsub!( /\"\.\"/ui, ""."")
|
171
|
+
_text = '""';
|
172
|
+
while _text != text do
|
173
|
+
_text = text
|
174
|
+
text.gsub!( /(^|\s|\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|>)\"([0-9A-Za-z\'\!\s\.\?\,\-\&\;\:\_\xF0\xF0\xF0\xF0\xFF\xFF\xFF\xFF]+(\"|”))/ui, '\1“\2')
|
175
|
+
#this doesnt work in-place. somehow.
|
176
|
+
text.replace text.gsub( /(\&\#147\;([A-Za-z0-9\'\!\s\.\?\,\-\&\;\:\xF0\xF0\xF0\xF0\xFF\xFF\xFF\xFF\_]*).*[A-Za-z0-9][\xF0\xF0\xF0\xF0\xFF\xFF\xFF\xFF\?\.\!\,]*)\"/ui, '\1”')
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Кавычки - елочки
|
181
|
+
def process_typographer_quotes(text)
|
182
|
+
# 2. ёлочки
|
183
|
+
text.gsub!( /\"\"/ui, """");
|
184
|
+
text.gsub!( /(^|\s|\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|>|\()\"((\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1«\\2");
|
185
|
+
# nb: wacko only regexp follows:
|
186
|
+
text.gsub!( /(^|\s|\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|>|\()\"((\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|\/ |\/|\!)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1«\\2")
|
187
|
+
_text = "\"\"";
|
188
|
+
while (_text != text) do
|
189
|
+
_text = text;
|
190
|
+
text.gsub!( /(\«\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1»")
|
191
|
+
# nb: wacko only regexps follows:
|
192
|
+
text.gsub!( /(\«\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*\?(\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1»")
|
193
|
+
text.gsub!( /(\«\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|\/|\!)*)\"/sui, "\\1»")
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Cложные кавычки
|
198
|
+
def process_compound_quotes(text)
|
199
|
+
text.gsub!(/(\&\#147\;(([A-Za-z0-9'!\.?,\-&;:]|\s|\xF0\xF0\xF0\xF0|\xFF\xFF\xFF\xFF)*)«(.*)»)»/ui,"\\1”");
|
200
|
+
end
|
211
201
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
202
|
+
# Обрабатывает короткое тире
|
203
|
+
def process_dashes(text)
|
204
|
+
text.gsub!( /(\s|;)\-(\s)/ui, "\\1–\\2")
|
205
|
+
end
|
206
|
+
|
207
|
+
# Обрабатывает длинные тире
|
208
|
+
def process_emdashes(text)
|
209
|
+
text.gsub!( /(\s|;)\-\-(\s)/ui, "\\1—\\2")
|
210
|
+
end
|
218
211
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
# Склейка дефисоов
|
226
|
-
def process_dashglue(text)
|
227
|
-
text.gsub!( /([a-zа-яА-Я0-9]+(\-[a-zа-яА-Я0-9]+)+)/ui, '<nobr>\1</nobr>')
|
228
|
-
end
|
229
|
-
|
230
|
-
# Запятые и пробелы
|
231
|
-
def process_spacing(text)
|
232
|
-
text.gsub!( /(\s*)([,]*)/sui, "\\2\\1");
|
233
|
-
text.gsub!( /(\s*)([\.?!]*)(\s*[ЁА-ЯA-Z])/su, "\\2\\1\\3");
|
234
|
-
end
|
235
|
-
|
236
|
-
# Неразрывные пробелы - пока глючит страшным образом
|
237
|
-
def process_nonbreakables(text)
|
238
|
-
text.replace " " + text + " ";
|
239
|
-
_text = " " + text + " ";
|
240
|
-
until _text == text
|
241
|
-
_text.replace text.clone
|
242
|
-
text.gsub!( /(\s+)([a-zа-яА-Я]{1,2})(\s+)([^\\s$])/ui, '\1\2 \4')
|
243
|
-
text.gsub!( /(\s+)([a-zа-яА-Я]{3})(\s+)([^\\s$])/ui, '\1\2 \4')
|
244
|
-
end
|
245
|
-
|
246
|
-
for i in @glueleft
|
247
|
-
text.gsub!( /(\s)(#{i})(\s+)/sui, '\1\2 ')
|
248
|
-
end
|
212
|
+
# Обрабатывает знаки копирайта, торговой марки и т.д.
|
213
|
+
def process_specials(text)
|
214
|
+
# 4. (с)
|
215
|
+
text.gsub!(/\([сСcC]\)((?=\w)|(?=\s[0-9]+))/u, "©")
|
216
|
+
# 4a. (r)
|
217
|
+
text.gsub!( /\(r\)/ui, "<sup>®</sup>")
|
249
218
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
219
|
+
# 4b. (tm)
|
220
|
+
text.gsub!( /\(tm\)|\(тм\)/ui, "™")
|
221
|
+
# 4c. (p)
|
222
|
+
text.gsub!( /\(p\)/ui, "§")
|
223
|
+
end
|
224
|
+
|
225
|
+
# Склейка дефисоов
|
226
|
+
def process_dashglue(text)
|
227
|
+
text.gsub!( /([a-zа-яА-Я0-9]+(\-[a-zа-яА-Я0-9]+)+)/ui, '<nobr>\1</nobr>')
|
228
|
+
end
|
229
|
+
|
230
|
+
# Запятые и пробелы
|
231
|
+
def process_spacing(text)
|
232
|
+
text.gsub!( /(\s*)([,]*)/sui, "\\2\\1");
|
233
|
+
text.gsub!( /(\s*)([\.?!]*)(\s*[ЁА-ЯA-Z])/su, "\\2\\1\\3");
|
234
|
+
end
|
235
|
+
|
236
|
+
# Неразрывные пробелы - пока глючит страшным образом
|
237
|
+
def process_nonbreakables(text)
|
238
|
+
text.replace " " + text + " ";
|
239
|
+
_text = " " + text + " ";
|
240
|
+
until _text == text
|
241
|
+
_text.replace text.clone
|
242
|
+
text.gsub!( /(\s+)([a-zа-яА-Я]{1,2})(\s+)([^\\s$])/ui, '\1\2 \4')
|
243
|
+
text.gsub!( /(\s+)([a-zа-яА-Я]{3})(\s+)([^\\s$])/ui, '\1\2 \4')
|
244
|
+
end
|
255
245
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
246
|
+
for i in @glueleft
|
247
|
+
text.gsub!( /(\s)(#{i})(\s+)/sui, '\1\2 ')
|
248
|
+
end
|
249
|
+
|
250
|
+
for i in @glueright
|
251
|
+
text.gsub!( /(\s)(#{i})(\s+)/sui, ' \2\3')
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
# Знак дюйма
|
257
|
+
def process_inches(text)
|
258
|
+
text.gsub!(/\s([0-9]{1,2}([\.,][0-9]{1,2})?)\"/ui, ' \1"') if @settings["inches"]
|
259
|
+
end
|
260
|
+
|
261
|
+
# Обрабатывает знак +/-
|
262
|
+
def process_plusmin(text)
|
263
|
+
text.gsub!(/\+\-/ui, "±") if @settings["+-"]
|
264
|
+
end
|
265
|
+
|
266
|
+
# Обрабатывает телефоны
|
267
|
+
def process_phones(text)
|
268
|
+
@phonemasks[0].each_with_index do |regex, i|
|
269
|
+
text.gsub!(regex, @phonemasks[1][i])
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# Обрабатывает знак градуса, набранный как caret
|
274
|
+
def process_degrees(text)
|
275
|
+
text.gsub!( /-([0-9])+\^([FCС])/, '–\1°\2')
|
276
|
+
text.gsub!( /\+([0-9])+\^([FCС])/, "+\\1°\\2")
|
277
|
+
text.gsub!( /\^([FCС])/, "°\\1")
|
278
|
+
end
|
280
279
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
if defined?(BlueCloth)
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
class BlueCloth < String #:nodoc:
|
3
|
+
alias_method :old_to_html, :to_html
|
4
|
+
def to_html(*opts)
|
5
|
+
RuTils::overrides_enabled? ? RuTils::Gilenson::Formatter.new(old_to_html(*opts)).to_html : old_to_html(*opts)
|
6
|
+
end
|
7
|
+
end
|
8
8
|
end
|
@@ -1,7 +1,3 @@
|
|
1
|
-
load File.dirname(__FILE__) + '/blue_cloth_override.rb'
|
2
|
-
load File.dirname(__FILE__) + '/red_cloth_override.rb'
|
3
|
-
load File.dirname(__FILE__) + '/rails_date_helper_override.rb'
|
4
|
-
|
5
1
|
module RuTils
|
6
2
|
@@overrides = true
|
7
3
|
|
@@ -22,3 +18,7 @@ module RuTils
|
|
22
18
|
@@overrides = (new_override_flag ? true : false)
|
23
19
|
end
|
24
20
|
end
|
21
|
+
|
22
|
+
load File.dirname(__FILE__) + '/blue_cloth_override.rb'
|
23
|
+
load File.dirname(__FILE__) + '/red_cloth_override.rb'
|
24
|
+
load File.dirname(__FILE__) + '/rails_date_helper_override.rb'
|
@@ -1,7 +1,7 @@
|
|
1
|
-
if defined?(ActionView
|
1
|
+
if defined?(ActionView)
|
2
2
|
module ActionView #:nodoc:
|
3
|
-
module Helpers
|
4
|
-
module DateHelper
|
3
|
+
module Helpers
|
4
|
+
module DateHelper
|
5
5
|
|
6
6
|
# Reports the approximate distance in time between two Time objects or integers.
|
7
7
|
# For example, if the distance is 47 minutes, it'll return
|
@@ -12,7 +12,7 @@ if defined?(ActionView``)
|
|
12
12
|
#
|
13
13
|
# Set <tt>include_seconds</tt> to true if you want more detailed approximations if distance < 1 minute
|
14
14
|
|
15
|
-
alias :
|
15
|
+
alias :stock_distance_of_time_in_words :distance_of_time_in_words
|
16
16
|
def distance_of_time_in_words(*args)
|
17
17
|
RuTils::overrides_enabled? ? RuTils::DateTime::distance_of_time_in_words(*args) : stock_distance_of_time_in_words
|
18
18
|
end
|
@@ -1,18 +1,17 @@
|
|
1
1
|
if defined?(RedCloth)
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
2
|
+
# RuTils выполняет перегрузку Textile Glyphs в RedCloth, перенося форматирование спецсимволов на Gilenson.
|
3
|
+
class RedCloth < String #:nodoc:
|
4
|
+
# Этот метод в RedCloth эскейпит слишком много HTML, нам ничего не оставляет :-)
|
5
|
+
alias_method :stock_htmlesc, :htmlesc
|
6
|
+
def htmlesc(text, mode=0) #:nodoc:
|
7
|
+
RuTils::overrides_enabled? ? text : stock_htmlesc(text, mode)
|
8
|
+
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
# А этот метод обрабатывает Textile Glyphs - ту самую типографицу.
|
11
|
+
# Вместо того чтобы влезать в таблицы мы просто заменим Textile Glyphs - и все будут рады.
|
12
|
+
alias_method :stock_pgl, :pgl
|
13
|
+
def pgl(text) #:nodoc:
|
14
14
|
RuTils::overrides_enabled? ? text.replace(RuTils::Gilenson::Formatter.new(text).to_html) : stock_pgl(text)
|
15
|
-
|
16
|
-
|
17
|
-
end
|
15
|
+
end
|
16
|
+
end
|
18
17
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module RuTils
|
2
|
-
module Pluralization
|
2
|
+
module Pluralization #:nodoc:
|
3
3
|
# Выбирает нужный падеж существительного в зависимости от числа
|
4
4
|
def self.choose_plural(amount, *variants)
|
5
5
|
variant = (amount%10==1 && amount%100!=11 ? 1 : amount%10>=2 && amount%10<=4 && (amount%100<10 || amount%100>=20) ? 2 : 3)
|
@@ -134,7 +134,7 @@ module RuTils
|
|
134
134
|
end
|
135
135
|
|
136
136
|
# сборка строки
|
137
|
-
return [(hundreds + tens + ones + end_word + " " + into).strip, tmp_val]
|
137
|
+
return [(hundreds.to_s + tens.to_s + ones.to_s + end_word.to_s + " " + into.to_s).strip, tmp_val]
|
138
138
|
end
|
139
139
|
|
140
140
|
# Реализует вывод прописью любого объекта, реализующего Float
|
@@ -174,6 +174,15 @@ module RuTils
|
|
174
174
|
suf1, suf2, suf3 = it[signs][0], it[signs][1], it[signs][2]
|
175
175
|
st + " " + RuTils::Pluralization::sum_string(rmdr.to_i, 2, suf1, suf2, suf2)
|
176
176
|
end
|
177
|
+
|
178
|
+
def propisju_items(gender=1, *forms)
|
179
|
+
if self == self.to_i
|
180
|
+
return self.to_i.propisju_items(gender, *forms)
|
181
|
+
else
|
182
|
+
self.propisju(gender) + " " + forms[1]
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
177
186
|
end
|
178
187
|
|
179
188
|
# Реализует вывод прописью любого объекта, реализующего Numeric
|
@@ -186,7 +195,7 @@ module RuTils
|
|
186
195
|
end
|
187
196
|
|
188
197
|
def propisju_items(gender=1, *forms)
|
189
|
-
|
198
|
+
self.propisju(gender) + " " + RuTils::Pluralization::choose_plural(self.to_i, *forms)
|
190
199
|
end
|
191
200
|
|
192
201
|
# Выбирает корректный вариант числительного в зависимости от рода и числа. Например:
|
data/lib/rutils.rb
CHANGED
data/test/t_datetime.rb
CHANGED
@@ -5,6 +5,7 @@ require File.dirname(__FILE__) + '/../lib/rutils'
|
|
5
5
|
class DistanceOfTimeTest < Test::Unit::TestCase
|
6
6
|
def test_distance_of_time_in_words
|
7
7
|
assert_equal "меньше минуты", RuTils::DateTime::distance_of_time_in_words(0, 50)
|
8
|
-
assert_equal "
|
8
|
+
assert_equal "2 минуты", RuTils::DateTime::distance_of_time_in_words(0, 140)
|
9
|
+
assert_equal "около 2 часов", RuTils::DateTime::distance_of_time_in_words(0, 60*114)
|
9
10
|
end
|
10
11
|
end
|
data/test/t_pluralize.rb
CHANGED
@@ -14,7 +14,7 @@ class PropisjuTestCase < Test::Unit::TestCase
|
|
14
14
|
assert_equal "пять", 5.propisju
|
15
15
|
assert_equal "шестьсот двенадцать", 612.propisju
|
16
16
|
assert_equal "двадцать пять колес", 25.propisju_items(3, "колесо", "колеса", "колес")
|
17
|
-
assert_equal "двадцать одна подстава", 21.propisju_items(2, "подстава", "подставы", "подстав")
|
17
|
+
assert_equal "двадцать одна подстава", 21.propisju_items(2, "подстава", "подставы", "подстав")
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_floats
|
@@ -23,6 +23,8 @@ class PropisjuTestCase < Test::Unit::TestCase
|
|
23
23
|
assert_equal "триста сорок одна целая двести сорок пять тысячных", (341.245).propisju
|
24
24
|
assert_equal "двести три целых сорок одна сотая", (203.41).propisju
|
25
25
|
assert_equal "четыреста сорок две целых пять десятых", (442.50000).propisju
|
26
|
+
assert_equal "двести двенадцать целых четыре десятых сволочи", (212.40).propisju_items(2, "сволочь", "сволочи", "сволочей")
|
27
|
+
assert_equal "двести двенадцать сволочей", (212.00).propisju_items(2, "сволочь", "сволочи", "сволочей")
|
26
28
|
end
|
27
29
|
|
28
30
|
def test_items
|
@@ -30,7 +32,7 @@ class PropisjuTestCase < Test::Unit::TestCase
|
|
30
32
|
assert_equal "партий", 6727.items("партия", "партии", "партий")
|
31
33
|
assert_equal "козлов", 45.items("козел", "козла", "козлов")
|
32
34
|
assert_equal "колес", 260.items("колесо", "колеса", "колес")
|
33
|
-
end
|
35
|
+
end
|
34
36
|
end
|
35
37
|
|
36
38
|
#class PluralizeTestCase < Test::Unit::TestCase
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: rutils
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0
|
7
|
-
date: 2005-10-
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2005-10-23 00:00:00 +02:00
|
8
8
|
summary: Simple processing of russian strings
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -62,6 +62,7 @@ rdoc_options:
|
|
62
62
|
- "--main=README"
|
63
63
|
- "--line-numbers"
|
64
64
|
- "--charset=utf-8"
|
65
|
+
- "--promiscuous"
|
65
66
|
extra_rdoc_files:
|
66
67
|
- README
|
67
68
|
- TODO
|