rotuka-rutils 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +110 -0
- data/README +202 -0
- data/Rakefile.rb +128 -0
- data/TODO +11 -0
- data/bin/gilensize +18 -0
- data/bin/rutilize +38 -0
- data/init.rb +6 -0
- data/lib/countries/countries.rb +1772 -0
- data/lib/datetime/datetime.rb +87 -0
- data/lib/gilenson/gilenson.rb +642 -0
- data/lib/gilenson/gilenson_port.rb +321 -0
- data/lib/integration/blue_cloth_override.rb +12 -0
- data/lib/integration/integration.rb +32 -0
- data/lib/integration/rails_date_helper_override.rb +113 -0
- data/lib/integration/red_cloth_override.rb +27 -0
- data/lib/pluralizer/pluralizer.rb +236 -0
- data/lib/rutils.rb +32 -0
- data/lib/transliteration/bidi.rb +71 -0
- data/lib/transliteration/simple.rb +74 -0
- data/lib/transliteration/transliteration.rb +51 -0
- data/test/run_tests.rb +4 -0
- data/test/t_datetime.rb +42 -0
- data/test/t_gilenson.rb +371 -0
- data/test/t_integration.rb +125 -0
- data/test/t_pluralize.rb +69 -0
- data/test/t_rutils_base.rb +10 -0
- data/test/t_transliteration.rb +109 -0
- data/test/t_typografica.rb +57 -0
- metadata +92 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
if defined?(Object::RedCloth) && !RedCloth.instance_methods.include?(:htmlesc_without_rutils)
|
2
|
+
# RuTils выполняет перегрузку Textile Glyphs в RedCloth, перенося форматирование спецсимволов на Gilenson.
|
3
|
+
class RedCloth < String #:nodoc:
|
4
|
+
|
5
|
+
# Этот метод в RedCloth при наличии Гиленсона надо отключать
|
6
|
+
alias_method :htmlesc_without_rutils, :htmlesc
|
7
|
+
def htmlesc(text, mode=0) #:nodoc:
|
8
|
+
RuTils::overrides_enabled? ? text : htmlesc_without_rutils(text, mode)
|
9
|
+
end
|
10
|
+
|
11
|
+
# А этот метод обрабатывает Textile Glyphs - ту самую типографицу.
|
12
|
+
# Вместо того чтобы влезать в чужие таблицы мы просто заменим Textile Glyphs на Gilenson - и все будут рады.
|
13
|
+
alias_method :pgl_without_rutils, :pgl
|
14
|
+
def pgl(text) #:nodoc:
|
15
|
+
if RuTils::overrides_enabled?
|
16
|
+
# Suspend the spaces in the start and end of the block because Gilenson chews them off, and RedCloth feeds them to us in packs
|
17
|
+
# that appear between tag starts/stops. We mess up the formatting but preserve the spacing.
|
18
|
+
spaces = Array.new(2,'')
|
19
|
+
text.gsub!(/\A([\s]+)/) { spaces[0] = $1; '' }
|
20
|
+
text.gsub!(/(\s+)\Z/) { spaces[1] = $1; '' }
|
21
|
+
text.replace(spaces[0].to_s + RuTils::Gilenson::Formatter.new(text).to_html + spaces[1].to_s)
|
22
|
+
else
|
23
|
+
pgl_without_rutils(text)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
module RuTils
|
2
|
+
module Pluralization #:nodoc:
|
3
|
+
# Выбирает нужный падеж существительного в зависимости от числа
|
4
|
+
def self.choose_plural(amount, *variants)
|
5
|
+
variant = (amount%10==1 && amount%100!=11 ? 1 : amount%10>=2 && amount%10<=4 && (amount%100<10 || amount%100>=20) ? 2 : 3)
|
6
|
+
variants[variant-1]
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.rublej(amount)
|
10
|
+
pts = []
|
11
|
+
|
12
|
+
pts << RuTils::Pluralization::sum_string(amount.to_i, 1, "рубль", "рубля", "рублей") unless amount.to_i == 0
|
13
|
+
if amount.kind_of?(Float)
|
14
|
+
remainder = (amount.divmod(1)[1]*100).round
|
15
|
+
if (remainder == 100)
|
16
|
+
pts = [RuTils::Pluralization::sum_string(amount.to_i+1, 1, 'рубль', 'рубля', 'рублей')]
|
17
|
+
else
|
18
|
+
pts << RuTils::Pluralization::sum_string(remainder.to_i, 2, 'копейка', 'копейки', 'копеек')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
pts.join(' ')
|
23
|
+
end
|
24
|
+
|
25
|
+
# Выполняет преобразование числа из цифрого вида в символьное
|
26
|
+
# amount - числительное
|
27
|
+
# gender = 1 - мужской, = 2 - женский, = 3 - средний
|
28
|
+
# one_item - именительный падеж единственного числа (= 1)
|
29
|
+
# two_items - родительный падеж единственного числа (= 2-4)
|
30
|
+
# five_items - родительный падеж множественного числа ( = 5-10)
|
31
|
+
def self.sum_string(amount, gender, one_item='', two_items='', five_items='')
|
32
|
+
into = ''
|
33
|
+
tmp_val ||= 0
|
34
|
+
|
35
|
+
return "ноль " + five_items if amount == 0
|
36
|
+
|
37
|
+
tmp_val = amount
|
38
|
+
|
39
|
+
# единицы
|
40
|
+
into, tmp_val = sum_string_fn(into, tmp_val, gender, one_item, two_items, five_items)
|
41
|
+
|
42
|
+
return into if tmp_val == 0
|
43
|
+
|
44
|
+
# тысячи
|
45
|
+
into, tmp_val = sum_string_fn(into, tmp_val, 2, "тысяча", "тысячи", "тысяч")
|
46
|
+
|
47
|
+
return into if tmp_val == 0
|
48
|
+
|
49
|
+
# миллионы
|
50
|
+
into, tmp_val = sum_string_fn(into, tmp_val, 1, "миллион", "миллиона", "миллионов")
|
51
|
+
|
52
|
+
return into if tmp_val == 0
|
53
|
+
|
54
|
+
# миллиардов
|
55
|
+
into, tmp_val = sum_string_fn(into, tmp_val, 1, "миллиард", "миллиарда", "миллиардов")
|
56
|
+
return into
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def self.sum_string_fn(into, tmp_val, gender, one_item='', two_items='', five_items='')
|
61
|
+
rest, rest1, end_word, ones, tens, hundreds = [nil]*6
|
62
|
+
#
|
63
|
+
rest = tmp_val % 1000
|
64
|
+
tmp_val = tmp_val / 1000
|
65
|
+
if rest == 0
|
66
|
+
# последние три знака нулевые
|
67
|
+
into = five_items + " " if into == ""
|
68
|
+
return [into, tmp_val]
|
69
|
+
end
|
70
|
+
#
|
71
|
+
# начинаем подсчет с Rest
|
72
|
+
end_word = five_items
|
73
|
+
# сотни
|
74
|
+
hundreds = case rest / 100
|
75
|
+
when 0 then ""
|
76
|
+
when 1 then "сто "
|
77
|
+
when 2 then "двести "
|
78
|
+
when 3 then "триста "
|
79
|
+
when 4 then "четыреста "
|
80
|
+
when 5 then "пятьсот "
|
81
|
+
when 6 then "шестьсот "
|
82
|
+
when 7 then "семьсот "
|
83
|
+
when 8 then "восемьсот "
|
84
|
+
when 9 then "девятьсот "
|
85
|
+
end
|
86
|
+
|
87
|
+
# десятки
|
88
|
+
rest = rest % 100
|
89
|
+
rest1 = rest / 10
|
90
|
+
ones = ""
|
91
|
+
case rest1
|
92
|
+
when 0 then tens = ""
|
93
|
+
when 1 # особый случай
|
94
|
+
tens = case rest
|
95
|
+
when 10 then "десять "
|
96
|
+
when 11 then "одиннадцать "
|
97
|
+
when 12 then "двенадцать "
|
98
|
+
when 13 then "тринадцать "
|
99
|
+
when 14 then "четырнадцать "
|
100
|
+
when 15 then "пятнадцать "
|
101
|
+
when 16 then "шестнадцать "
|
102
|
+
when 17 then "семнадцать "
|
103
|
+
when 18 then "восемнадцать "
|
104
|
+
when 19 then "девятнадцать "
|
105
|
+
end
|
106
|
+
when 2: tens = "двадцать "
|
107
|
+
when 3: tens = "тридцать "
|
108
|
+
when 4: tens = "сорок "
|
109
|
+
when 5: tens = "пятьдесят "
|
110
|
+
when 6: tens = "шестьдесят "
|
111
|
+
when 7: tens = "семьдесят "
|
112
|
+
when 8: tens = "восемьдесят "
|
113
|
+
when 9: tens = "девяносто "
|
114
|
+
end
|
115
|
+
#
|
116
|
+
if rest1 < 1 or rest1 > 1 # единицы
|
117
|
+
case rest % 10
|
118
|
+
when 1
|
119
|
+
ones = case gender
|
120
|
+
when 1 then "один "
|
121
|
+
when 2 then "одна "
|
122
|
+
when 3 then "одно "
|
123
|
+
end
|
124
|
+
end_word = one_item
|
125
|
+
when 2
|
126
|
+
if gender == 2
|
127
|
+
ones = "две "
|
128
|
+
else
|
129
|
+
ones = "два "
|
130
|
+
end
|
131
|
+
end_word = two_items
|
132
|
+
when 3
|
133
|
+
ones = "три " if end_word = two_items
|
134
|
+
when 4
|
135
|
+
ones = "четыре " if end_word = two_items
|
136
|
+
when 5
|
137
|
+
ones = "пять "
|
138
|
+
when 6
|
139
|
+
ones = "шесть "
|
140
|
+
when 7
|
141
|
+
ones = "семь "
|
142
|
+
when 8
|
143
|
+
ones = "восемь "
|
144
|
+
when 9
|
145
|
+
ones = "девять "
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# сборка строки
|
150
|
+
st = ''
|
151
|
+
return [(st << hundreds.to_s << tens.to_s << ones.to_s << end_word.to_s << " " << into.to_s).strip, tmp_val]
|
152
|
+
end
|
153
|
+
|
154
|
+
# Реализует вывод прописью любого объекта, реализующего Float
|
155
|
+
module FloatFormatting
|
156
|
+
|
157
|
+
# Выдает сумму прописью с учетом дробной доли. Дробная доля округляется до миллионной, или (если
|
158
|
+
# дробная доля оканчивается на нули) до ближайшей доли ( 500 тысячных округляется до 5 десятых).
|
159
|
+
# Дополнительный аргумент - род существительного (1 - мужской, 2- женский, 3-средний)
|
160
|
+
def propisju(gender = 2)
|
161
|
+
raise "Это не число!" if self.nan?
|
162
|
+
|
163
|
+
st = RuTils::Pluralization::sum_string(self.to_i, gender, "целая", "целых", "целых")
|
164
|
+
|
165
|
+
remainder = self.to_s.match(/\.(\d+)/)[1]
|
166
|
+
|
167
|
+
signs = remainder.to_s.size- 1
|
168
|
+
|
169
|
+
it = [["десятая", "десятых"]]
|
170
|
+
it << ["сотая", "сотых"]
|
171
|
+
it << ["тысячная", "тысячных"]
|
172
|
+
it << ["десятитысячная", "десятитысячных"]
|
173
|
+
it << ["стотысячная", "стотысячных"]
|
174
|
+
it << ["миллионная", "милллионных"]
|
175
|
+
it << ["десятимиллионная", "десятимилллионных", "десятимиллионных"]
|
176
|
+
it << ["стомиллионная", "стомилллионных", "стомиллионных"]
|
177
|
+
it << ["миллиардная", "миллиардных", "миллиардных"]
|
178
|
+
it << ["десятимиллиардная", "десятимиллиардных", "десятимиллиардных"]
|
179
|
+
it << ["стомиллиардная", "стомиллиардных", "стомиллиардных"]
|
180
|
+
it << ["триллионная", "триллионных", "триллионных"]
|
181
|
+
|
182
|
+
while it[signs].nil?
|
183
|
+
remainder = (remainder/10).round
|
184
|
+
signs = remainder.to_s.size- 1
|
185
|
+
end
|
186
|
+
|
187
|
+
suf1, suf2, suf3 = it[signs][0], it[signs][1], it[signs][2]
|
188
|
+
st + " " + RuTils::Pluralization::sum_string(remainder.to_i, 2, suf1, suf2, suf2)
|
189
|
+
end
|
190
|
+
|
191
|
+
def propisju_items(gender=1, *forms)
|
192
|
+
if self == self.to_i
|
193
|
+
return self.to_i.propisju_items(gender, *forms)
|
194
|
+
else
|
195
|
+
self.propisju(gender) + " " + forms[1]
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
# Реализует вывод прописью любого объекта, реализующего Numeric
|
202
|
+
module NumericFormatting
|
203
|
+
# Выбирает корректный вариант числительного в зависимости от рода и числа и оформляет сумму прописью
|
204
|
+
# 234.propisju => "двести сорок три"
|
205
|
+
# 221.propisju(2) => "двести двадцать одна"
|
206
|
+
def propisju(gender = 1)
|
207
|
+
RuTils::Pluralization::sum_string(self, gender, "")
|
208
|
+
end
|
209
|
+
|
210
|
+
def propisju_items(gender=1, *forms)
|
211
|
+
self.propisju(gender) + " " + RuTils::Pluralization::choose_plural(self.to_i, *forms)
|
212
|
+
end
|
213
|
+
|
214
|
+
# Выбирает корректный вариант числительного в зависимости от рода и числа. Например:
|
215
|
+
# * 4.items("колесо", "колеса", "колес") => "колеса"
|
216
|
+
def items(one_item, two_items, five_items)
|
217
|
+
RuTils::Pluralization::choose_plural(self, one_item, two_items, five_items)
|
218
|
+
end
|
219
|
+
|
220
|
+
# Выводит сумму в рублях прописью. Например:
|
221
|
+
# * (15.4).rublej => "пятнадцать рублей сорок копеек"
|
222
|
+
def rublej
|
223
|
+
RuTils::Pluralization::rublej(self)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
class Object::Numeric
|
230
|
+
include RuTils::Pluralization::NumericFormatting
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
class Object::Float
|
235
|
+
include RuTils::Pluralization::FloatFormatting
|
236
|
+
end
|
data/lib/rutils.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
$KCODE = 'u'
|
2
|
+
|
3
|
+
# Главный контейнер модуля
|
4
|
+
module RuTils
|
5
|
+
# Папка, куда установлен модуль RuTils. Нужно чтобы автоматически копировать RuTils в другие приложения.
|
6
|
+
INSTALLATION_DIRECTORY = File.expand_path(File.dirname(__FILE__) + '/../') #:nodoc:
|
7
|
+
MAJOR = 0
|
8
|
+
MINOR = 2
|
9
|
+
TINY = 3
|
10
|
+
|
11
|
+
# Версия RuTils
|
12
|
+
VERSION = [MAJOR, MINOR ,TINY].join('.') #:nodoc:
|
13
|
+
|
14
|
+
# Стандартный маркер для подстановок - invalid UTF sequence
|
15
|
+
SUBSTITUTION_MARKER = "\xF0\xF0\xF0\xF0" #:nodoc:
|
16
|
+
|
17
|
+
def self.load_component(name) #:nodoc:
|
18
|
+
require File.join(RuTils::INSTALLATION_DIRECTORY, "lib", name.to_s, name.to_s)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.reload_component(name) #:nodoc:
|
22
|
+
load File.join(RuTils::INSTALLATION_DIRECTORY, "lib", name.to_s, "#{name}.rb")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
RuTils::load_component :pluralizer #Выбор числительного и сумма прописью
|
28
|
+
RuTils::load_component :gilenson # Гиленсон
|
29
|
+
RuTils::load_component :datetime # Дата и время без локалей
|
30
|
+
RuTils::load_component :transliteration # Транслит
|
31
|
+
RuTils::load_component :integration # Интеграция с rails, textile и тд
|
32
|
+
RuTils::load_component :countries # Данные о странах на русском и английском
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Реализует транслитерацию "в обе стороны", дающую возможность автоматически использовать URL как ключ записи
|
2
|
+
module RuTils::Transliteration::BiDi
|
3
|
+
TABLE_TO = {
|
4
|
+
"А"=>"A","Б"=>"B","В"=>"V","Г"=>"G","Д"=>"D",
|
5
|
+
"Е"=>"E","Ё"=>"JO","Ж"=>"ZH","З"=>"Z","И"=>"I",
|
6
|
+
"Й"=>"JJ","К"=>"K","Л"=>"L","М"=>"M","Н"=>"N",
|
7
|
+
"О"=>"O","П"=>"P","Р"=>"R","С"=>"S","Т"=>"T",
|
8
|
+
"У"=>"U","Ф"=>"F","Х"=>"KH","Ц"=>"C","Ч"=>"CH",
|
9
|
+
"Ш"=>"SH","Щ"=>"SHH","Ъ"=>"_~","Ы"=>"Y","Ь"=>"_'",
|
10
|
+
"Э"=>"EH","Ю"=>"JU","Я"=>"JA","а"=>"a","б"=>"b",
|
11
|
+
"в"=>"v","г"=>"g","д"=>"d","е"=>"e","ё"=>"jo",
|
12
|
+
"ж"=>"zh","з"=>"z","и"=>"i","й"=>"jj","к"=>"k",
|
13
|
+
"л"=>"l","м"=>"m","н"=>"n","о"=>"o","п"=>"p",
|
14
|
+
"р"=>"r","с"=>"s","т"=>"t","у"=>"u","ф"=>"f",
|
15
|
+
"х"=>"kh","ц"=>"c","ч"=>"ch","ш"=>"sh","щ"=>"shh",
|
16
|
+
"ъ"=>"~","ы"=>"y","ь"=>"'","э"=>"eh","ю"=>"ju",
|
17
|
+
"я"=>"ja",
|
18
|
+
# " "=>"__","_"=>"__"
|
19
|
+
# так сразу не получится, будут проблемы с "Ь"=>"_'"
|
20
|
+
}.sort do |one, two|
|
21
|
+
two[1].split(//).size <=> one[1].split(//).size
|
22
|
+
end
|
23
|
+
|
24
|
+
TABLE_FROM = TABLE_TO.unshift([" ","__"]).clone
|
25
|
+
TABLE_TO.unshift(["_","__"])
|
26
|
+
|
27
|
+
def self.translify(str, allow_slashes = true)
|
28
|
+
slash = allow_slashes ? '/' : '';
|
29
|
+
|
30
|
+
s = str.clone.gsub(/[^\- _0-9a-zA-ZА-ёЁ#{slash}]/, '')
|
31
|
+
lang_fr = s.scan(/[А-ёЁ ]+/)
|
32
|
+
lang_fr.each do |fr|
|
33
|
+
TABLE_TO.each do | translation |
|
34
|
+
fr.gsub!(/#{translation[0]}/, translation[1])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
lang_sr = s.scan(/[0-9A-Za-z\_\-\.\/\']+/)
|
39
|
+
|
40
|
+
string = ""
|
41
|
+
if s =~ /\A[А-ёЁ ]/
|
42
|
+
lang_fr, lang_sr = lang_sr, lang_fr
|
43
|
+
string = "+"
|
44
|
+
end
|
45
|
+
|
46
|
+
0.upto([lang_fr.length, lang_sr.length].min-1) do |x|
|
47
|
+
string += lang_sr[x] + "+" + lang_fr[x] + "+";
|
48
|
+
end
|
49
|
+
|
50
|
+
if (lang_fr.length < lang_sr.length)
|
51
|
+
string += lang_sr[lang_sr.length-1]
|
52
|
+
else
|
53
|
+
string[0, string.length-1]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.detranslify(str, allow_slashes = true)
|
58
|
+
slash = allow_slashes ? '/' : '';
|
59
|
+
|
60
|
+
str.split('/').inject(out = "") do |out, pg|
|
61
|
+
strings = pg.split('+')
|
62
|
+
1.step(strings.length-1, 2) do |x|
|
63
|
+
TABLE_FROM.each do | translation |
|
64
|
+
strings[x].gsub!(/#{translation[1]}/, translation[0])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
out << slash << strings.to_s
|
68
|
+
end
|
69
|
+
out[slash.length, out.length-slash.length]
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Реализует простейшую транслитерацию
|
2
|
+
# "вот мы и здесь".translify => "vot my i zdes"
|
3
|
+
# "vot my i zdes".detranslify => "вот мы и здесь"
|
4
|
+
module RuTils::Transliteration::Simple
|
5
|
+
TABLE_LOWER = {
|
6
|
+
"і"=>"i","ґ"=>"g","ё"=>"yo","№"=>"#","є"=>"e",
|
7
|
+
"ї"=>"yi","а"=>"a","б"=>"b",
|
8
|
+
"в"=>"v","г"=>"g","д"=>"d","е"=>"e","ж"=>"zh",
|
9
|
+
"з"=>"z","и"=>"i","й"=>"y","к"=>"k","л"=>"l",
|
10
|
+
"м"=>"m","н"=>"n","о"=>"o","п"=>"p","р"=>"r",
|
11
|
+
"с"=>"s","т"=>"t","у"=>"u","ф"=>"f","х"=>"h",
|
12
|
+
"ц"=>"ts","ч"=>"ch","ш"=>"sh","щ"=>"sch","ъ"=>"'",
|
13
|
+
"ы"=>"yi","ь"=>"","э"=>"e","ю"=>"yu","я"=>"ya"
|
14
|
+
}.sort do | one, two|
|
15
|
+
two[1].size <=> one[1].size
|
16
|
+
end
|
17
|
+
|
18
|
+
TABLE_UPPER = {
|
19
|
+
"Ґ"=>"G","Ё"=>"YO","Є"=>"E","Ї"=>"YI","І"=>"I",
|
20
|
+
"А"=>"A","Б"=>"B","В"=>"V","Г"=>"G",
|
21
|
+
"Д"=>"D","Е"=>"E","Ж"=>"ZH","З"=>"Z","И"=>"I",
|
22
|
+
"Й"=>"Y","К"=>"K","Л"=>"L","М"=>"M","Н"=>"N",
|
23
|
+
"О"=>"O","П"=>"P","Р"=>"R","С"=>"S","Т"=>"T",
|
24
|
+
"У"=>"U","Ф"=>"F","Х"=>"H","Ц"=>"TS","Ч"=>"CH",
|
25
|
+
"Ш"=>"SH","Щ"=>"SCH","Ъ"=>"'","Ы"=>"YI","Ь"=>"",
|
26
|
+
"Э"=>"E","Ю"=>"YU","Я"=>"YA",
|
27
|
+
}.sort do | one, two|
|
28
|
+
two[1].size <=> one[1].size
|
29
|
+
end
|
30
|
+
|
31
|
+
TABLE = TABLE_UPPER + TABLE_LOWER
|
32
|
+
|
33
|
+
# Заменяет кириллицу в строке на латиницу. Немного специфично потому что поддерживает
|
34
|
+
# комби-регистр (Щука -> Shuka)
|
35
|
+
def self.translify(str)
|
36
|
+
chars = str.split(//)
|
37
|
+
|
38
|
+
lowers = TABLE_LOWER.map{|e| e[0] }
|
39
|
+
uppers = TABLE_UPPER.map{|e| e[0] }
|
40
|
+
|
41
|
+
hashtable = {}
|
42
|
+
TABLE.each do | item |
|
43
|
+
next unless item[0] && item[1]
|
44
|
+
hashtable[item[0]] = item[1]
|
45
|
+
end
|
46
|
+
|
47
|
+
result = ''
|
48
|
+
chars.each_with_index do | char, index |
|
49
|
+
if uppers.include?(char) && lowers.include?(chars[index+1])
|
50
|
+
# Combined case. Here we deal with Latin letters so there is no problem to use
|
51
|
+
# Ruby's builtin upcase_downcase
|
52
|
+
ch = hashtable[char].downcase.capitalize
|
53
|
+
result << ch
|
54
|
+
elsif uppers.include?(char)
|
55
|
+
result << hashtable[char]
|
56
|
+
elsif lowers.include?(char)
|
57
|
+
result << hashtable[char]
|
58
|
+
else
|
59
|
+
result << char
|
60
|
+
end
|
61
|
+
end
|
62
|
+
return result
|
63
|
+
end
|
64
|
+
|
65
|
+
# Транслитерирует строку, делая ее пригодной для применения как имя директории или URL
|
66
|
+
def self.dirify(string)
|
67
|
+
st = self.translify(string)
|
68
|
+
st.gsub!(/(\s\&\s)|(\s\&\;\s)/, ' and ') # convert & to "and"
|
69
|
+
st.gsub!(/\W/, ' ') #replace non-chars
|
70
|
+
st.gsub!(/(_)$/, '') #trailing underscores
|
71
|
+
st.gsub!(/^(_)/, '') #leading unders
|
72
|
+
st.strip.translify.gsub(/(\s)/,'-').downcase.squeeze('-')
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module RuTils
|
2
|
+
module Transliteration #:nodoc:
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require File.join(File.dirname(__FILE__), 'simple')
|
7
|
+
require File.join(File.dirname(__FILE__), 'bidi')
|
8
|
+
|
9
|
+
|
10
|
+
# Реализует транслитерацию любого объекта, реализующего String или to_s
|
11
|
+
module RuTils::Transliteration::StringFormatting
|
12
|
+
|
13
|
+
# Транслитерирует строку в латиницу, и возвращает измененную строку
|
14
|
+
def translify
|
15
|
+
RuTils::Transliteration::Simple::translify(self.to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Транслитерирует строку, меняя объект
|
19
|
+
def translify!
|
20
|
+
self.replace(self.translify)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Транслитерирует строку, делая ее пригодной для применения как имя директории или URL
|
24
|
+
def dirify
|
25
|
+
RuTils::Transliteration::Simple::dirify(self.to_s)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Транслитерирует строку (взаимно-однозначный транслит), и возвращает измененную строку
|
29
|
+
def bidi_translify(allow_slashes = true)
|
30
|
+
RuTils::Transliteration::BiDi::translify(self.to_s, allow_slashes)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Транслитерирует строку (взаимно-однозначный транслит), меняя объект
|
34
|
+
def bidi_translify!(allow_slashes = true)
|
35
|
+
self.replace(RuTils::Transliteration::BiDi::translify(self.to_s, allow_slashes))
|
36
|
+
end
|
37
|
+
|
38
|
+
# Заменяет латиницу на кириллицу (взаимно-однозначный транслит), меняя объект
|
39
|
+
def bidi_detranslify!(allow_slashes = true)
|
40
|
+
self.replace(RuTils::Transliteration::BiDi::detranslify(self.to_s, allow_slashes))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Заменяет латиницу на кириллицу (взаимно-однозначный транслит), и возвращает измененную строку
|
44
|
+
def bidi_detranslify(allow_slashes = true)
|
45
|
+
RuTils::Transliteration::BiDi::detranslify(self.to_s, allow_slashes)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Object::String
|
50
|
+
include RuTils::Transliteration::StringFormatting
|
51
|
+
end
|