rutils 0.0.4 → 0.1.0
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/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
|