ruby_typograph 0.0.1.pre.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: df22ecd8c810f3eca7f45f19e0bff20ee3a254f1
4
+ data.tar.gz: bed8ba9ec1431e3f11d6c2115130ad90372f5473
5
+ SHA512:
6
+ metadata.gz: ea04e9d94b1602ea9bc0687c2d86badb6f26409187c6b4f0237cf3fa4293d0fbdc608f3b2e278d0a95d7a45bb2799f00c4914ba0b6263b7324ef04f471be945a
7
+ data.tar.gz: 4afcd23b08cb1ad3018c8e700a94910f560e35afae1edb6172769cf3acd9a89947d85f009d37747c8d6b88a016371e0471cbe15392ae4df2580bbfb984840212
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in typograph.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 sterebooster
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # Typograph
2
+
3
+ Gem for typographing russian and english texts.
4
+
5
+ ##### Привязка союзов, предлогов
6
+ ``` ruby
7
+ Typograph.process 'Я бы в лётчики б пошёл, пусть меня научат.'
8
+ > 'Я бы в летчики б пошел, пусть меня научат.'
9
+ ```
10
+
11
+ ##### Расстановка кавычек
12
+ ``` ruby
13
+ Typograph.process '"Кавычки "второго уровня"" and "Quotes "second level""'
14
+ > '«Кавычки “второго уровня”» and “Quotes ‘second level’”'
15
+ ```
16
+
17
+ ##### Расстановка запятых перед а, но
18
+ ``` ruby
19
+ Typograph.process 'Мало написать а запятые кто за тебя расставит.'
20
+ > '"Мало написать, а запятые кто за тебя расставит.'
21
+ ```
22
+
23
+ ##### Отсутствие запятых у "а"" и "но" после тире
24
+ ``` ruby
25
+ Typograph.process 'Текст до тире – а теперь после'
26
+ > 'Текст до тире — а теперь после'
27
+ ```
28
+
29
+ ##### Расстановка правильного апострофа в английских текстах
30
+ ``` ruby
31
+ Typograph.process "don't"
32
+ > 'don’t'
33
+ ```
34
+
35
+
36
+ - Замена ё на е
37
+ - Удаление лишних пробелов
38
+ - Расстановка дефиса в предлогах из-за, из-под
39
+ - Расстановка дефиса перед -таки
40
+ - Расстановка дефиса после кое-, кой-
41
+ - Удаление пробела перед символом процент
42
+ - Удаление пробелов внутри скобок
43
+ - Выделение прямой речи
44
+ - Замена (R) на символ зарегистрированной торговой марки
45
+ - Замена (c) на символ копирайт
46
+ - Замена (tm) на символ торговой марки
47
+ - Замена дробей 1/2, 1/4, 3/4 на соответствующие символы
48
+ - Расстановка пробелов перед сокращениями см., им.
49
+ - Расстановка пробелов перед сокращениями гл., стр., рис., илл.
50
+ - Объединение сокращений и др.
51
+ - Расстановка пробелов в сокращениях г., ул., пер., д.
52
+ - Расстановка пробелов перед сокращениями dpi, lpi
53
+
54
+ ### rspec
55
+
56
+ ``` ruby
57
+ Finished in 0.07754 seconds
58
+ 47 examples, 3 failures
59
+
60
+ Failed examples:
61
+
62
+ rspec ./spec/typograph_spec.rb:73 # .process Удаление пробелов перед знаками препинания
63
+ rspec ./spec/typograph_spec.rb:79 # .process Расстановка пробелов после знака препинания
64
+ rspec ./spec/typograph_spec.rb:103 # .process Выделение прямой речи
65
+ ```
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ desc "Run all specs"
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
9
+ LANG = "ru_RU.UTF-8"
10
+
11
+ SET_CMD = case RUBY_PLATFORM
12
+ when /mingw32/ then
13
+ "set"
14
+ else
15
+ "export"
16
+ end
17
+
18
+ desc "run tests"
19
+ task :test do
20
+ sh "#{SET_CMD} LANG=#{LANG} && chcp 65001 && bundle exec rake"
21
+ end
data/lib/typograph.rb ADDED
@@ -0,0 +1,12 @@
1
+ require "typograph/version"
2
+ require "typograph/adapter"
3
+ require "typograph/processors/quotes"
4
+ require "typograph/processors/russian_grammar"
5
+ require "typograph/processor"
6
+
7
+ module Typograph
8
+ def self.process(text="", options={})
9
+ return "" if text.nil?
10
+ Processor.new(options).process(text)
11
+ end
12
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ require 'htmlentities'
4
+
5
+ module Typograph
6
+ class Adapter
7
+
8
+ SPECIAL = {
9
+ :lsquo => '‘',
10
+ :rsquo => '’',
11
+ :sbquo => '‚',
12
+ :ldquo => '“',
13
+ :rdquo => '”',
14
+ :bdquo => '„',
15
+ :lsaquo => '‹',
16
+ :rsaquo => '›',
17
+ :quot => '"',
18
+ :grave => '`',
19
+ :laquo => '«',
20
+ :raquo => '»',
21
+ :acute => '´',
22
+ :hellip => '…',
23
+ :ndash => '–',
24
+ :mdash => '—',
25
+ :nbsp => "\xA0",
26
+ :shy => "\xAD",
27
+ :cent => '¢',
28
+ :pound => '£',
29
+ :curren => '¤',
30
+ :yen => '¥',
31
+ :sect => '§',
32
+ :sup2 => '²',
33
+ :sup3 => '³'
34
+ }
35
+
36
+ def initialize(options={})
37
+ @options = options
38
+ end
39
+
40
+ def process(text)
41
+
42
+ end
43
+
44
+ def sym_to_char(sym)
45
+ res = SPECIAL[sym]
46
+ raise ArgumentError, "Unknown sym #{sym}" unless res
47
+ res
48
+ end
49
+
50
+ def normalize(str)
51
+ str.gsub!(/ | /, ' ')
52
+ str.chomp(" \r\n\t")
53
+ HTMLEntities.new.decode(str)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ module Typograph
4
+ class Processor
5
+
6
+ DEFAULTS = {}
7
+
8
+ SAFE_BLOCKS = [
9
+ ['<pre[^>]*>','</pre>'],
10
+ ['<style[^>]*>','</style>'],
11
+ ['<script[^>]*>','</script>'],
12
+ ['<!--','-->'],
13
+ ['<code[^>]*>','</code>']
14
+ ]
15
+
16
+ def initialize(options={})
17
+ @adapter = Adapter.new options
18
+ @russian_grammar = Processors::RussianGrammar.new options
19
+ @quotes = Processors::Quotes.new options
20
+ end
21
+
22
+ def safe_blocks
23
+ @pattern ||= begin
24
+ pattern = SAFE_BLOCKS.map do |val|
25
+ val.join('.*?')
26
+ end.join('|')
27
+ Regexp.new("(#{pattern}|<[^>]*[\\s][^>]*>)", Regexp::IGNORECASE | Regexp::MULTILINE)
28
+ end
29
+ end
30
+
31
+ def process(str)
32
+ str = @adapter.normalize(str)
33
+
34
+ @safe_blocks = {}
35
+ str.gsub!(safe_blocks) do |match|
36
+ key = "<#{@safe_blocks.length}>"
37
+ @safe_blocks[key] = match
38
+ key
39
+ end
40
+
41
+ str = @quotes.process str
42
+ str = @russian_grammar.process str
43
+
44
+
45
+ if @safe_blocks
46
+ str.gsub! /(<\d>)/ do |match|
47
+ @safe_blocks[match]
48
+ end
49
+ end
50
+ @safe_blocks = {}
51
+
52
+ str
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,83 @@
1
+ module Typograph
2
+ module Processors
3
+ class Quotes
4
+
5
+ SPECIAL = {
6
+ :lsquo => '‘',
7
+ :rsquo => '’',
8
+ :sbquo => '‚',
9
+ :ldquo => '“',
10
+ :rdquo => '”',
11
+ :bdquo => '„',
12
+ :quot => '"',
13
+ :grave => '`',
14
+ :laquo => '«',
15
+ :raquo => '»',
16
+ :acute => '´',
17
+ }
18
+ RU = 'А-я'
19
+ EN = 'A-z'
20
+
21
+ def initialize(options)
22
+ @options = options
23
+ end
24
+
25
+ def process(str)
26
+ if @options.nil? || @options[:only].nil?
27
+ str = replace_russian_quotes str
28
+ str = replace_english_quotes str
29
+ else
30
+ if @options[:only].include? :ru
31
+ str = replace_russian_quotes str, RU+EN
32
+ elsif @options[:only].include? :en
33
+ str = replace_english_quotes str, RU+EN
34
+ end
35
+ end
36
+ str
37
+ end
38
+
39
+ private
40
+
41
+ def replace_russian_quotes(str,lang=RU)
42
+ left1 = SPECIAL[:laquo]
43
+ right1 = SPECIAL[:raquo]
44
+ left2 = SPECIAL[:ldquo]
45
+ right2 = SPECIAL[:rdquo]
46
+ str = replace_quotes str, left1, right1, left2, right2, lang
47
+ end
48
+
49
+ def replace_english_quotes(str,lang=EN)
50
+ left1 = SPECIAL[:ldquo]
51
+ right1 = SPECIAL[:rdquo]
52
+ left2 = SPECIAL[:lsquo]
53
+ right2 = SPECIAL[:rsquo]
54
+ str = replace_quotes str, left1, right1, left2, right2, lang
55
+ end
56
+
57
+ def replace_quotes(str,left1,right1,left2,right2,letters)
58
+ replace_quotes = lambda do
59
+ old_str = String.new(str)
60
+ str.gsub!(Regexp.new("(\"|\')([#{letters}].*?[^\\s])\\1", Regexp::MULTILINE | Regexp::IGNORECASE)) do |match|
61
+ inside, before, after = $2, $`, $'
62
+ if after.match(/^([^<]+>|>)/) || before.match(/<[^>]+$/)
63
+ match
64
+ else
65
+ "#{left1}#{inside}#{right1}"
66
+ end
67
+ end
68
+ old_str != str
69
+ end
70
+ while replace_quotes.call do end
71
+ replace_second_level_quotes = lambda do
72
+ regexp = "(#{left1}([^#{right1},.])*)#{left1}(.*)#{right1}(.*#{right1})"
73
+ str.gsub! Regexp.new(regexp, Regexp::MULTILINE | Regexp::IGNORECASE) do |text|
74
+ "#{$1}#{left2}#{$3}#{right2}#{$4}"
75
+ end
76
+ end
77
+ while replace_second_level_quotes.call do end
78
+ str
79
+ end
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,274 @@
1
+ # encoding: utf-8
2
+
3
+ module Typograph
4
+ module Processors
5
+ class RussianGrammar
6
+
7
+ OPTIONS = {
8
+ :ndash => '–',
9
+ :mdash => '—',
10
+ :minus => '-',
11
+ :orphan => false
12
+ }
13
+
14
+ def initialize(options={})
15
+ @options = OPTIONS.dup.merge(options)
16
+
17
+ @ndash = @options[:ndash]
18
+ @mdash = @options[:mdash]
19
+ @minus = @options[:minus]
20
+
21
+ @abbr = 'ООО|ОАО|ЗАО|ЧП|ИП|НПФ|НИИ|ООО\p{Zs}ТПК'
22
+ @prepos = 'а|в|во|вне|и|к|о|с|у|со|об|обо|от|ото|то|на|не|ни|но|из|изо|за|уж|на|по|подо|пред|предо|про|над|надо|как|без|безо|да|до|там|ещё|их|ко|меж|между|перед|передо|около|через|сквозь|при|я'
23
+ # что|для|или|под
24
+ @metrics = 'мм|см|м|км'
25
+ @measure = "#{@metrics}|г|кг|б|кб|мб|гб|dpi|px"
26
+ @shortages = 'г|гр|тов|пос|c|ул|д|пер|м|зам|им|бул'
27
+ @money = 'руб\.|долл\.|евро|у\.е\.'
28
+ @countables = 'млн|тыс'
29
+
30
+ @rules_strict = rules_strict
31
+ @rules_symbols = rules_symbols
32
+ @rules_braces = rules_braces
33
+ @rules_main = rules_main
34
+ @rules_main[/(\s)(\S+)\Z/] = '&nbsp;\2' if options[:orphan]
35
+
36
+ end
37
+
38
+ def process(str)
39
+ str = apply_rules @rules_strict, str # Сначала применим строгие правила: пробелы, запятые
40
+ str = apply_rules @rules_symbols, str
41
+ str = apply_rules @rules_main, str
42
+ str = apply_rules @rules_braces, str
43
+ end
44
+
45
+ private
46
+
47
+ def apply_rules(rules, str)
48
+ res = str.dup
49
+ rules.each do |rul, rep|
50
+ str.gsub!(rul, rep)
51
+ end
52
+ str
53
+ end
54
+
55
+ def rules_strict
56
+ {
57
+ # Много пробелов или табуляций -> один пробел
58
+ /( |\t)+/ => ' ',
59
+ # Запятые после «а» и «но». Если уже есть — не ставим.
60
+ /([а-яA-я0-9])\s(а|но)\s/ => '\1, \2 ',
61
+ }
62
+ end
63
+
64
+ def rules_symbols
65
+ {
66
+ # Лишние знаки.
67
+ # TODO: сделать красиво
68
+ /([^!])!!([^!])/ => '\1!\2',
69
+ /([^?])\?\?([^?])/ => '\1?\2',
70
+ /(\p{L})\s*\.\.(\p{Zs})/ => '\1.\2', # new
71
+ /(\p{L});[;\s]*(;)/ => '\1;', # new
72
+ /(\p{L}),[,\s]*(,)/ => '\1,', # new
73
+ /(\p{L}):[:\s]*(:)/ => '\1:', # new
74
+
75
+ /([!\?])\s*(!\s*)[!\s]*(!)/ => '\1!!', # new
76
+ /(\?\s*)(\?\s*)[\?\s]*(\?)/ => '???', # new
77
+ /(\.\s*)(\.\s*)[\.\s]*(\.)/ => '...', # new
78
+ /(,\s*)[,\s]*(,)/ => ',', # new
79
+ /;{2,}/ => ';', # new
80
+ /,{2,}/ => ',', # new
81
+ /:{2,}/ => ':', # new
82
+
83
+ # /([;,:])(\S)/ => '\1 \2', # new
84
+
85
+ # Занятная комбинация
86
+ /!\?/ => '?!',
87
+
88
+ # Знаки (c), (r), (tm)
89
+ /\((c|с)\)/i => '©',
90
+ /\(r\)/i => '<sup><small>®</small></sup>',
91
+ /\(tm\)/i => '™',
92
+
93
+ # От 2 до 5 знака точки подряд - на знак многоточия (больше - мб авторской задумкой).
94
+ /\s*\.{2,5}/ => '…',
95
+
96
+ # Дроби
97
+ # TODO: найти замену \b
98
+ /\b1\/2\b/ => '½',
99
+ /\b1\/3\b/ => '⅓',
100
+ /\b2\/3\b/ => '⅔',
101
+ /\b1\/4\b/ => '¼',
102
+ /\b3\/4\b/ => '¾',
103
+ /\b1\/5\b/ => '⅕',
104
+ /\b2\/5\b/ => '⅖',
105
+ /\b3\/5\b/ => '⅗',
106
+ /\b4\/5\b/ => '⅘',
107
+ /\b1\/6\b/ => '⅙',
108
+ /\b5\/6\b/ => '⅚',
109
+ /\b1\/8\b/ => '⅛',
110
+ /\b3\/8\b/ => '⅜',
111
+ /\b5\/8\b/ => '⅝',
112
+ /\b7\/8\b/ => '⅞',
113
+
114
+ # LО'Лайт, O'Reilly
115
+ /([A-Z])''?([а-яА-Яa-zA-Z])/i => '\1’\2',
116
+
117
+ /'/ => '&#39;',
118
+
119
+ # Размеры 10x10, правильный знак + убираем лишние пробелы
120
+ /(\p{Nd}+)\p{Zs}{0,}?[x|X|х|Х|*]\p{Zs}{0,}(\p{Nd}+)/ => '\1×\2',
121
+
122
+ # +-
123
+ /([^\+]|^)\+\/?-/ => '\1±',
124
+
125
+ # Стрелки
126
+ /([^-]|^)->/ => '\1→',
127
+ /<-([^-]|$)/ => '←\1'
128
+ }
129
+ end
130
+
131
+ def rules_braces
132
+ {
133
+ # Оторвать скобку от слова
134
+ /(\p{L})\(/ => '\1 (',
135
+ # Слепляем скобки со словами
136
+ /\( /m => '(',
137
+ / \)/m => ')'
138
+ }
139
+ end
140
+
141
+ def rules_main
142
+ {
143
+ # Конфликт с «газо- и электросварка»
144
+ # Оторвать тире от слова
145
+ # /(\p{L})- / => '\1 - ',
146
+
147
+ # P.S., P.P.S - конфликтует с правилом инициалов.
148
+ 'P.P.S.' => '<nobr>P. P. S.</nobr>',
149
+ /([^.]|^)P\.S\./ => '\1<nobr>P. S.</nobr>',
150
+ # /и(&nbsp;|\s)?т(&nbsp;|\s)?\.?д(&nbsp;|\s)?\.{0,2}/ => "<nobr>и т. д.</nobr>",
151
+ # /и(&nbsp;|\s)?т(&nbsp;|\s)?\.?п(&nbsp;|\s)?\.{0,2}/ => "<nobr>и т. п.</nobr>",
152
+ # /в(&nbsp;|\s)?т(&nbsp;|\s)?\.?ч(&nbsp;|\s)?\.{0,2}/ => "<nobr>в т. ч.</nobr>",
153
+
154
+ # Знаки с предшествующим пробелом… нехорошо!
155
+ # -/(\p{L}|>|\p{Nd}) +([?!:,;…])/ => '\1\2',
156
+ # /([?!:,;])(\p{L}|<)/ => '\1 \2',
157
+ # Для точки отдельно
158
+ /(\p{L})\p{Zs}(?:\.)(\p{Zs}|$)/ => '\1.\2',
159
+ # Но перед кавычками пробелов не ставим
160
+ /([?!:,;\.])\p{Zs}(»)/ => '\1\2',
161
+
162
+ # Неразрывные названия организаций и абревиатуры форм собственности
163
+ # ~ почему не один &nbsp;?
164
+ # ! названия организаций тоже могут содержать пробел !
165
+ /(#{@abbr})\p{Zs}+(«[^»]*»)/ => '<nobr>\1 \2</nobr>',
166
+
167
+ # Нельзя отрывать сокращение от относящегося к нему слова.
168
+ # Например: тов. Сталин, г. Воронеж
169
+ # Ставит пробел, если его нет.
170
+ /(^|[^a-zA-Zа-яА-Я])(#{@shortages})\.\s?([А-Я0-9]+)/m => '\1\2.&nbsp;\3',
171
+ /(^|[^a-zA-Zа-яА-Я])(см)\.\s?([А-Яа-я]+)/m => '\1\2.&nbsp;\3',
172
+
173
+ # Не отделять стр., с. и т.д. от номера.
174
+ /(стр|с|табл|рис|илл|гл)\.\p{Zs}*(\p{Nd}+)/mi => '\1.&nbsp;\2',
175
+
176
+ # Не разделять 2007 г., ставить пробел, если его нет. Ставит точку, если её нет.
177
+ /(\p{Nd}+)\p{Zs}*([гГ])\.\s/m => '\1&nbsp;\2. ',
178
+ /(\p{Nd}+)\p{Zs}*-\p{Zs}*(\p{Nd}+)г\.?г\./ => "<nobr>\\1—\\2 гг.</nobr>",
179
+ /(\d\d\.\d\d\.\d\d\d?\d?)(\s|&nbsp;)*г\.?(\s|&nbsp;)/ => "<nobr>\\1 г.</nobr> ",
180
+
181
+ # Неразрывный пробел между цифрой и единицей измерения
182
+ /(\p{Nd}+)\s*(#{@measure})/m => '\1&nbsp;\2',
183
+
184
+ # Сантиметр и другие ед. измерения в квадрате, кубе и т.д.
185
+ /(\p{Zs}#{@metrics})2/ => '\1&sup2;',
186
+ /(\p{Zs}#{@metrics})3/ => '\1&sup3;',
187
+ /(\p{Zs}#{@metrics})(\p{Nd}+)/ => '\1<sup>\2</sup>',
188
+
189
+ # Знак дефиса или два знака дефиса подряд — на знак длинного тире.
190
+ # + Нельзя разрывать строку перед тире, например: Знание&nbsp;— сила, Курить&nbsp;— здоровью вредить.
191
+ /\p{Zs}+(?:--?|—)(?=\p{Zs})/ => "&nbsp;#{@mdash}",
192
+ /^(?:--?|—)(?=\p{Zs})/ => @mdash,
193
+
194
+ # Прямая речь
195
+ /(?:^|\s+)(?:--?|—)(?=\p{Zs})/ => '\0',
196
+
197
+ # Знак дефиса, ограниченный с обоих сторон цифрами — на знак короткого тире.
198
+ /(?<=\p{Nd})-(?=\p{Nd})/ => @minus,
199
+
200
+ # Знак дефиса, ограниченный с обоих сторон пробелами — на знак длинного тире.
201
+ /(\s)(&ndash;|–)(\s)/ => "&nbsp;#{@mdash} ",
202
+
203
+ # Знак дефиса, идущий после тэга и справа пробел — на знак длинного тире.
204
+ /(?<=>)(&ndash;|–|-)(\s)/ => "#{@mdash} ",
205
+
206
+ # Расстановка дефиса перед -ка, -де, -кась
207
+ # /\b(\S+)[\s-](ка|де|кась)\b/ => "<nobr>\\1#{ndash}\\2</nobr>",
208
+
209
+ # Расстановка дефиса после кое-, кой-
210
+ /\b(кое|кой)[\s-](как|кого|какой)\b/i => "<nobr>\\1#{@ndash}\\2</nobr>",
211
+
212
+ # Расстановка дефиса перед -то, -либо, -нибудь
213
+ ### to od /(кто|что|где|когда|почему|зачем|кем|чем|как|чего)(\s|-|–|—|&nbsp;)+(либо|нибудь|то)([^:]|$)/i => "<nobr>\\1#{ndash}\\3</nobr>\\4",
214
+
215
+ # Расстановка дефиса перед -таки
216
+ /(все)(\s|-|–|—|&nbsp;)+(таки)/i => "<nobr>\\1#{@ndash}\\3</nobr>",
217
+
218
+ # Расстановка дефисов в предлогах «из-за», «из-под», «по-над», «по-под».
219
+ /\b(из)[\s-]?(за|под)\b/i => "<nobr>\\1#{@ndash}\\2</nobr>",
220
+ /\b(по)[\s-]?(над|под)\b/i => "<nobr>\\1#{@ndash}\\2</nobr>",
221
+
222
+ # Нельзя оставлять в конце строки предлоги и союзы
223
+ /(?<=\p{Zs}|^|\p{^L})(#{@prepos})(\s+)/i => '\1&nbsp;',
224
+
225
+ # Нельзя отрывать частицы бы, ли, же от предшествующего слова, например: как бы, вряд ли, так же.
226
+ /(?<=\p{^Zs})(\p{Zs}+)(ж|бы|б|же|ли|ль|либо)(?=(<.*?>)*[\p{Zs})!?.…])/i => '&nbsp;\2',
227
+ # |или
228
+
229
+ # Неразрывный пробел после инициалов.
230
+ /([А-ЯA-Z]\.)\s?([А-ЯA-Z]\.)\p{Zs}?([А-ЯA-Z][а-яa-z]+)/m => '\1\2&nbsp;\3',
231
+
232
+ # Сокращения сумм не отделяются от чисел.
233
+ /(\p{Nd}+)\p{Zs}?(#{@countables})/m => '\1&nbsp;\2',
234
+
235
+ # «уе» в денежных суммах
236
+ /(\p{Nd}+|#{@countables})\p{Zs}?уе/m => '\1&nbsp;у.е.',
237
+
238
+ # Денежные суммы, расставляя пробелы в нужных местах.
239
+ /(\p{Nd}+|#{@countables})\p{Zs}?(#{@money})/m => '\1&nbsp;\2',
240
+
241
+ # Неразрывные пробелы в кавычках
242
+ # "/($sym[lquote]\S*)(\s+)(\S*$sym[rquote])/U" => '\1'.\sym["nbsp"].'\3',
243
+
244
+ # Телефоны
245
+ /(?:тел\.?\/?факс:?\s?\((\d+)\))/i => 'тел./факс:&nbsp(\1)',
246
+
247
+ /тел[:\.] ?(\p{Nd}+)/m => '<nobr>тел: \1</nobr>',
248
+
249
+ # Номер версии программы пишем неразрывно с буковкой v.
250
+ /([vв]\.) ?(\p{Nd})/i => '\1&nbsp;\2',
251
+ /(\p{L}) ([vв]\.)/i => '\1&nbsp;\2',
252
+
253
+ # % не отделяется от числа
254
+ /(\p{Nd}+)\p{Zs}+%/ => '\1%',
255
+
256
+ # IP-адреса рвать нехорошо
257
+ /(1\p{Nd}{0,2}|2(\p{Nd}|[0-5]\p{Nd}+)?)\.(0|1\p{Nd}{0,2}|2(\p{Nd}|[0-5]\p{Nd})?)\.(0|1\p{Nd}{0,2}|2(\p{Nd}|[0-5]\p{Nd})?)\.(0|1\p{Nd}{0,2}|2(\p{Nd}|[0-5]\p{Nd})?)/ =>
258
+ '<nobr>\0</nobr>',
259
+
260
+ # Делаем неразрывными слова с дефисом.
261
+ # Пример: "слово-слово", "слово-слово-слово".
262
+ /(\^|;)((\p{L}+((&ndash;|–|-)\p{L}+){1,2}))/ => '\1<nobr>\2</nobr>',
263
+
264
+ # Меняем ё на е и Ё на Е
265
+ /ё/ => 'е',
266
+ /Ё/ => 'Е',
267
+
268
+ }
269
+ end
270
+
271
+ end
272
+ end
273
+ end
274
+
@@ -0,0 +1,3 @@
1
+ module Typograph
2
+ VERSION = "0.0.1.pre.7"
3
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+ # $KCODE = "utf-8" if defined?($KCODE)
3
+
4
+ require "typograph"
5
+ require "rspec"
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+ # $KCODE = "utf-8" if defined?($KCODE)
3
+
4
+ require "typograph"
5
+ require "rspec"
6
+
7
+ OPT = {
8
+ :ndash => '-'
9
+ }
10
+
11
+ describe 'errors' do
12
+
13
+ describe 'quotes' do
14
+
15
+ it '#1' do
16
+ text = "БМК «ПРОСТ»,Библиотека Тургенева приглашают на 2-е заседание дискуссионного клуба 'Дисккуб21'."
17
+ text_processed = "БМК «ПРОСТ»,Библиотека Тургенева приглашают на&nbsp;2-е заседание дискуссионного клуба «Дисккуб21»."
18
+ Typograph.process(text, OPT).should eq text_processed
19
+ end
20
+
21
+
22
+ it '#2' do
23
+ text = "Аля Самохина, создатель блога wholesomeway.net, и Аня Сидорова, организатор фитнес-туров Fitness travel, научат готовить необычные блюда из фруктов, зелени, орехов и других полезных продуктов:\n\n"+
24
+ "— смузи \"Бодрость зелени\";\n\n" +
25
+ "— мороженое \"Банановый рассвет\";\n\n" +
26
+ "— пирожное \"Баунти\".\n\n" +
27
+ "Мастер-класс Али Самохиной и Ани Сидоровой состоится в рамках Делай феста — в секции 'Ланчи-бранчи'. Полная программа «Делай феста»\n"
28
+
29
+ text_processed = "Аля Самохина, создатель блога wholesomeway.net, и&nbsp;Аня Сидорова, организатор фитнес-туров Fitness travel, научат готовить необычные блюда из&nbsp;фруктов, зелени, орехов и&nbsp;других полезных продуктов:\n\n"+
30
+ "— смузи «Бодрость зелени»;\n\n" +
31
+ "— мороженое «Банановый рассвет»;\n\n" +
32
+ "— пирожное «Баунти».\n\n" +
33
+ "Мастер-класс Али Самохиной и&nbsp;Ани Сидоровой состоится в&nbsp;рамках Делай феста&nbsp;— в&nbsp;секции «Ланчи-бранчи». Полная программа «Делай феста»\n"
34
+
35
+ Typograph.process(text, OPT).should eq text_processed
36
+ end
37
+
38
+ end
39
+
40
+ describe 'ampersand' do
41
+ it '#1' do
42
+ text = '<p>Воркшоп состоится в рамках «Делай феста» — в секции «Арт&amp;Дизайн». Полная программа http://makefest.exchang.es/schedule</p>'
43
+ text_processed = "<p>Воркшоп состоится в&nbsp;рамках «Делай феста»&nbsp;— в&nbsp;секции «Арт&Дизайн». Полная программа http://makefest.exchang.es/schedule</p>"
44
+ Typograph.process(text, OPT).should eq text_processed
45
+ end
46
+ end
47
+
48
+
49
+
50
+ describe 'options' do
51
+ it 'only russian quotes' do
52
+ text = 'Тумбочка "staple x"'
53
+ text_processed = "Тумбочка «staple x»"
54
+ Typograph.process(text, only: [:ru]).should eq text_processed
55
+ end
56
+ end
57
+
58
+
59
+
60
+
61
+ end
@@ -0,0 +1,431 @@
1
+ # encoding: utf-8
2
+ # $KCODE = "utf-8" if defined?($KCODE)
3
+
4
+ require "typograph"
5
+ require "rspec"
6
+
7
+ OPT = {
8
+ :ndash => '-'
9
+ }
10
+
11
+ describe '.process' do
12
+ it 'Удаление лишних пробельных символов и табуляций' do
13
+ text = "В этом тексте \t много пробелов."
14
+ text_processed = 'В&nbsp;этом тексте много пробелов.'
15
+ Typograph.process(text, OPT).should eq text_processed
16
+ end
17
+
18
+ # it 'Удаление повторяющихся слов' do
19
+ # text = 'При при проверке текста обнаружились обнаружились повторяющиеся слова слова. Слова убраны.'
20
+ # text_processed = 'При проверке текста обнаружились повторяющиеся слова. Слова убраны.'
21
+ # Typograph.process(text, OPT).should eq text_processed
22
+ # end
23
+
24
+ it 'Расстановка запятых перед а, но' do
25
+ text = 'Мало написать а запятые кто за тебя расставит.'
26
+ text_processed = 'Мало написать, а&nbsp;запятые кто за&nbsp;тебя расставит.'
27
+ Typograph.process(text, OPT).should eq text_processed
28
+ end
29
+
30
+ it 'Отсутствие запятых у "а"" и "но" после тире' do
31
+ text = 'Текст до тире – а теперь после'
32
+ text_processed = 'Текст до&nbsp;тире&nbsp;— а&nbsp;теперь после'
33
+ Typograph.process(text, OPT).should eq text_processed
34
+ end
35
+
36
+ # it 'Расстановка дефиса перед -то, -либо, -нибудь' do
37
+ # text = 'Кто то где то когда то как то что то чем то стукнул. И возможно чего нибудь бы получилось если б кто либо пришел.'
38
+ # text_processed = '<nobr>Кто-то</nobr> <nobr>где-то</nobr> <nobr>когда-то</nobr> <nobr>как-то</nobr> <nobr>что-то</nobr> <nobr>чем-то</nobr> стукнул. И&nbsp;возможно <nobr>чего-нибудь</nobr>&nbsp;бы получилось если&nbsp;б <nobr>кто-либо</nobr> пришел.'
39
+ # # Опять же что - то получилось, но как- то не так.
40
+ # Typograph.process(text, OPT).should eq text_processed
41
+ # end
42
+
43
+ # it 'Расстановка дефиса перед -ка, -де, -кась' do
44
+ # text = 'Возьми ка детка молока. А коль увижу де, что казнь ему мала, повешу тут же всех судей вокруг стола. Поди кась так. Планета Ка-Пэкс'
45
+ # text_processed = '<nobr>Возьми-ка</nobr> детка молока. А&nbsp;коль <nobr>увижу-де</nobr>, что казнь ему мала, повешу тут&nbsp;же всех судей вокруг стола. <nobr>Поди-кась</nobr> так. Планета Ка-Пэкс'
46
+ # Typograph.process(text, OPT).should eq text_processed
47
+ # end
48
+
49
+ it 'Расстановка дефиса после кое-, кой-' do
50
+ text = 'Кое как дошли. Кой кого встретили. Кое от кого, кое на чем, кой у кого, кое с чьим.'
51
+ text_processed = '<nobr>Кое-как</nobr> дошли. <nobr>Кой-кого</nobr> встретили. Кое от&nbsp;кого, кое на&nbsp;чем, кой у&nbsp;кого, кое с&nbsp;чьим.'
52
+ Typograph.process(text, OPT).should eq text_processed
53
+ end
54
+
55
+ it 'Расстановка дефиса перед -таки' do
56
+ text = 'Секретарь, хотя и чувствовал свое слабое недовольство, все таки радовался наличию таких старушек в активе района. Но хоть и велик был соблазн, я таки успел себя побороть.'
57
+ text_processed = 'Секретарь, хотя и&nbsp;чувствовал свое слабое недовольство, <nobr>все-таки</nobr> радовался наличию таких старушек в&nbsp;активе района. Но&nbsp;хоть и&nbsp;велик был соблазн, я&nbsp;таки успел себя побороть.'
58
+ Typograph.process(text, OPT).should eq text_processed
59
+ end
60
+
61
+ it 'Расстановка дефиса в предлогах из-за, из-под' do
62
+ text = 'Из за леса величаво выплывало солнце. Из под развесистой сирени вдруг с лаем выскочила собака.'
63
+ text_processed = '<nobr>Из-за</nobr> леса величаво выплывало солнце. <nobr>Из-под</nobr> развесистой сирени вдруг с&nbsp;лаем выскочила собака.'
64
+ Typograph.process(text, OPT).should eq text_processed
65
+ end
66
+
67
+ it 'Удаление парных знаков препинания' do
68
+ text = 'Правда!? Правда!!! Неправда??? Честно?? Честно!! Проехали.. Задумчиво...'
69
+ text_processed = 'Правда?! Правда!!! Неправда??? Честно? Честно! Проехали. Задумчиво…'
70
+ Typograph.process(text, OPT).should eq text_processed
71
+ end
72
+
73
+ it 'Удаление пробелов перед знаками препинания' do
74
+ text = 'Некоторые виды деревьев : ель ,сосна , берёза, дуб ; растут в наших лесах .'
75
+ text_processed = 'Некоторые виды деревьев: ель, сосна, береза, дуб; растут в&nbsp;наших лесах.'
76
+ Typograph.process(text, OPT).should eq text_processed
77
+ end
78
+
79
+ it 'Расстановка пробелов после знака препинания' do
80
+ text = 'Так бывает.И вот так...И ещё вот так!..Бывает же???Что поделать. Вывод:верен.'
81
+ text_processed = 'Так бывает. И&nbsp;вот так… И&nbsp;ещё вот так!.. Бывает&nbsp;же??? Что поделать. Вывод: верен.'
82
+ Typograph.process(text, OPT).should eq text_processed
83
+ end
84
+
85
+ it 'Удаление пробела перед символом процент' do
86
+ text = '100 %'
87
+ text_processed = '100%'
88
+ Typograph.process(text, OPT).should eq text_processed
89
+ end
90
+
91
+ it 'Удаление пробелов внутри скобок' do
92
+ text = 'Текст( ( Внутри ) скобок ).'
93
+ text_processed = 'Текст ((Внутри) скобок).'
94
+ Typograph.process(text, OPT).should eq text_processed
95
+ end
96
+
97
+ # it 'Расстановка пробела перед скобками' do
98
+ # text = 'Текст(Внутри скобок).'
99
+ # text_processed = 'Текст (Внутри скобок).'
100
+ # Typograph.process(text, OPT).should eq text_processed
101
+ # end
102
+
103
+ it 'Выделение прямой речи' do
104
+ text = '- Я пошёл домой... - Может останешься? - Нет, ухожу.'
105
+ text_processed = '—&nbsp;Я&nbsp;пошёл домой… —&nbsp;Может останешься? —&nbsp;Нет, ухожу.'
106
+ Typograph.process(text, OPT).should eq text_processed
107
+ end
108
+
109
+ it 'Привязка союзов, предлогов' do
110
+ text = 'Я бы в лётчики б пошёл, пусть меня научат.'
111
+ text_processed = 'Я&nbsp;бы в&nbsp;летчики&nbsp;б пошел, пусть меня научат.'
112
+ Typograph.process(text, OPT).should eq text_processed
113
+ end
114
+
115
+ it 'Замена x на символ × в размерных единицах' do
116
+ text = '3х4, 3 х 6'
117
+ text_processed = '3×4, 3×6'
118
+ Typograph.process(text, OPT).should eq text_processed
119
+ end
120
+
121
+ it 'Замена дробей 1/2, 1/4, 3/4 на соответствующие символы' do
122
+ text = '1/2, 1/4, 3/4, 123/432'
123
+ text_processed = '½, ¼, ¾, 123/432'
124
+ Typograph.process(text, OPT).should eq text_processed
125
+ end
126
+
127
+ it 'Замена (R) на символ зарегистрированной торговой марки' do
128
+ text = '(r)'
129
+ text_processed = '<sup><small>®</small></sup>'
130
+ Typograph.process(text, OPT).should eq text_processed
131
+ end
132
+
133
+ it 'Замена (c) на символ копирайт' do
134
+ text = '(c) Eugene Spearance'
135
+ text_processed = '© Eugene Spearance'
136
+ Typograph.process(text, OPT).should eq text_processed
137
+ end
138
+
139
+ it 'Замена (tm) на символ торговой марки' do
140
+ text = 'ВасяПупкин(tm)'
141
+ text_processed = 'ВасяПупкин™'
142
+ Typograph.process(text, OPT).should eq text_processed
143
+ end
144
+
145
+ # it 'Тире в конце строки (стихотворная форма)' do
146
+ # text = %q{Раздобудь к утру ковёр -
147
+ # Шитый золотом узор!..
148
+ # Государственное дело, -
149
+ # Расшибись, а будь добёр!}
150
+ # text_processed = %q{Раздобудь к&nbsp;утру ковёр —<br />\nШитый золотом узор!..<br />\nГосударственное дело, —<br />\nРасшибись, а&nbsp;будь добёр!}
151
+ # Typograph.process(text, OPT).should eq text_processed
152
+ # end
153
+
154
+ it 'Расстановка знака минус между числами' do
155
+ text = '123-32'
156
+ text_processed = '123-32'
157
+ Typograph.process(text, OPT).should eq text_processed
158
+ end
159
+
160
+ it 'Расстановка правильного апострофа в английских текстах' do
161
+ text = "don't"
162
+ text_processed = 'don’t'
163
+ Typograph.process(text, OPT).should eq text_processed
164
+ end
165
+
166
+ # it 'Замена символа параграф с привязкой к числу' do
167
+ # text = '§32, §IV'
168
+ # text_processed = '&sect;&nbsp;32, &sect;&nbsp;IV'
169
+ # Typograph.process(text, OPT).should eq text_processed
170
+ # end
171
+
172
+ # it 'Замена символа номер с привязкой к числу' do
173
+ # text = '№15Ф, №34/25'
174
+ # text_processed = '&#8470;&nbsp;15Ф, &#8470;&nbsp;34/25'
175
+ # Typograph.process(text, OPT).should eq text_processed
176
+ # end
177
+
178
+ it 'Расстановка правильных «тройных» кавычек' do
179
+ text = 'Она добавила: "И цвет мой самый любимый - "эсмеральда"".'
180
+ text_processed = 'Она добавила: «И&nbsp;цвет мой самый любимый&nbsp;— “эсмеральда”».'
181
+ Typograph.process(text, OPT).should eq text_processed
182
+ end
183
+
184
+ # it 'Расстановка пробелов и привязка в денежных сокращениях' do
185
+ # text = '10,34руб., 23тыс.долл., 64 млн.евро, 34.3€, 56$, 3,65уе'
186
+ # text_processed = '10,34&nbsp;руб., 23&nbsp;тыс.&nbsp;долл., 64&nbsp;млн.&nbsp;евро, 34.3&nbsp;&euro;, 56&nbsp;$, 3,65&nbsp;у.е.'
187
+ # Typograph.process(text, OPT).should eq text_processed
188
+ # end
189
+
190
+ # it 'Объединение сокращений и т.д., и т.п., в т.ч.' do
191
+ # text = 'Лес, газ, нефть и тд., и т.п.. Перины, подушки в тч. подушки-думки.'
192
+ # text_processed = 'Лес, газ, нефть <nobr>и т. д.</nobr>, <nobr>и т. п.</nobr> Перины, подушки <nobr>в т. ч.</nobr> <nobr>подушки-думки</nobr>.'
193
+ # Typograph.process(text, OPT).should eq text_processed
194
+ # end
195
+
196
+ it 'Расстановка пробелов перед сокращениями см., им.' do
197
+ text = 'Данные изложены в таблице см.цветной вкладыш. Дом им.Пушкина.'
198
+ text_processed = 'Данные изложены в&nbsp;таблице см.&nbsp;цветной вкладыш. Дом им.&nbsp;Пушкина.'
199
+ Typograph.process(text, OPT).should eq text_processed
200
+ end
201
+
202
+ it 'Расстановка пробелов перед сокращениями гл., стр., рис., илл.' do
203
+ text = 'Инструкцию см. гл. 8, стр.34, рис.3 или илл.3.'
204
+ text_processed = 'Инструкцию см.&nbsp;гл.&nbsp;8, стр.&nbsp;34, рис.&nbsp;3 или илл.&nbsp;3.'
205
+ Typograph.process(text, OPT).should eq text_processed
206
+ end
207
+
208
+ it 'Объединение сокращений и др.' do
209
+ text = 'Оля, Иван, Олег и др. ребята.'
210
+ text_processed = 'Оля, Иван, Олег и&nbsp;др. ребята.'
211
+ Typograph.process(text, OPT).should eq text_processed
212
+ end
213
+
214
+ it 'Расстановка пробелов в сокращениях г., ул., пер., д.' do
215
+ text = 'г.Тюмень, ул.Ленина, пер. Ленина, бул. Ленина, д. 4'
216
+ text_processed = 'г.&nbsp;Тюмень, ул.&nbsp;Ленина, пер.&nbsp;Ленина, бул.&nbsp;Ленина, д.&nbsp;4'
217
+ Typograph.process(text, OPT).should eq text_processed
218
+ end
219
+
220
+ it 'Расстановка пробелов перед сокращениями dpi, lpi' do
221
+ text = 'Разрешение 300dpi (для офсета).'
222
+ text_processed = 'Разрешение 300&nbsp;dpi (для офсета).'
223
+ Typograph.process(text, OPT).should eq text_processed
224
+ end
225
+
226
+ it 'Объединение сокращений P.S., P.P.S.' do
227
+ text = 'P.S. привет всем. P.P.S. и мне тоже.'
228
+ text_processed = '<nobr>P. S.</nobr> привет всем. <nobr>P. P. S.</nobr> и&nbsp;мне тоже.'
229
+ Typograph.process(text, OPT).should eq text_processed
230
+ end
231
+
232
+ # it 'Объединение в неразрывные конструкции слов с дефисом.' do
233
+ # text = 'Жёлто-оранжевый цвет. Ростов-на-Дону красивый город.'
234
+ # text_processed = '<nobr>Жёлто-оранжевый</nobr> цвет. <nobr>Ростов-на-Дону</nobr> красивый город.'
235
+ # Typograph.process(text, OPT).should eq text_processed
236
+ # end
237
+
238
+ # it 'Привязка сокращений форм собственности к названиям организаций' do
239
+ # text = 'ООО "Фирма Терминал", НИИ "ОблСнабВротКомпот"'
240
+ # text_processed = '<nobr>ООО «Фирма Терминал»</nobr>, <nobr>НИИ «ОблСнабВротКомпот»</nobr>'
241
+ # Typograph.process(text, OPT).should eq text_processed
242
+ # end
243
+
244
+ # it 'Объединение в неразрывные конструкции номеров телефонов' do
245
+ # text = '+7 (3452) 55-66-77, 8 905 555-55-55'
246
+ # text_processed = '<nobr>+7 (3452) 55-66-77</nobr>, <nobr>8 905 555-55-55</nobr>'
247
+ # Typograph.process(text, OPT).should eq text_processed
248
+ # end
249
+
250
+ # it 'Привязка сокращения ГОСТ к номеру' do
251
+ # text = 'Гост 5773-90 - российские стандартные форматы изданий'
252
+ # text_processed = '<nobr>ГОСТ 5773&ndash;90 —</nobr> российские стандартные форматы изданий'
253
+ # Typograph.process(text, OPT).should eq text_processed
254
+ # end
255
+
256
+ # it 'Установка пробельных символов в сокращении вольт' do
257
+ # text = '~23,5в'
258
+ # text_processed = '<nobr>~23,5 В</nobr>'
259
+ # Typograph.process(text, OPT).should eq text_processed
260
+ # end
261
+
262
+ # it 'Объединение триад чисел' do
263
+ # text = '123 456 789 руб. В стычке участвовало 3 200 человек.'
264
+ # text_processed = '123&nbsp;456&nbsp;789&nbsp;руб. В&nbsp;стычке участвовало 3&nbsp;200 человек.'
265
+ # Typograph.process(text, OPT).should eq text_processed
266
+ # end
267
+
268
+ it 'Объединение IP-адресов' do
269
+ text = 'Адрес localhost - 127.0.0.1'
270
+ text_processed = 'Адрес localhost&nbsp;— <nobr>127.0.0.1</nobr>'
271
+ Typograph.process(text, OPT).should eq text_processed
272
+ end
273
+
274
+ # it 'Установка тире и пробельных символов в периодах дат' do
275
+ # text = 'Это событие произошло между 1999-2001г.г., на стыке XX-XXIв.'
276
+ # text_processed = 'Это событие произошло между&nbsp;<nobr>1999—2001&nbsp;гг.</nobr>, на&nbsp;стыке <nobr>XX—XXI вв.</nobr>'
277
+ # Typograph.process(text, OPT).should eq text_processed
278
+ # end
279
+
280
+ # it 'Привязка года к дате' do
281
+ # text = 'Документ был подписан 17.02.1983г. И утратил свою силу 07.03.93 года.'
282
+ # text_processed = 'Документ был подписан <nobr>17.02.1983&nbsp;г.</nobr> И&nbsp;утратил свою силу 07.03.93&nbsp;года.'
283
+ # Typograph.process(text, OPT).should eq text_processed
284
+ # end
285
+
286
+ # it 'Расстановка тире и объединение в неразрывные периоды дней' do
287
+ # text = 'Собеседования состоятся 14-24 сентября, в актовом зале с 11:30-13:00.'
288
+ # text_processed = 'Собеседования состоятся <nobr>14—24 сентября</nobr>, в&nbsp;актовом зале с&nbsp;<nobr>11:30—13:00</nobr>.'
289
+ # Typograph.process(text, OPT).should eq text_processed
290
+ # end
291
+
292
+ it 'Расстановка тире и объединение в неразрывные периоды месяцев' do
293
+ text = 'Выставка пройдёт в апреле-мае этого года.'
294
+ text_processed = 'Выставка пройдет в&nbsp;<nobr>апреле-мае</nobr> этого года.'
295
+ Typograph.process(text, OPT).should eq text_processed
296
+ end
297
+
298
+ it 'Привязка сокращений до н.э., н.э.' do
299
+ text = 'IV в до н.э, в V-VIвв до нэ., третий в. н.э.'
300
+ text_processed = 'IV в&nbsp;до&nbsp;н.э, в&nbsp;<nobr>V-VIвв</nobr> до&nbsp;нэ., третий&nbsp;в. н.э.'
301
+ Typograph.process(text, OPT).should eq text_processed
302
+ end
303
+
304
+ it 'Привязка инициалов к фамилиям' do
305
+ text = 'А.С.Пушкин, Пушкин А.С.'
306
+ text_processed = 'А.С.&nbsp;Пушкин, Пушкин А.С.'
307
+ Typograph.process(text, OPT).should eq text_processed
308
+ end
309
+
310
+ it 'Замена символа градус, плюс-минус' do
311
+ text = '+- 10, +/- 25'
312
+ text_processed = '± 10, ± 25'
313
+ Typograph.process(text, OPT).should eq text_processed
314
+ end
315
+
316
+ it 'Замена символов и привязка сокращений в размерных величинах: м, см, м2…' do
317
+ text = 'На лесопилку завезли 32 м3 леса, из которых 4м3 пустили под распил на 25мм доски, длинной по 6м.'
318
+ text_processed = 'На&nbsp;лесопилку завезли 32&nbsp;м&sup3; леса, из&nbsp;которых 4&nbsp;м&sup3; пустили под распил на&nbsp;25&nbsp;мм доски, длинной по&nbsp;6&nbsp;м.'
319
+ Typograph.process(text, OPT).should eq text_processed
320
+ end
321
+
322
+ it 'Повторное типографирование текста' do
323
+ text = '<p><nobr>Coca-Cola</nobr><sup><small>&reg;</small></sup>&nbsp;— зарегистрированный товарный знак.</p>'
324
+ text_processed = '<p><nobr>Coca-Cola</nobr><sup><small>®</small></sup>&nbsp;— зарегистрированный товарный знак.</p>'
325
+ Typograph.process(text, OPT).should eq text_processed
326
+ end
327
+
328
+ it 'Обработка HTML' do
329
+ text = '<!-- В тексте попался комментарий -->'
330
+ text_processed = text.dup
331
+ Typograph.process(text, OPT).should eq text_processed
332
+ end
333
+
334
+ it 'Обработка CSS' do
335
+ text = %q{<style type="text/css">
336
+ SPAN.nobr { white-space: nowrap }
337
+ </style>}
338
+ text_processed = text.dup
339
+ Typograph.process(text, OPT).should eq text_processed
340
+ end
341
+
342
+ it 'Обработка JavaScript' do
343
+ text = "<script type='text/javascript'>document.write('Этот текст не должен быть типографирован.')</script>"
344
+ text_processed = text.dup
345
+ Typograph.process(text, OPT).should eq text_processed
346
+ end
347
+
348
+ it 'Обработка тегов <pre>' do
349
+ text = %q{<pre> Я не хотел бы
350
+ чтобы этот текст
351
+ был форматирован.</pre>}
352
+ text_processed = text.dup
353
+ Typograph.process(text, OPT).should eq text_processed
354
+ end
355
+
356
+ # it 'Выделение ссылок из текста' do
357
+ # text = 'В тексте встретилась ссылка: http://www.typograf.ru'
358
+ # text_processed = 'В&nbsp;тексте встретилась ссылка: <a href="http://www.typograf.ru">http://www.typograf.ru</a>'
359
+ # Typograph.process(text, OPT).should eq text_processed
360
+ # end
361
+
362
+ # it 'Выделение e-mail из текста' do
363
+ # text = 'В тексте встретился e-mail: mail@typograf.ru'
364
+ # text_processed = 'В&nbsp;тексте встретился <nobr>e-mail</nobr>: <a href="mailto:mail@typograf.ru">mail@typograf.ru</a>'
365
+ # Typograph.process(text, OPT).should eq text_processed
366
+ # end
367
+
368
+ # it 'Обработка списков' do
369
+ # text = ''
370
+ # # * Программное обеспечение
371
+ # # ** Операционные системы
372
+ # # +++ Windows XP
373
+ # # +++ Linux RedHat
374
+ # # +++ MacOS X
375
+ # # ** Текстовые радакторы
376
+ # # * Компьютеры
377
+ # text_processed = ''
378
+ # Typograph.process(text, OPT).should eq text_processed
379
+ # end
380
+
381
+ # it 'Выделение акронимов' do
382
+ # text = '<p>Все что вы хотели узнать о HTML.</p>'
383
+ # text_processed = '<p>Все что вы&nbsp;хотели узнать о&nbsp;<acronym title="HyperText Markup Language" lang="en">HTML</acronym>.</p>'
384
+ # Typograph.process(text, OPT).should eq text_processed
385
+ # end
386
+
387
+ it 'Меняем ё на е и Ё на Е' do
388
+ text = 'Ёж обыкновенный, или европейский ёж.'
389
+ text_processed = 'Еж обыкновенный, или европейский еж.'
390
+ Typograph.process(text, OPT).should eq text_processed
391
+ end
392
+
393
+ it 'Не трогаем ссылки в маркдауне' do
394
+ text = "Глава из книги Бориса Гройса «Поэтика политики»](http://theoryandpractice.ru/posts/6762-wikileaks-vosstanie-klerkov-glava-iz-knigi-borisa-groysa-poetika-politiki)"
395
+ text_processed = "Глава из&nbsp;книги Бориса Гройса «Поэтика политики»](http://theoryandpractice.ru/posts/6762-wikileaks-vosstanie-klerkov-glava-iz-knigi-borisa-groysa-poetika-politiki)"
396
+ Typograph.process(text, OPT).should eq text_processed
397
+ end
398
+
399
+ it 'Не трогам отсупы у тире, если с тире начинается строка' do
400
+ text = "Правах человека в России, и о ее месте в Совете Европы, и о коллективной памяти о преступлениях Советской власти.
401
+ Татьяна Добровольская
402
+ -------
403
+ **— Где и чему ты учишься, как давно?**
404
+ — Сейчас я учусь по обмену в Болонском университете на факультете политических наук. В Москве — в Высшей школе экономики"
405
+ text_processed = "Правах человека в&nbsp;России, и&nbsp;о&nbsp;ее месте в&nbsp;Совете Европы, и&nbsp;о&nbsp;коллективной памяти о&nbsp;преступлениях Советской власти.
406
+ Татьяна Добровольская
407
+ -------
408
+ **— Где и&nbsp;чему ты учишься, как&nbsp;давно?**
409
+ — Сейчас я&nbsp;учусь по&nbsp;обмену в&nbsp;Болонском университете на&nbsp;факультете политических наук. В&nbsp;Москве&nbsp;— в&nbsp;Высшей школе экономики"
410
+ Typograph.process(text, OPT).should eq text_processed
411
+ end
412
+
413
+ it "Лишнее тере с 'как' 'то'" do
414
+ text = "Я постараюсь ответить на твой вопрос так просто, как только смогу. Вот мой ответ:"
415
+ text_processed = "Я&nbsp;постараюсь ответить на&nbsp;твой вопрос так просто, как&nbsp;только смогу. Вот мой ответ:"
416
+ Typograph.process(text, OPT).should eq text_processed
417
+ end
418
+
419
+ it "should make english and russian quotes in the same string" do
420
+ text = '"Quotes" и "Кавычки"'
421
+ text_processed = '“Quotes” и&nbsp;«Кавычки»'
422
+ Typograph.process(text, OPT).should eq text_processed
423
+ end
424
+
425
+ it 'Quotes second level' do
426
+ text = '"Кавычки "второго уровня"" and "Quotes "second level""'
427
+ text_processed = "«Кавычки “второго уровня”» and “Quotes ‘second level’”"
428
+ Typograph.process(text, OPT).should eq text_processed
429
+ end
430
+
431
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'typograph/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = 'ruby_typograph'
8
+ gem.version = Typograph::VERSION
9
+ gem.authors = ['Tolia']
10
+ gem.email = ['toliademidov@gmail.com']
11
+ gem.description = %q{Gem for typographing russian and english texts.}
12
+ gem.summary = %q{Gem for typographing russian and english texts.}
13
+ gem.homepage = "https://github.com/Tolia/typograph"
14
+ gem.license = "MIT"
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(spec)/})
19
+ gem.require_paths = ["lib"]
20
+
21
+ gem.add_dependency 'htmlentities'
22
+
23
+ gem.add_development_dependency 'rake'
24
+ gem.add_development_dependency 'rspec'
25
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_typograph
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre.7
5
+ platform: ruby
6
+ authors:
7
+ - Tolia
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: htmlentities
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Gem for typographing russian and english texts.
56
+ email:
57
+ - toliademidov@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/typograph.rb
69
+ - lib/typograph/adapter.rb
70
+ - lib/typograph/processor.rb
71
+ - lib/typograph/processors/quotes.rb
72
+ - lib/typograph/processors/russian_grammar.rb
73
+ - lib/typograph/version.rb
74
+ - spec/helper.rb
75
+ - spec/parse_error_spec.rb
76
+ - spec/typograph_spec.rb
77
+ - typographer.gemspec
78
+ homepage: https://github.com/Tolia/typograph
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">"
94
+ - !ruby/object:Gem::Version
95
+ version: 1.3.1
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.2.2
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Gem for typographing russian and english texts.
102
+ test_files:
103
+ - spec/helper.rb
104
+ - spec/parse_error_spec.rb
105
+ - spec/typograph_spec.rb