rutils 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,5 @@
1
+ Версия 0.03 - 18.10.2005
2
+ * Легкий рефакторинг и чистка документации, добавлена реализация BiDi-транслита
3
+
4
+ Версия 0.02 - 12.07.2005
5
+ * Заменен маркер подстановки тегов в Gilenson. Ранее без oniguruma из-за его применения "проглатывалась" буква "р"
data/README ADDED
@@ -0,0 +1,104 @@
1
+ == Добро пожаловать в RuTils
2
+
3
+ RuTils - простой обработчик русского текста, позволяющий использовать и обрабатывать
4
+ русский текст несколькими несложными способами. Основная цель RuTils - сделать
5
+ разработку русскоязычных приложений на Ruby (и Rails) максимально простой и приятной (в идеале - столь же
6
+ простой как и разработку оных на английском)
7
+
8
+ Весь функционал RuTils поддерживает только UTF-8 (настройка $KCODE / KanjiCode 'u'). Стандартно работа RuTils проверяется
9
+ как на стандартной версии Ruby, так и на парсере регулярных выражений Oniguruma (правда имейте в виду, что с ним
10
+ Gilenson работает медленнее).
11
+
12
+
13
+ Это версия RuTils
14
+
15
+ $Revision: 1.6 $
16
+
17
+ Пожалуйста упоминайте версию при сообщении ошибок.
18
+
19
+ Удостоверьтесь, что ваш скрипт правильно обрабатывает Unicode - то есть:
20
+
21
+ * Переменная $KCODE включена в режим 'u'
22
+ * В скрипт загружена библиотека jcode
23
+
24
+ Если вы используете RuTils для сайта под mod_ruby воспользуйтесь директивой RubyKanjiCode в своем httpd.conf.
25
+
26
+ == Cумма прописью
27
+
28
+ RuTils реализует сумму прописью для целых и дробных чисел, с дополнительным учетом рода. Например:
29
+
30
+ 4.propisju => "четыре"
31
+ 345.propisju => "триста сорок пять"
32
+ 231.propisju(2) => "двести тридцать одна"
33
+ 341.propisju_items(1, "чемодан", "чемодана", "чемоданов") => "триста сорок один чемодан"
34
+ (212.40).propisju_items(2, "сволочь", "сволочи", "сволочей") => "двести двенадцать целых четыре десятых сволочи"
35
+
36
+ Также реализуется выбор варианта числительного в зависимости от числа
37
+
38
+ 15.items("кодер", "кодера", "кодеров") => "кодеров"
39
+
40
+ == Транслит
41
+
42
+ RuTils на данный момент реализует простейший транслит "в одну сторону".
43
+
44
+ "Вот такое вот дело".translify => "Vot takoye vot delo"
45
+ "Несомненный прогресс по сравнению с PHP".dirify => "nesomnennyi-progress-po-sravneniu-s-php"
46
+
47
+ В ближайшее время будет добавлен BiDi-транслит.
48
+
49
+ == Обработка русской типографики в HTML
50
+
51
+ RuTils включает Gilenson - порт Тыпографицы[http://pixel-apes.com/typografica] от
52
+ Pixel Apes на Ruby. Тыпографица - механизм автоматической расстановки подстановок в тексте
53
+ перед его выводом в HTML, оформляющий неразрывные пробелы, типографские кавычки
54
+ и реализующая элементарные макроподстановки.
55
+
56
+ Большое спасибо Роману Иванову aka Kukutz и Николаю Яремко aka Kuso Mendokuzee за изначальную реализацию
57
+ на PHP.
58
+
59
+ Имейте в виду, что на баги в Gilenson жаловаться разработчикам Typografica не стоит -
60
+ они вас не поймут и будут правы. Поддержку Gilenson PixelApes не осуществляют.
61
+
62
+ В комплекте также есть скрипт gilensize, которым можно поточно обрабатывать Unicode-тексты в среде UNIX
63
+ пользуясь стандартным выводом
64
+
65
+ $ cat myfile.txt | gilensize > myfile.html
66
+
67
+ == Интеграция с Rails, RedCloth и BlueCloth
68
+
69
+ RuTils в первую очередь задумывался как максимально "прозрачный" механизм обработки русского текста
70
+ в контексте Rails-приложения. Если вы используете RuTils в одном приложении с RedCloth или BlueCloth,
71
+ RuTils автоматически будет обрабатывать типографику во всех текстах, пропускаемых через них. Имейте в виду, что для
72
+ корректной работы этой функции RuTils надо загружать после модулей RedCloth и BlueCloth.
73
+
74
+
75
+ В принципе если вы пользуетесь RedCloth или BlueCloth все что ими обрабатывается будет автоматически
76
+ обрабатываться и Gilenson'ом тоже. В случае с RedCloth Glienson автоматически заменяет стандартные для
77
+ Textile английские кавычки и типографские знаки на свои - русские.
78
+
79
+ Перегрузку всех функций (RedCloth, BlueCloth и компоненты Rails) можно включать и отключать в любое время
80
+ с помощью метода overrides= модуля RuTils. Когда перегрузка выключена, все сторонние библиотеки будут работать
81
+ в стандартном режиме (например, RedCloth будет расставлять английские типографские кавычки).
82
+
83
+ == Требования
84
+
85
+ * Ruby 1.8.2, немного прямых рук.
86
+ * Rake[http://rake.rubyforge.org], Rails, RedCloth и BlueCloth для выполнения тестов
87
+
88
+ == Как использовать
89
+
90
+ Просто включите rutils в свою программу как gem
91
+
92
+ require_gem 'rutils'
93
+
94
+ или как библиотеку
95
+
96
+ require 'rutils'
97
+
98
+ == Где получить помощь
99
+
100
+ На странице проекта на RubyForge[http://rubyforge.org/projects/rutils]
101
+
102
+ == Работает ли это с текстом в кодировке Windows-1251
103
+
104
+ Нет и никогда не будет.
data/TODO ADDED
@@ -0,0 +1,26 @@
1
+ =TODO
2
+
3
+ ==Gilenson
4
+
5
+ * Заменить все entities в Гиленсоне на UTF-эквиваленты (в том числе и в тестах)
6
+ (пока генерируемый им код содержит, например, raquo и nbsp - неприменимо для XML)
7
+ * Выяснить, стоит ли отрабатывать типографику в атрибутах тегов
8
+ * Полностью рефакторнуть (вынести каждую трансформацию в метод)
9
+ * чтобы тестить трансформации по одной
10
+ * чтобы применять трансформации по одной буде на то нужда
11
+
12
+ ==Pluralization
13
+
14
+ * Истинная плюрализация без передачи рода и вариантов (как в Rails)
15
+
16
+ ==Даты
17
+
18
+ * В принципе нужно обеспечить полноценное покрытие stfmt
19
+
20
+ ==Rails
21
+
22
+ * distance_of_time_in_words и тому подобные
23
+
24
+ ==Транслит
25
+
26
+ * bidi-транслит (Данил)
data/bin/gilensize ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ $KCODE = 'u'
3
+ require 'rubygems'
4
+ require_gem 'rutils'
5
+
6
+ while st = gets do
7
+ puts RuTils::Gilenson::Formatter.new(st).to_html
8
+ end
@@ -0,0 +1,61 @@
1
+ require 'date'
2
+
3
+ module RuTils
4
+ module DateTime
5
+ ABBR_MONTHNAMES = %w{ Янв Фев Мар Апр Май Июн Июл Авг Сен Окт Ноя Дек }
6
+ MONTHNAMES = %w{ Январь Февраль Март Апрель Май Июнь Июль Август Сентябрь Октябрь Ноябрь Декабрь }
7
+ def self.distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, absolute = false) #nodoc
8
+ from_time = from_time.to_time if from_time.respond_to?(:to_time)
9
+ to_time = to_time.to_time if to_time.respond_to?(:to_time)
10
+ distance_in_minutes = (((to_time - from_time).abs)/60).round
11
+ distance_in_seconds = ((to_time - from_time).abs).round
12
+
13
+ case distance_in_minutes
14
+ when 0..1
15
+ return (distance_in_minutes==0) ? 'меньше минуты' : '1 минуту' unless include_seconds
16
+
17
+ case distance_in_seconds
18
+ when 0..5 then 'менее чем 5 секунд'
19
+ when 6..10 then 'менее чем 10 секунд'
20
+ when 11..20 then 'менее чем 20 секунд'
21
+ when 21..40 then 'пол-минуты'
22
+ when 41..59 then 'меньше минуты'
23
+ else '1 минуту'
24
+ end
25
+
26
+ when 2..45 then distance_in_minutes.propisju_items(2, "минута", "минуты", "минут")
27
+ when 46..90 then 'около часа'
28
+ when 90..1440 then "около " + (distance_in_minutes.to_f / 60.0).round.items("час", "часа", "часов")
29
+ when 1441..2880 then '1 день'
30
+ else (distance_in_minutes / 1440).round.items("день", "дня", "дней")
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+
37
+ class RuTils::DateTime::RussianDate < Date
38
+ # Full month names, in English. Months count from 1 to 12; a
39
+ # month's numerical representation indexed into this array
40
+ # gives the name of that month (hence the first element is nil).
41
+ MONTHNAMES = [nil] + %w(Январь Февраль Март Апрель Май Июнь Июль
42
+ Август Сентябрь Октябрь Ноябрь Декабрь)
43
+
44
+ # Full names of days of the week, in English. Days of the week
45
+ # count from 0 to 6 (except in the commercial week); a day's numerical
46
+ # representation indexed into this array gives the name of that day.
47
+ DAYNAMES = %w(Воскресенье Понедельник Вторник Среда Четверг Пятница Суббота)
48
+
49
+ # Abbreviated month names, in English.
50
+ ABBR_MONTHNAMES = [nil] + %w(Янв Фев Мар Апр Май Июнь
51
+ Июль Авг Сен Окт Ноя Дек)
52
+ # Abbreviated day names, in English.
53
+ ABBR_DAYNAMES = %w(Вск Пн Вт Ср Чт Пт Сб)
54
+
55
+ end
56
+
57
+ class Date
58
+ def ru_strftime(*args)
59
+ RuTils::DateTime::RussianDate.new(self).strftime(*args)
60
+ end
61
+ end
@@ -0,0 +1,280 @@
1
+ module RuTils
2
+ class Gilenson < String #:nodoc:
3
+
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
+ }
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 = ['руб.', 'коп.', 'у.е.', 'мин.']
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
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
111
+
112
+ super(*args)
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;
142
+
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) } # Вставляем таги обратно.
151
+
152
+ end
153
+
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
166
+
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
201
+
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
211
+
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>")
218
+
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
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
279
+ end
280
+ end