Class: Gilenson

Inherits:
Object
  • Object
show all
Defined in:
lib/gilenson.rb

Defined Under Namespace

Modules: StringFormatting Classes: BlueClothExtra, MarukuExtra, RDiscountExtra, RedClothExtra, UnknownSetting

Constant Summary collapse

VERSION =
'1.2.2'
SETTINGS =
{
   "inches"    => true,    # преобразовывать дюймы в знак дюйма;
   "laquo"     => true,    # кавычки-ёлочки
   "quotes"    => true,    # кавычки-английские лапки
   "dash"      => true,    # короткое тире (150)
   "emdash"    => true,    # длинное тире двумя минусами (151)
   "initials"  => true,    # тонкие шпации в инициалах
   "copypaste" => false,   # замена непечатных и "специальных" юникодных символов на entities
   "(c)" => true,    # обрабатывать знаки копирайтов и трейдмарков
   "acronyms"  => true,    # Акронимы с пояснениями - ЖЗЛ(Жизнь Замечатльных Людей)
   "+-"        => true,    # спецсимволы, какие - понятно
   "degrees"   => true,    # знак градуса
   "dashglue"  => true, "wordglue" => true, # приклеивание предлогов и дефисов
   "spacing"   => true,    # запятые и пробелы, перестановка
   "phones"    => true,    # обработка телефонов
   "html"      => true,    # разрешение использования тагов html
   "de_nobr"   => false,   # при true все <nobr/> заменяются на <span class="nobr"/>
   "raw_output" => false,  # выводить UTF-8 вместо entities
   "skip_attr" => false,   # при true не отрабатывать типографику в атрибутах тегов
   "skip_code" => true,    # при true не отрабатывать типографику внутри <code/>, <tt/>, CDATA
   "enforce_en_quotes" => false, # только латинские кавычки
   "enforce_ru_quotes" => false, # только русские кавычки (enforce_en_quotes при этом игнорируется)
   "(r)"       => true, # DEPRECATED
   "(tm)"      => true, # DEPRECATED
   "(p)"       => true, # DEPRECATED
}.freeze
GLYPHS =

Глифы, использующиеся в подстановках по-умолчанию

{
  :quot       => "&#34;",     # quotation mark
  :amp        => "&#38;",     # ampersand
  :apos       => "&#39;",     # apos
  :gt         => "&#62;",     # greater-than sign
  :lt         => "&#60;",     # less-than sign
  :nbsp       => "&#160;",    # non-breaking space
  :sect       => "&#167;",    # section sign
  :copy       => "&#169;",    # copyright sign
  :laquo      => "&#171;",    # left-pointing double angle quotation mark = left pointing guillemet
  :reg        => "&#174;",    # registered sign = registered trade mark sign
  :deg        => "&#176;",    # degree sign
  :plusmn     => "&#177;",    # plus-minus sign = plus-or-minus sign
  :para       => "&#182;",    # pilcrow sign = paragraph sign
  :middot     => "&#183;",    # middle dot = Georgian comma = Greek middle dot
  :raquo      => "&#187;",    # right-pointing double angle quotation mark = right pointing guillemet
  :ndash      => "&#8211;",   # en dash
  :mdash      => "&#8212;",   # em dash
  :lsquo      => "&#8216;",   # left single quotation mark
  :rsquo      => "&#8217;",   # right single quotation mark
  :ldquo      => "&#8220;",   # left double quotation mark
  :rdquo      => "&#8221;",   # right double quotation mark
  :bdquo      => "&#8222;",   # double low-9 quotation mark
  :bull       => "&#8226;",   # bullet = black small circle
  :hellip     => "&#8230;",   # horizontal ellipsis = three dot leader
  :numero     => "&#8470;",   # numero
  :trade      => "&#8482;",   # trade mark sign
  :minus      => "&#8722;",   # minus sign
  :inch       => "&#8243;",   # inch/second sign (u0x2033) (не путать с кавычками!)
  :thinsp     => "&#8201;",   # полукруглая шпация (тонкий пробел)
  :nob_open   => '<span class="nobr">',    # открывающий блок без переноса слов
  :nob_close  => '</span>',    # закрывающий блок без переноса слов
}.freeze
VERBATIM_GLYPHS =

Нормальные “типографские” символы в UTF-виде. Браузерами обрабатываются плохонько, поэтому лучше заменять их на entities.

{
 ' '         => :nbsp,# alt+0160 (NBSP here)
 '«'         => :laquo,
 '»'         => :raquo,
 '§'         => :sect,
 '©'         => :copy,
 '®'         => :reg,
 '°'         => :deg,
 '±'         => :plusmn,
 ''         => :para,
 '·'         => :middot,
 ''         => :ndash,
 ''         => :mdash,
 ''         => :lsquo,
 ''         => :rsquo,
 ''         => :ldquo,
 ''         => :rdquo,
 ''         => :bdquo,
 ''         => :bull,
 ''         => :hellip,
 ''         => :numero,
 ''         => :trade,
 ''         => :minus,
 ''         => :thinsp,
 ''         => :inch,
}.freeze
REPLACEMENT_MARKER =

Метка на которую подменяются вынутые теги - Unicode Character ‘OBJECT REPLACEMENT CHARACTER’ (U+FFFC) unicode.org/reports/tr20/tr20-1.html Он официально применяется для обозначения вложенного обьекта

[0xEF, 0xBF, 0xBC].pack("U*").freeze
FORBIDDEN_NUMERIC_ENTITIES =

Кто придумал &#147;? Не учите людей плохому… Привет А.Лебедеву www.artlebedev.ru/kovodstvo/62/ Используем символы, потом берем по символам из glyphs форматтера. Молодец mash!

{
  '132'       => :bdquo,
  '133'       => :hellip,
  '146'       => :apos,
  '147'       => :ldquo,
  '148'       => :rdquo,
  '149'       => :bull,
  '150'       => :ndash,
  '151'       => :mdash,
  '153'       => :trade,
}.freeze
UNICODE_WHITESPACE =

Все юникодные пробелы, шпации и отступы

[
  (0x0009..0x000D).to_a, # White_Space # Cc   [5] <control-0009>..<control-000D>
  0x0020,                # White_Space # Zs       SPACE
  0x0085,                # White_Space # Cc       <control-0085>
  0x00A0,                # White_Space # Zs       NO-BREAK SPACE
  0x1680,                # White_Space # Zs       OGHAM SPACE MARK
  0x180E,                # White_Space # Zs       MONGOLIAN VOWEL SEPARATOR
  (0x2000..0x200A).to_a, # White_Space # Zs  [11] EN QUAD..HAIR SPACE
  0x2028,                # White_Space # Zl       LINE SEPARATOR
  0x2029,                # White_Space # Zp       PARAGRAPH SEPARATOR
  0x202F,                # White_Space # Zs       NARROW NO-BREAK SPACE
  0x205F,                # White_Space # Zs       MEDIUM MATHEMATICAL SPACE
  0x3000,                # White_Space # Zs       IDEOGRAPHIC SPACE
].flatten.pack("U*").freeze
PROTECTED_SETTINGS =

:nodoc:

[ :raw_output ]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Gilenson

Returns a new instance of Gilenson.



156
157
158
159
160
# File 'lib/gilenson.rb', line 156

def initialize(*args)
  @_text = args[0].is_a?(String) ? args[0] : ''
  setup_default_settings!
  accept_configuration_arguments!(args.last) if args.last.is_a?(Hash)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args) ⇒ Object

Неизвестные методы - настройки. С = - установка ключа, без - получение значения



171
172
173
174
175
176
# File 'lib/gilenson.rb', line 171

def method_missing(meth, *args) #:nodoc:
  setting = meth.to_s.gsub(/=$/, '')
  super(meth, *args) unless @settings.has_key?(setting) #this will pop the exception if we have no such setting
  
  return (@settings[setting] = args[0])
end

Instance Attribute Details

#glyphObject

Returns the value of attribute glyph.



14
15
16
# File 'lib/gilenson.rb', line 14

def glyph
  @glyph
end

#settingsObject

Returns the value of attribute settings.



15
16
17
# File 'lib/gilenson.rb', line 15

def settings
  @settings
end

Instance Method Details

#apply(filter, text, lift_ignored_elements = true) ⇒ Object

Применяет отдельный фильтр к text и возвращает результат. Например:

formatter.apply(:wordglue, "Вот так") => "Вот&#160;так"

Удобно применять когда вам нужно задействовать отдельный фильтр Гиленсона, но не нужна остальная механика Последний аргумент определяет, нужно ли при применении фильтра сохранить в неприкосновенности таги и другие игнорируемые фрагменты текста (по умолчанию они сохраняются).



290
291
292
293
294
295
296
297
298
# File 'lib/gilenson.rb', line 290

def apply(filter, text, lift_ignored_elements = true)
  copy = text.dup
  unless lift_ignored_elements
    self.send("process_#{filter}".to_sym, copy)
  else
    lifting_fragments(copy) { self.send("process_#{filter}".to_sym, copy) }
  end
  copy
end

#configure!(*config) ⇒ Object Also known as: configure

Настраивает форматтер ассоциированным хешем

formatter.configure!(:dash=>true, :wordglue=>false)


164
165
166
# File 'lib/gilenson.rb', line 164

def configure!(*config)
  accept_configuration_arguments!(config.last) if config.last.is_a?(Hash)
end

#process(text_to_process, *args) ⇒ Object

Обрабатывает text_to_process с сохранением настроек, присвоенных обьекту-форматтеру Дополнительные аргументы передаются как параметры форматтера и не сохраняются после прогона.



180
181
182
183
184
# File 'lib/gilenson.rb', line 180

def process(text_to_process, *args)
  @_text = text_to_process
  
  args.last.is_a?(Hash) ? with_configuration(args.last) { to_html } : to_html
end

#to_htmlObject

Обрабатывает текст, присвоенный форматтеру при создании и возвращает результат обработки



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/gilenson.rb', line 187

def to_html
  return '' unless @_text
  
  # NOTE: strip is Unicode-space aware on 1.9.1, so here we simulate that
  text = @_text.gsub(/[#{UNICODE_WHITESPACE}]\z/, '').gsub(/\A[#{UNICODE_WHITESPACE}]/, '')
  
  # -6. Подмухляем таблицу глифов, если нам ее передали
  glyph_table = glyph.dup
  
  if @settings["enforce_ru_quotes"]
    glyph_table[:ldquo], glyph_table[:rdquo] = glyph_table[:laquo], glyph_table[:raquo]
  elsif @settings["enforce_en_quotes"]
    glyph_table[:laquo], glyph_table[:raquo] = glyph_table[:ldquo], glyph_table[:rdquo]
  end
  
  # -5. Копируем глифы в ивары, к ним доступ быстр и в коде они глаза тоже не мозолят
  glyph_table.each_pair do | ki, wi |
    instance_variable_set("@#{ki}", wi)
  end

  # -4. запрет тагов html
  process_escape_html(text) unless @settings["html"]
 
  # -3. Никогда (вы слышите?!) не пущать лабуду &#not_correct_number;
  FORBIDDEN_NUMERIC_ENTITIES.dup.each_pair do | key, rep |
    text.gsub!(/&##{key};/, self.glyph[rep])
  end
   
  # -2. Чистим copy&paste
  process_copy_paste_clearing(text) if @settings['copypaste']

  # -1. Замена &entity_name; на входе ('&nbsp;' => '&#160;' и т.д.)
  process_html_entities(text)

  # 0. Вырезаем таги
  tags = lift_ignored_elements(text) if @skip_tags

  # 1. Запятые и пробелы
  process_spacing(text) if @settings["spacing"]

  # 1. лапки
  process_quotes(text) if @settings["quotes"]
  
  # 2. ёлочки
  process_laquo(text) if @settings["laquo"]

  # 3. Инчи
  process_inches(text) if @settings["inches"]

  # 2b. одновременно ёлочки и лапки
  process_compound_quotes(text) if (@settings["quotes"] && @settings["laquo"])

  # 3. тире
  process_dash(text) if @settings["dash"]

  # 3a. тире длинное
  process_emdash(text) if @settings["emdash"]
  
  # 4. копимарки и трейдрайты
  process_copymarks(text) if @settings["(c)"]
  
  # 5. +/-
  process_plusmin(text) if @settings["+-"]

  # 5a. 12^C
  process_degrees(text) if @settings["degrees"]

  # 6. телефоны
  process_phones(text) if @settings["phones"]

  # 7. Короткие слова и &nbsp;
  process_wordglue(text) if @settings["wordglue"]

  # 8. Склейка ласт. Тьфу! дефисов.
  process_dashglue(text) if @settings["dashglue"]

  # 8a. Инициалы
  process_initials(text) if @settings['initials']

  # 8b. Троеточия
  process_ellipsises(text) if @settings["wordglue"]

  # 9. Акронимы от Текстиля
  process_acronyms(text) if @settings["acronyms"]
  
  # БЕСКОНЕЧНОСТЬ. Вставляем таги обратно.
  reinsert_fragments(text, tags) if @skip_tags

  # фуф, закончили.
  process_span_instead_of_nobr(text) if @settings["de_nobr"]

  # заменяем entities на истинные символы
  process_raw_output(text) if @settings["raw_output"]
  
  text.strip
end