rubypants 0.7.0 → 0.7.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8dc4efc96c1fe85653d5cfb4f6d0291a94edcdbc
4
- data.tar.gz: b17cda053df199efe900caed483404b903345f9c
2
+ SHA256:
3
+ metadata.gz: 766f0400e12ec2e5bb64917568fcf5dba1b7fdf7e31632c62144602e0b1bd674
4
+ data.tar.gz: 87de02ec38116b4d9d179e80f958f608101565a9724f63a751e7efb642dab7ff
5
5
  SHA512:
6
- metadata.gz: eaebe94dfee7f1ef9295910593ff64e0b10a5147ab96e802e7ce98031a15ee4e6c78ae7ee45ccadccaeb30d2c86d96692a2625733bb6e3f7edcda3ecd995c1a6
7
- data.tar.gz: 3eabe14d2d081f67239047c29d7d71e93025622cdd3f562b1f3fd2b83a26cddea359e2fbc8a20d3f9ca9f0c855c12c4fe3f76e16442e6f2898a6dc346f2e6f4e
6
+ metadata.gz: 543191639285ce9c53716b19fcbfa72dd6b14e96f53cb88b87a62f5cf4446725ceeb384c6ea3c7767c97409195d7e5cb11c8694d06eb93545284b230b2407bf0
7
+ data.tar.gz: ed420062908b83fa18c96bb8048870095350f4d9b45ac2294939a9265f775c04a1aa4c5d7e40ed8b3bee741a013103be0bf218e4d18e4e0e59dbbe3eb6cd2fc0
@@ -1,8 +1,7 @@
1
1
  rvm:
2
- - 2.0
3
- - 2.1
4
- - 2.2
5
- - 2.3.0
2
+ - 2.4
3
+ - 2.5
4
+ - 2.6
6
5
  - jruby
7
6
 
8
7
  # Workaround for `NoMethodError: undefined method 'spec' for nil:NilClass`,
@@ -70,12 +70,23 @@ class RubyPants < String
70
70
 
71
71
  @options = [*options]
72
72
  @entities = default_entities
73
- @entities.merge!(named_entities) if @options.include?(:named_entities)
73
+ @entities.merge!(named_entities) if @options.include?(:named_entities)
74
74
  @entities.merge!(character_entities) if @options.include?(:character_entities)
75
- @entities.merge!(character_spaces) if @options.include?(:character_spaces)
75
+ @entities.merge!(character_spaces) if @options.include?(:character_spaces)
76
76
  @entities.merge!(entities)
77
+
78
+ @single_left_quote = @entities[:single_left_quote]
79
+ @single_right_quote = @entities[:single_right_quote]
80
+ @double_left_quote = @entities[:double_left_quote]
81
+ @double_right_quote = @entities[:double_right_quote]
82
+ @ellipsis = @entities[:ellipsis]
83
+ @em_dash = @entities[:em_dash]
84
+ @en_dash = @entities[:en_dash]
77
85
  end
78
86
 
87
+ SPECIAL_HTML_TAGS = %r!\A<(/?)(pre|code|kbd|script|style|math)[\s>]!
88
+ NON_WHITESPACE_CHARS = /\S/
89
+
79
90
  # Apply SmartyPants transformations.
80
91
  def to_html
81
92
  do_quotes = do_backticks = do_dashes = do_ellipses = do_stupify = nil
@@ -102,16 +113,16 @@ class RubyPants < String
102
113
  end
103
114
 
104
115
  # Explicit flags override numeric flag groups.
105
- do_quotes = true if @options.include?(:quotes)
106
- do_backticks = true if @options.include?(:backticks)
107
- do_backticks = :both if @options.include?(:allbackticks)
108
- do_dashes = :normal if @options.include?(:dashes)
116
+ do_quotes = true if @options.include?(:quotes)
117
+ do_backticks = true if @options.include?(:backticks)
118
+ do_backticks = :both if @options.include?(:allbackticks)
119
+ do_dashes = :normal if @options.include?(:dashes)
109
120
  do_dashes = :oldschool if @options.include?(:oldschool)
110
- do_dashes = :inverted if @options.include?(:inverted)
111
- prevent_breaks = true if @options.include?(:prevent_breaks)
112
- do_ellipses = true if @options.include?(:ellipses)
113
- convert_quotes = true if @options.include?(:convertquotes)
114
- do_stupefy = true if @options.include?(:stupefy)
121
+ do_dashes = :inverted if @options.include?(:inverted)
122
+ prevent_breaks = true if @options.include?(:prevent_breaks)
123
+ do_ellipses = true if @options.include?(:ellipses)
124
+ convert_quotes = true if @options.include?(:convertquotes)
125
+ do_stupefy = true if @options.include?(:stupefy)
115
126
 
116
127
  # Parse the HTML
117
128
  tokens = tokenize
@@ -133,7 +144,7 @@ class RubyPants < String
133
144
  result << token[1]
134
145
  if token[1].end_with? '/>'
135
146
  # ignore self-closing tags
136
- elsif token[1] =~ %r!\A<(/?)(pre|code|kbd|script|style|math)[\s>]!
147
+ elsif token[1] =~ SPECIAL_HTML_TAGS
137
148
  if $1 == '' && ! in_pre
138
149
  in_pre = $2
139
150
  elsif $1 == '/' && $2 == in_pre
@@ -149,36 +160,36 @@ class RubyPants < String
149
160
  unless in_pre
150
161
  t = process_escapes t
151
162
 
152
- t.gsub!(/&quot;/, '"') if convert_quotes
163
+ t.gsub!('&quot;', '"') if convert_quotes
153
164
 
154
165
  if do_dashes
155
- t = educate_dashes t, prevent_breaks if do_dashes == :normal
156
- t = educate_dashes_oldschool t, prevent_breaks if do_dashes == :oldschool
157
- t = educate_dashes_inverted t, prevent_breaks if do_dashes == :inverted
166
+ t = educate_dashes t, prevent_breaks if do_dashes == :normal
167
+ t = educate_dashes_oldschool t, prevent_breaks if do_dashes == :oldschool
168
+ t = educate_dashes_inverted t, prevent_breaks if do_dashes == :inverted
158
169
  end
159
170
 
160
- t = educate_ellipses t, prevent_breaks if do_ellipses
171
+ t = educate_ellipses t, prevent_breaks if do_ellipses
161
172
 
162
173
  # Note: backticks need to be processed before quotes.
163
174
  if do_backticks
164
175
  t = educate_backticks t
165
- t = educate_single_backticks t if do_backticks == :both
176
+ t = educate_single_backticks t if do_backticks == :both
166
177
  end
167
178
 
168
179
  if do_quotes
169
180
  if t == "'"
170
181
  # Special case: single-character ' token
171
- if prev_token_last_char =~ /\S/
172
- t = entity(:single_right_quote)
182
+ if prev_token_last_char =~ NON_WHITESPACE_CHARS
183
+ t = @single_right_quote
173
184
  else
174
- t = entity(:single_left_quote)
185
+ t = @single_left_quote
175
186
  end
176
187
  elsif t == '"'
177
188
  # Special case: single-character " token
178
- if prev_token_last_char =~ /\S/
179
- t = entity(:double_right_quote)
189
+ if prev_token_last_char =~ NON_WHITESPACE_CHARS
190
+ t = @double_right_quote
180
191
  else
181
- t = entity(:double_left_quote)
192
+ t = @double_left_quote
182
193
  end
183
194
  else
184
195
  # Normal case:
@@ -186,7 +197,7 @@ class RubyPants < String
186
197
  end
187
198
  end
188
199
 
189
- t = stupefy_entities t if do_stupefy
200
+ t = stupefy_entities t if do_stupefy
190
201
  end
191
202
 
192
203
  prev_token_last_char = last_char
@@ -227,6 +238,7 @@ class RubyPants < String
227
238
 
228
239
  DOUBLE_DASH = n_of(2, '-')
229
240
  TRIPLE_DASH = n_of(3, '-')
241
+ TRIPLE_DOTS = n_of(3, '.')
230
242
 
231
243
  # Return +str+ replacing all +patt+ with +repl+. If +prevent_breaks+ is true,
232
244
  # then replace spaces preceding +patt+ with a non-breaking space, and if there
@@ -250,7 +262,7 @@ class RubyPants < String
250
262
  # em-dash HTML entity.
251
263
  #
252
264
  def educate_dashes(str, prevent_breaks=false)
253
- educate(str, DOUBLE_DASH, entity(:em_dash), prevent_breaks)
265
+ educate(str, DOUBLE_DASH, @em_dash, prevent_breaks)
254
266
  end
255
267
 
256
268
  # Return the string, with each instance of "<tt>--</tt>" translated to an
@@ -258,8 +270,8 @@ class RubyPants < String
258
270
  # em-dash HTML entity.
259
271
  #
260
272
  def educate_dashes_oldschool(str, prevent_breaks=false)
261
- str = educate(str, TRIPLE_DASH, entity(:em_dash), prevent_breaks)
262
- educate(str, DOUBLE_DASH, entity(:en_dash), prevent_breaks)
273
+ str = educate(str, TRIPLE_DASH, @em_dash, prevent_breaks)
274
+ educate(str, DOUBLE_DASH, @en_dash, prevent_breaks)
263
275
  end
264
276
 
265
277
  # Return the string, with each instance of "<tt>--</tt>" translated
@@ -273,18 +285,20 @@ class RubyPants < String
273
285
  # Aaron Swartz for the idea.)
274
286
  #
275
287
  def educate_dashes_inverted(str, prevent_breaks=false)
276
- str = educate(str, TRIPLE_DASH, entity(:en_dash), prevent_breaks)
277
- educate(str, DOUBLE_DASH, entity(:em_dash), prevent_breaks)
288
+ str = educate(str, TRIPLE_DASH, @en_dash, prevent_breaks)
289
+ educate(str, DOUBLE_DASH, @em_dash, prevent_breaks)
278
290
  end
279
291
 
292
+ SPACED_ELLIPSIS_PATTERN = /(?<!\.|\.[ ])\.[ ]\.[ ]\.(?!\.|[ ]\.)/
293
+
280
294
  # Return the string, with each instance of "<tt>...</tt>" translated
281
295
  # to an ellipsis HTML entity. Also converts the case where there are
282
296
  # spaces between the dots.
283
297
  #
284
298
  def educate_ellipses(str, prevent_breaks=false)
285
- str = educate(str, RubyPants.n_of(3, '.'), entity(:ellipsis), prevent_breaks)
286
- educate(str, /(?<!\.|\.[[:space:]])\.[[:space:]]\.[[:space:]]\.(?!\.|[[:space:]]\.)/,
287
- entity(:ellipsis), prevent_breaks)
299
+ str = educate(str, TRIPLE_DOTS, @ellipsis, prevent_breaks)
300
+ educate(str, SPACED_ELLIPSIS_PATTERN,
301
+ @ellipsis, prevent_breaks)
288
302
  end
289
303
 
290
304
  # Return the string, with "<tt>``backticks''</tt>"-style single quotes
@@ -292,8 +306,8 @@ class RubyPants < String
292
306
  #
293
307
  def educate_backticks(str)
294
308
  str.
295
- gsub("``", entity(:double_left_quote)).
296
- gsub("''", entity(:double_right_quote))
309
+ gsub("``", @double_left_quote).
310
+ gsub("''", @double_right_quote)
297
311
  end
298
312
 
299
313
  # Return the string, with "<tt>`backticks'</tt>"-style single quotes
@@ -301,66 +315,79 @@ class RubyPants < String
301
315
  #
302
316
  def educate_single_backticks(str)
303
317
  str.
304
- gsub("`", entity(:single_left_quote)).
305
- gsub("'", entity(:single_right_quote))
318
+ gsub("`", @single_left_quote).
319
+ gsub("'", @single_right_quote)
306
320
  end
307
321
 
322
+ PUNCT_CLASS = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]'.freeze
323
+ SNGL_QUOT_PUNCT_CASE = /^'(?=#{PUNCT_CLASS}\B)/
324
+ DBLE_QUOT_PUNCT_CASE = /^"(?=#{PUNCT_CLASS}\B)/
325
+
326
+ STARTS_MIXED_QUOTS_WITH_SNGL = /'"(?=\w)/
327
+ STARTS_MIXED_QUOTS_WITH_DBLE = /"'(?=\w)/
328
+
329
+ DECADE_ABBR_CASE = /'(?=\d\ds)/
330
+
331
+ CLOSE_CLASS = '[^\ \t\r\n\\[\{\(\-]'.freeze
332
+ CHAR_LEADS_SNGL_QUOTE = /(#{CLOSE_CLASS})'/
333
+ WHITESPACE_TRAILS_SNGL_QUOTE = /'(\s|s\b|$)/
334
+ CHAR_LEADS_DBLE_QUOTE = /(#{CLOSE_CLASS})"/
335
+ WHITESPACE_TRAILS_DBLE_QUOTE = /"(\s|s\b|$)/
336
+
308
337
  # Return the string, with "educated" curly quote HTML entities.
309
338
  #
310
339
  def educate_quotes(str)
311
- punct_class = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]'
312
-
313
340
  str = str.dup
314
341
 
315
342
  # Special case if the very first character is a quote followed by
316
343
  # punctuation at a non-word-break. Close the quotes by brute
317
344
  # force:
318
- str.gsub!(/^'(?=#{punct_class}\B)/,
319
- entity(:single_right_quote))
320
- str.gsub!(/^"(?=#{punct_class}\B)/,
321
- entity(:double_right_quote))
345
+ str.gsub!(SNGL_QUOT_PUNCT_CASE,
346
+ @single_right_quote)
347
+ str.gsub!(DBLE_QUOT_PUNCT_CASE,
348
+ @double_right_quote)
322
349
 
323
350
  # Special case for double sets of quotes, e.g.:
324
351
  # <p>He said, "'Quoted' words in a larger quote."</p>
325
- str.gsub!(/"'(?=\w)/,
326
- "#{entity(:double_left_quote)}#{entity(:single_left_quote)}")
327
- str.gsub!(/'"(?=\w)/,
328
- "#{entity(:single_left_quote)}#{entity(:double_left_quote)}")
352
+ str.gsub!(STARTS_MIXED_QUOTS_WITH_DBLE,
353
+ "#{@double_left_quote}#{@single_left_quote}")
354
+ str.gsub!(STARTS_MIXED_QUOTS_WITH_SNGL,
355
+ "#{@single_left_quote}#{@double_left_quote}")
329
356
 
330
357
  # Special case for decade abbreviations (the '80s):
331
- str.gsub!(/'(?=\d\ds)/,
332
- entity(:single_right_quote))
358
+ str.gsub!(DECADE_ABBR_CASE,
359
+ @single_right_quote)
333
360
 
334
- close_class = %![^\ \t\r\n\\[\{\(\-]!
335
- dec_dashes = "#{entity(:en_dash)}|#{entity(:em_dash)}"
361
+ dec_dashes = "#{@en_dash}|#{@em_dash}"
362
+ quote_precedent = "[[:space:]]|&nbsp;|--|&[mn]dash;|#{dec_dashes}|&#x201[34];"
336
363
 
337
364
  # Get most opening single quotes:
338
- str.gsub!(/([[:space:]]|&nbsp;|--|&[mn]dash;|#{dec_dashes}|&#x201[34];)'(?=\w)/,
339
- '\1' + entity(:single_left_quote))
365
+ str.gsub!(/(#{quote_precedent})'(?=\w)/,
366
+ '\1' + @single_left_quote)
340
367
 
341
368
  # Single closing quotes:
342
- str.gsub!(/(#{close_class})'/,
343
- '\1' + entity(:single_right_quote))
344
- str.gsub!(/'(\s|s\b|$)/,
345
- entity(:single_right_quote) + '\1')
369
+ str.gsub!(CHAR_LEADS_SNGL_QUOTE,
370
+ '\1' + @single_right_quote)
371
+ str.gsub!(WHITESPACE_TRAILS_SNGL_QUOTE,
372
+ @single_right_quote + '\1')
346
373
 
347
374
  # Any remaining single quotes should be opening ones:
348
- str.gsub!(/'/,
349
- entity(:single_left_quote))
375
+ str.gsub!("'",
376
+ @single_left_quote)
350
377
 
351
378
  # Get most opening double quotes:
352
- str.gsub!(/([[:space:]]|&nbsp;|--|&[mn]dash;|#{dec_dashes}|&#x201[34];)"(?=\w)/,
353
- '\1' + entity(:double_left_quote))
379
+ str.gsub!(/(#{quote_precedent})"(?=\w)/,
380
+ '\1' + @double_left_quote)
354
381
 
355
382
  # Double closing quotes:
356
- str.gsub!(/(#{close_class})"/,
357
- '\1' + entity(:double_right_quote))
358
- str.gsub!(/"(\s|s\b|$)/,
359
- entity(:double_right_quote) + '\1')
383
+ str.gsub!(CHAR_LEADS_DBLE_QUOTE,
384
+ '\1' + @double_right_quote)
385
+ str.gsub!(WHITESPACE_TRAILS_DBLE_QUOTE,
386
+ @double_right_quote + '\1')
360
387
 
361
388
  # Any remaining quotes should be opening ones:
362
- str.gsub!(/"/,
363
- entity(:double_left_quote))
389
+ str.gsub!('"',
390
+ @double_left_quote)
364
391
 
365
392
  str
366
393
  end
@@ -382,12 +409,14 @@ class RubyPants < String
382
409
  :double_right_quote => '"',
383
410
  :ellipsis => '...'
384
411
  }.each do |k,v|
385
- new_str.gsub!(/#{entity(k)}/, v)
412
+ new_str.gsub!(entity(k).to_s, v)
386
413
  end
387
414
 
388
415
  new_str
389
416
  end
390
417
 
418
+ TAG_SOUP = /([^<]*)(<!--.*?-->|<[^>]*>)/m
419
+
391
420
  # Return an array of the tokens comprising the string. Each token is
392
421
  # either a tag (possibly with nested, tags contained therein, such
393
422
  # as <tt><a href="<MTFoo>"></tt>, or a run of text between
@@ -401,14 +430,12 @@ class RubyPants < String
401
430
  # Chad Miller in the Python port of SmartyPants.
402
431
  #
403
432
  def tokenize
404
- tag_soup = /([^<]*)(<!--.*?-->|<[^>]*>)/m
405
-
406
433
  tokens = []
407
434
 
408
435
  prev_end = 0
409
436
 
410
- scan(tag_soup) do
411
- tokens << [:text, $1] if $1 != ""
437
+ scan(TAG_SOUP) do
438
+ tokens << [:text, $1] if $1 != ""
412
439
  tokens << [:tag, $2]
413
440
  prev_end = $~.end(0)
414
441
  end
@@ -1,3 +1,3 @@
1
1
  module RubyPantsVersion
2
- VERSION = "0.7.0"
2
+ VERSION = "0.7.1"
3
3
  end
@@ -11,6 +11,10 @@ class RubyPantsTest < Minitest::Test
11
11
  assert_equal orig, RubyPants.new(str, options, entities).to_html
12
12
  end
13
13
 
14
+ def refute_rp_equal(str, orig, options=[2], entities = {})
15
+ refute_equal orig, RubyPants.new(str, options, entities).to_html
16
+ end
17
+
14
18
  def assert_verbatim(str)
15
19
  assert_rp_equal str, str
16
20
  end
@@ -152,6 +156,28 @@ EOF
152
156
  assert_rp_equal "foo. . . .bar", 'foo. . . .bar', [:ellipses, :prevent_breaks]
153
157
  assert_rp_equal "foo . . . . bar", 'foo . . . . bar', [:ellipses, :prevent_breaks]
154
158
 
159
+ # dots and tab-spaces
160
+ refute_rp_equal "foo. . .bar", 'foo&#8230;bar', [:ellipses]
161
+ refute_rp_equal "foo . . . bar", 'foo &#8230; bar', [:ellipses]
162
+ assert_rp_equal "foo. . . .bar", 'foo. . . .bar', [:ellipses]
163
+ assert_rp_equal "foo . . . . bar", 'foo . . . . bar', [:ellipses]
164
+ # and with :prevent_breaks
165
+ refute_rp_equal "foo. . .bar", 'foo&#8288;&#8230;bar', [:ellipses, :prevent_breaks]
166
+ refute_rp_equal "foo . . . bar", 'foo&nbsp;&#8230; bar', [:ellipses, :prevent_breaks]
167
+ assert_rp_equal "foo. . . .bar", 'foo. . . .bar', [:ellipses, :prevent_breaks]
168
+ assert_rp_equal "foo . . . . bar", 'foo . . . . bar', [:ellipses, :prevent_breaks]
169
+
170
+ # dots and line-breaks
171
+ refute_rp_equal "foo.\n.\n.bar", 'foo&#8230;bar', [:ellipses]
172
+ refute_rp_equal "foo\n.\n.\n.\nbar", "foo\n&#8230;\nbar", [:ellipses]
173
+ assert_rp_equal "foo.\n.\n.\n.bar", "foo.\n.\n.\n.bar", [:ellipses]
174
+ assert_rp_equal "foo\n.\n.\n.\n.\nbar", "foo\n.\n.\n.\n.\nbar", [:ellipses]
175
+ # and with :prevent_breaks
176
+ refute_rp_equal "foo.\n.\n.bar", "foo&#8288;&#8230;bar", [:ellipses, :prevent_breaks]
177
+ refute_rp_equal "foo\n.\n.\n.\nbar", "foo&nbsp;&#8230;\nbar", [:ellipses, :prevent_breaks]
178
+ assert_rp_equal "foo.\n.\n.\n.bar", "foo.\n.\n.\n.bar", [:ellipses, :prevent_breaks]
179
+ assert_rp_equal "foo\n.\n.\n.\n.\nbar", "foo\n.\n.\n.\n.\nbar", [:ellipses, :prevent_breaks]
180
+
155
181
  # nasty ones
156
182
  assert_rp_equal "foo. . ..bar", 'foo. . ..bar', [:ellipses]
157
183
  assert_rp_equal "foo. . ...bar", 'foo. . &#8230;bar', [:ellipses]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubypants
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Gruber
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2018-02-26 00:00:00.000000000 Z
15
+ date: 2019-12-30 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: minitest
@@ -68,8 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0'
70
70
  requirements: []
71
- rubyforge_project:
72
- rubygems_version: 2.6.13
71
+ rubygems_version: 3.0.3
73
72
  signing_key:
74
73
  specification_version: 4
75
74
  summary: RubyPants is a Ruby port of the smart-quotes library SmartyPants.