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 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