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 CHANGED
@@ -12,7 +12,7 @@ Gilenson работает медленнее).
12
12
 
13
13
  Это версия RuTils
14
14
 
15
- $Revision: 1.6 $
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. Когда перегрузка выключена, все сторонние библиотеки будут работать
@@ -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 'менее чем 5 секунд'
22
- when 6..10 then 'менее чем 10 секунд'
23
- when 11..20 then 'менее чем 20 секунд'
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.propisju_items(2, "минута", "минуты", "минут")
29
+ when 2..45 then distance_in_minutes.to_s +
30
+ " " + distance_in_minutes.items("минута", "минуты", "минут")
30
31
  when 46..90 then 'около часа'
31
- when 90..1440 then "около " + (distance_in_minutes.to_f / 60.0).round.items("час", "часа", "часов")
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.items("день", "дня", "дней")
36
+ else (distance_in_minutes / 1440).round.to_s +
37
+ " " + (distance_in_minutes / 1440).round.items("день", "дня", "дней")
34
38
  end
35
39
  end
36
40
 
@@ -1,280 +1,279 @@
1
- module RuTils
2
- class Gilenson::New < String #:nodoc:
1
+ class RuTils::Gilenson::New < String #:nodoc:
3
2
 
4
- def initialize(*args)
5
- # Задача (вкратце) состоит в том чтобы все ступени разработки развести в отдельные методы
6
- # и тестировать их отдельно друг от друга (а также иметь возможность их по-одному включать и выключать).
7
- # Фильтры, которые начинаются с lift работают с блоком (например - вытащить таги, провести обработку
8
- # текста и вернуть все назад)
9
-
10
- # Фильтры обрабатываются именно в таком порядке. Этот массив стравнивается с настройками, и если настройки
11
- # для конкретного фильтра установлены в false этот фильтр обработан не будет.
12
- # Каждый фильтр должен именоваться process_{filter}, принимать аргументом текст для обработки и возвращать его же!
13
- # После того как фильтр включен в массив order_of_filters и для него написан метод фильтр по лумолчанию включается,
14
- # и его настройку можно поменять с помощью аксессора с соотв. именем. Это делается автоматом.
15
- # Главный обработчик должен сам понимать, использовать ли блок (если метод-делегат начинается с lift_)
16
- # или просто process.
17
-
18
- # Аксессор само собой генерируется автоматом.
19
-
20
- @@order_of_filters = [
21
- :inches,
22
- :dashes,
23
- :emdashes,
24
- :specials,
25
- :spacing,
26
- :dashglue,
27
- :nonbreakables,
28
- :plusmin,
29
- :degrees,
30
- :phones,
31
- :simple_quotes,
32
- :typographer_quotes,
33
- :compound_quotes,
34
- ]
35
-
36
- # Символы, используемые в подстановках. Меняются через substitute_set(subst_name, subst_content)
37
- # Нужно потому как ващето &nbsp; недопустим в XML, равно как и всякие mdash.
38
- @@spec_chars = {
39
- :laquo=>'&laquo;', #left acute
40
- :raquo=>'&raquo;', #right acute
41
- :ndash=>'&ndash;', #en dash
42
- :mdash=>'&mdash;', #en dash
43
- :inch=>'&quot;', #en dash
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
+ # Нужно потому как ващето &nbsp; недопустим в XML, равно как и всякие mdash.
37
+ @@spec_chars = {
38
+ :laquo=>'&laquo;', #left acute
39
+ :raquo=>'&raquo;', #right acute
40
+ :ndash=>'&ndash;', #en dash
41
+ :mdash=>'&mdash;', #en dash
42
+ :inch=>'&quot;', #en dash
43
+ :nbsp=>'&nbsp;', #non-breakable
44
+ }
45
45
 
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&ndash;\2&ndash;\3&nbsp;\4:\5:\6</nobr>',
59
- '<nobr>\1&ndash;\2&ndash;\3</nobr>',
60
- '<nobr>\1&nbsp;\2&ndash;\3&ndash;\4</nobr>',
61
- '<nobr>\1&nbsp;\2&ndash;\3&ndash;\4</nobr>',
62
- '<nobr>\1&nbsp;\2&ndash;\3</nobr>',
63
- '<nobr>\1&nbsp;\2&ndash;\3</nobr>',
64
- '<nobr>\1&ndash;\2&ndash;\3</nobr>',
65
- '<nobr>\1&ndash;\2&ndash;\3</nobr>',
66
- '<nobr>\1&ndash;\2&ndash;\3</nobr>',
67
- '<nobr>\1&ndash;\2</nobr>',
68
- '<nobr>\1&ndash;\2</nobr>'
69
- ]]
70
-
71
- @@glueleft = ['рис.', 'табл.', 'см.', 'им.', 'ул.', 'пер.', 'кв.', 'офис', 'оф.', 'г.']
72
- @@glueright = ['руб.', 'коп.', 'у.е.', 'мин.']
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&ndash;\2&ndash;\3&nbsp;\4:\5:\6</nobr>',
59
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
60
+ '<nobr>\1&nbsp;\2&ndash;\3&ndash;\4</nobr>',
61
+ '<nobr>\1&nbsp;\2&ndash;\3&ndash;\4</nobr>',
62
+ '<nobr>\1&nbsp;\2&ndash;\3</nobr>',
63
+ '<nobr>\1&nbsp;\2&ndash;\3</nobr>',
64
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
65
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
66
+ '<nobr>\1&ndash;\2&ndash;\3</nobr>',
67
+ '<nobr>\1&ndash;\2</nobr>',
68
+ '<nobr>\1&ndash;\2</nobr>'
69
+ ]]
70
+
71
+ @@glueleft = ['рис.', 'табл.', 'см.', 'им.', 'ул.', 'пер.', 'кв.', 'офис', 'оф.', 'г.']
72
+ @@glueright = ['руб.', 'коп.', 'у.е.', 'мин.']
73
73
 
74
- @@settings = {
75
- "inches" => true, # преобразовывать дюймы в &quot;
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
74
+ @@settings = {
75
+ "inches" => true, # преобразовывать дюймы в &quot;
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
- 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
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
- super(*args)
112
+ super(*args)
113
113
 
114
- end
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
- 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) } # Вставляем таги обратно.
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
- end
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
- def process_simple_quotes(text)
169
- text.gsub!( /\"\"/ui, "&quot;&quot;")
170
- text.gsub!( /\"\.\"/ui, "&quot;.&quot;")
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]+(\"|&#148;))/ui, '\1&#147;\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&#148;')
177
- end
178
- end
179
-
180
- # Кавычки - елочки
181
- def process_typographer_quotes(text)
182
- # 2. ёлочки
183
- text.gsub!( /\"\"/ui, "&quot;&quot;");
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&laquo;\\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|\/&nbsp;|\/|\!)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1&laquo;\\2")
187
- _text = "\"\"";
188
- while (_text != text) do
189
- _text = text;
190
- text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1&raquo;")
191
- # nb: wacko only regexps follows:
192
- text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*\?(\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1&raquo;")
193
- text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|\/|\!)*)\"/sui, "\\1&raquo;")
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)*)&laquo;(.*)&raquo;)&raquo;/ui,"\\1&#148;");
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
- def process_dashes(text)
204
- text.gsub!( /(\s|;)\-(\s)/ui, "\\1&ndash;\\2")
205
- end
206
-
207
- # Обрабатывает длинные тире
208
- def process_emdashes(text)
209
- text.gsub!( /(\s|;)\-\-(\s)/ui, "\\1&mdash;\\2")
210
- end
167
+ # Кавычки - лапки
168
+ def process_simple_quotes(text)
169
+ text.gsub!( /\"\"/ui, "&quot;&quot;")
170
+ text.gsub!( /\"\.\"/ui, "&quot;.&quot;")
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]+(\"|&#148;))/ui, '\1&#147;\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&#148;')
177
+ end
178
+ end
179
+
180
+ # Кавычки - елочки
181
+ def process_typographer_quotes(text)
182
+ # 2. ёлочки
183
+ text.gsub!( /\"\"/ui, "&quot;&quot;");
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&laquo;\\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|\/&nbsp;|\/|\!)*[~0-9ёЁA-Za-zА-Яа-я\-:\/\.])/ui, "\\1&laquo;\\2")
187
+ _text = "\"\"";
188
+ while (_text != text) do
189
+ _text = text;
190
+ text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1&raquo;")
191
+ # nb: wacko only regexps follows:
192
+ text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*\?(\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0)*)\"/sui, "\\1&raquo;")
193
+ text.gsub!( /(\&laquo\;([^\"]*)[ёЁA-Za-zА-Яа-я0-9\.\-:\/](\xFF\xFF\xFF\xFF|\xF0\xF0\xF0\xF0|\/|\!)*)\"/sui, "\\1&raquo;")
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)*)&laquo;(.*)&raquo;)&raquo;/ui,"\\1&#148;");
200
+ end
211
201
 
212
- # Обрабатывает знаки копирайта, торговой марки и т.д.
213
- def process_specials(text)
214
- # 4. (с)
215
- text.gsub!(/\([сСcC]\)((?=\w)|(?=\s[0-9]+))/u, "&copy;")
216
- # 4a. (r)
217
- text.gsub!( /\(r\)/ui, "<sup>&#174;</sup>")
202
+ # Обрабатывает короткое тире
203
+ def process_dashes(text)
204
+ text.gsub!( /(\s|;)\-(\s)/ui, "\\1&ndash;\\2")
205
+ end
206
+
207
+ # Обрабатывает длинные тире
208
+ def process_emdashes(text)
209
+ text.gsub!( /(\s|;)\-\-(\s)/ui, "\\1&mdash;\\2")
210
+ end
218
211
 
219
- # 4b. (tm)
220
- text.gsub!( /\(tm\)|\(тм\)/ui, "&#153;")
221
- # 4c. (p)
222
- text.gsub!( /\(p\)/ui, "&#167;")
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&nbsp;\4')
243
- text.gsub!( /(\s+)([a-zа-яА-Я]{3})(\s+)([^\\s$])/ui, '\1\2&nbsp;\4')
244
- end
245
-
246
- for i in @glueleft
247
- text.gsub!( /(\s)(#{i})(\s+)/sui, '\1\2&nbsp;')
248
- end
212
+ # Обрабатывает знаки копирайта, торговой марки и т.д.
213
+ def process_specials(text)
214
+ # 4. (с)
215
+ text.gsub!(/\([сСcC]\)((?=\w)|(?=\s[0-9]+))/u, "&copy;")
216
+ # 4a. (r)
217
+ text.gsub!( /\(r\)/ui, "<sup>&#174;</sup>")
249
218
 
250
- for i in @glueright
251
- text.gsub!( /(\s)(#{i})(\s+)/sui, '&nbsp;\2\3')
252
- end
253
-
254
- end
219
+ # 4b. (tm)
220
+ text.gsub!( /\(tm\)|\(тм\)/ui, "&#153;")
221
+ # 4c. (p)
222
+ text.gsub!( /\(p\)/ui, "&#167;")
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&nbsp;\4')
243
+ text.gsub!( /(\s+)([a-zа-яА-Я]{3})(\s+)([^\\s$])/ui, '\1\2&nbsp;\4')
244
+ end
255
245
 
256
- # Знак дюйма
257
- def process_inches(text)
258
- text.gsub!(/\s([0-9]{1,2}([\.,][0-9]{1,2})?)\"/ui, ' \1&quot;') if @settings["inches"]
259
- end
260
-
261
- # Обрабатывает знак +/-
262
- def process_plusmin(text)
263
- text.gsub!(/\+\-/ui, "&#177;") 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С])/, '&ndash;\1&#176\2')
276
- text.gsub!( /\+([0-9])+\^([FCС])/, "+\\1&#176\\2")
277
- text.gsub!( /\^([FCС])/, "&#176\\1")
278
- end
279
- end
246
+ for i in @glueleft
247
+ text.gsub!( /(\s)(#{i})(\s+)/sui, '\1\2&nbsp;')
248
+ end
249
+
250
+ for i in @glueright
251
+ text.gsub!( /(\s)(#{i})(\s+)/sui, '&nbsp;\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&quot;') if @settings["inches"]
259
+ end
260
+
261
+ # Обрабатывает знак +/-
262
+ def process_plusmin(text)
263
+ text.gsub!(/\+\-/ui, "&#177;") 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С])/, '&ndash;\1&#176\2')
276
+ text.gsub!( /\+([0-9])+\^([FCС])/, "+\\1&#176\\2")
277
+ text.gsub!( /\^([FCС])/, "&#176\\1")
278
+ end
280
279
  end
@@ -1,8 +1,8 @@
1
1
  if defined?(BlueCloth)
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
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 #:nodoc:
4
- module DateHelper #:nodoc:
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 :distance_of_time_in_words :stock_distance_of_time_in_words
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
- # 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
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
- # А этот метод обрабатывает Textile Glyphs - ту самую типографицу.
11
- # Вместо того чтобы влезать в таблицы мы просто заменим Textile Glyphs - и все будут рады.
12
- alias_method :stock_pgl, :pgl
13
- def pgl(text) #:nodoc:
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
- #text.replace(RuTils::Gilenson.new(text).to_html)
16
- end
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
- RuTils::Pluralization::sum_string(self, gender, "") + " " + RuTils::Pluralization::choose_plural(self, *forms)
198
+ self.propisju(gender) + " " + RuTils::Pluralization::choose_plural(self.to_i, *forms)
190
199
  end
191
200
 
192
201
  # Выбирает корректный вариант числительного в зависимости от рода и числа. Например:
data/lib/rutils.rb CHANGED
@@ -3,7 +3,10 @@ require 'jcode'
3
3
 
4
4
  # Главный контейнер модуля
5
5
  module RuTils
6
- VERSION = '0.0.4'
6
+ MAJOR = 0
7
+ MINOR = 1
8
+ TINY = 0
9
+ VERSION = "#{MAJOR}.#{MINOR}.#{TINY}"
7
10
  end
8
11
 
9
12
  require File.dirname(__FILE__) + '/pluralizer/pluralizer'
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 "две минуты", RuTils::DateTime::distance_of_time_in_words(0, 140)
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.4
7
- date: 2005-10-20 00:00:00 +02:00
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