ruby_typograph 0.0.1.pre.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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