rubypants 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ class RubyPants
2
+ VERSION = "0.4.0"
3
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require "rubypants/version"
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'rubypants'
9
+ s.version = RubyPants::VERSION
10
+ s.summary = "RubyPants is a Ruby port of the smart-quotes library SmartyPants."
11
+ s.description = <<-EOF
12
+ The original "SmartyPants" is a free web publishing plug-in for
13
+ Movable Type, Blosxom, and BBEdit that easily translates plain ASCII
14
+ punctuation characters into "smart" typographic punctuation HTML
15
+ entities.
16
+ EOF
17
+ s.authors = [
18
+ "John Gruber",
19
+ "Chad Miller",
20
+ "Christian Neukirchen",
21
+ "Jeremy McNevin",
22
+ "Aron Griffis"
23
+ ]
24
+ s.email = 'jeremy@spokoino.net'
25
+ s.files = `git ls-files`.split($/)
26
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
27
+ s.require_paths = ["lib"]
28
+ s.homepage = 'https://github.com/jmcnevin/rubypants'
29
+ s.license = 'MIT'
30
+
31
+ s.add_development_dependency('minitest')
32
+ end
@@ -1,12 +1,12 @@
1
- require 'test/unit'
2
- require 'rubypants'
1
+ require 'minitest/autorun'
2
+ require_relative '../lib/rubypants'
3
3
 
4
4
  # Test EVERYTHING against SmartyPants.pl output!
5
5
 
6
6
 
7
- class TestRubyPants < Test::Unit::TestCase
8
- def assert_rp_equal(str, orig, options=[2])
9
- assert_equal orig, RubyPants.new(str, options).to_html
7
+ class RubyPantsTest < Minitest::Test
8
+ def assert_rp_equal(str, orig, options=[2], entities = {})
9
+ assert_equal orig, RubyPants.new(str, options, entities).to_html
10
10
  end
11
11
 
12
12
  def assert_verbatim(str)
@@ -62,6 +62,9 @@ EOF
62
62
 
63
63
  assert_rp_equal '<b>"</b>', "<b>&#8220;</b>"
64
64
  assert_rp_equal 'foo<b>"</b>', "foo<b>&#8221;</b>"
65
+
66
+ assert_rp_equal "foo\u00a0\"bar\"", "foo\u00a0&#8220;bar&#8221;"
67
+ assert_rp_equal "foo\u00a0'bar'", "foo\u00a0&#8216;bar&#8217;"
65
68
  end
66
69
 
67
70
  def test_dashes
@@ -85,6 +88,11 @@ EOF
85
88
  assert_rp_equal "foo-----bar", 'foo&#8211;&#8212;bar', 3
86
89
  assert_rp_equal "--foo--bar--quux--",
87
90
  '&#8212;foo&#8212;bar&#8212;quux&#8212;', 3
91
+
92
+ # mixed with HTML comments
93
+ assert_verbatim "<!-- comment -->"
94
+ assert_verbatim "<!-- <p>foo bar</p> -->"
95
+ assert_rp_equal "--<!-- -- -->--", '&#8211;<!-- -- -->&#8211;'
88
96
  end
89
97
 
90
98
  def test_ellipses
@@ -159,4 +167,12 @@ EOF
159
167
  assert_rp_equal %q{foo\*bar}, "foo\\*bar"
160
168
  assert_rp_equal %q{foo\&bar}, "foo\\&bar"
161
169
  end
170
+
171
+ def test_modified_entities
172
+ entities = {
173
+ :single_left_quote => 'SHAZAM',
174
+ :single_right_quote => 'POWZAP'
175
+ }
176
+ assert_rp_equal "Testing 'FOO!'", "Testing SHAZAMFOO!POWZAP", [2], entities
177
+ end
162
178
  end
metadata CHANGED
@@ -1,52 +1,75 @@
1
- --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.1
3
- specification_version: 1
1
+ --- !ruby/object:Gem::Specification
4
2
  name: rubypants
5
- version: !ruby/object:Gem::Version
6
- version: 0.2.0
7
- date: 2004-11-15
8
- summary: RubyPants is a Ruby port of the smart-quotes library SmartyPants.
9
- require_paths:
10
- - "."
11
- author: Christian Neukirchen
12
- email: chneukirchen@gmail.com
13
- homepage: http://www.kronavita.de/chris/blog/projects/rubypants.html
14
- rubyforge_project:
15
- description: "RubyPants is a Ruby port of the smart-quotes library SmartyPants. The original
16
- \"SmartyPants\" is a free web publishing plug-in for Movable Type, Blosxom, and
17
- BBEdit that easily translates plain ASCII punctuation characters into \"smart\"
18
- typographic punctuation HTML entities."
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - John Gruber
8
+ - Chad Miller
9
+ - Christian Neukirchen
10
+ - Jeremy McNevin
11
+ - Aron Griffis
19
12
  autorequire:
20
- default_executable:
21
13
  bindir: bin
22
- has_rdoc: false
23
- required_ruby_version: !ruby/object:Gem::Version::Requirement
24
- requirements:
25
- -
26
- - ">"
27
- - !ruby/object:Gem::Version
28
- version: 0.0.0
29
- version:
30
- platform: ruby
31
- files:
32
- - install.rb
33
- - rubypants.rb
34
- - test_rubypants.rb
35
- - README
36
- - Rakefile
37
- test_files:
38
- - test_rubypants.rb
39
- rdoc_options:
40
- - "--main"
41
- - README
42
- - "--line-numbers"
43
- - "--inline-source"
44
- - "--all"
45
- - "--exclude"
46
- - test_rubypants.rb
47
- extra_rdoc_files:
48
- - README
14
+ cert_chain: []
15
+ date: 2016-08-06 00:00:00.000000000 Z
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: minitest
19
+ requirement: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: '0'
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ description: |
32
+ The original "SmartyPants" is a free web publishing plug-in for
33
+ Movable Type, Blosxom, and BBEdit that easily translates plain ASCII
34
+ punctuation characters into "smart" typographic punctuation HTML
35
+ entities.
36
+ email: jeremy@spokoino.net
49
37
  executables: []
50
38
  extensions: []
39
+ extra_rdoc_files: []
40
+ files:
41
+ - ".gitignore"
42
+ - LICENSE.rdoc
43
+ - README.rdoc
44
+ - Rakefile
45
+ - lib/rubypants.rb
46
+ - lib/rubypants/core.rb
47
+ - lib/rubypants/version.rb
48
+ - rubypants.gemspec
49
+ - test/rubypants_test.rb
50
+ homepage: https://github.com/jmcnevin/rubypants
51
+ licenses:
52
+ - MIT
53
+ metadata: {}
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
51
68
  requirements: []
52
- dependencies: []
69
+ rubyforge_project:
70
+ rubygems_version: 2.4.8
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: RubyPants is a Ruby port of the smart-quotes library SmartyPants.
74
+ test_files:
75
+ - test/rubypants_test.rb
data/install.rb DELETED
@@ -1,9 +0,0 @@
1
- # Install RubyPants.
2
-
3
- require "rbconfig"
4
- require "fileutils"
5
-
6
- source = "rubypants.rb"
7
- dest = File.join(Config::CONFIG["sitelibdir"], source)
8
-
9
- FileUtils.install(source, dest, :mode => 0644, :verbose => true)
@@ -1,490 +0,0 @@
1
- #
2
- # = RubyPants -- SmartyPants ported to Ruby
3
- #
4
- # Ported by Christian Neukirchen <mailto:chneukirchen@gmail.com>
5
- # Copyright (C) 2004 Christian Neukirchen
6
- #
7
- # Incooporates ideas, comments and documentation by Chad Miller
8
- # Copyright (C) 2004 Chad Miller
9
- #
10
- # Original SmartyPants by John Gruber
11
- # Copyright (C) 2003 John Gruber
12
- #
13
-
14
- #
15
- # = RubyPants -- SmartyPants ported to Ruby
16
- #
17
- # == Synopsis
18
- #
19
- # RubyPants is a Ruby port of the smart-quotes library SmartyPants.
20
- #
21
- # The original "SmartyPants" is a free web publishing plug-in for
22
- # Movable Type, Blosxom, and BBEdit that easily translates plain ASCII
23
- # punctuation characters into "smart" typographic punctuation HTML
24
- # entities.
25
- #
26
- #
27
- # == Description
28
- #
29
- # RubyPants can perform the following transformations:
30
- #
31
- # * Straight quotes (<tt>"</tt> and <tt>'</tt>) into "curly" quote
32
- # HTML entities
33
- # * Backticks-style quotes (<tt>``like this''</tt>) into "curly" quote
34
- # HTML entities
35
- # * Dashes (<tt>--</tt> and <tt>---</tt>) into en- and em-dash
36
- # entities
37
- # * Three consecutive dots (<tt>...</tt> or <tt>. . .</tt>) into an
38
- # ellipsis entity
39
- #
40
- # This means you can write, edit, and save your posts using plain old
41
- # ASCII straight quotes, plain dashes, and plain dots, but your
42
- # published posts (and final HTML output) will appear with smart
43
- # quotes, em-dashes, and proper ellipses.
44
- #
45
- # RubyPants does not modify characters within <tt><pre></tt>,
46
- # <tt><code></tt>, <tt><kbd></tt>, <tt><math></tt> or
47
- # <tt><script></tt> tag blocks. Typically, these tags are used to
48
- # display text where smart quotes and other "smart punctuation" would
49
- # not be appropriate, such as source code or example markup.
50
- #
51
- #
52
- # == Backslash Escapes
53
- #
54
- # If you need to use literal straight quotes (or plain hyphens and
55
- # periods), RubyPants accepts the following backslash escape sequences
56
- # to force non-smart punctuation. It does so by transforming the
57
- # escape sequence into a decimal-encoded HTML entity:
58
- #
59
- # \\ \" \' \. \- \`
60
- #
61
- # This is useful, for example, when you want to use straight quotes as
62
- # foot and inch marks: 6'2" tall; a 17" iMac. (Use <tt>6\'2\"</tt>
63
- # resp. <tt>17\"</tt>.)
64
- #
65
- #
66
- # == Algorithmic Shortcomings
67
- #
68
- # One situation in which quotes will get curled the wrong way is when
69
- # apostrophes are used at the start of leading contractions. For
70
- # example:
71
- #
72
- # 'Twas the night before Christmas.
73
- #
74
- # In the case above, RubyPants will turn the apostrophe into an
75
- # opening single-quote, when in fact it should be a closing one. I
76
- # don't think this problem can be solved in the general case--every
77
- # word processor I've tried gets this wrong as well. In such cases,
78
- # it's best to use the proper HTML entity for closing single-quotes
79
- # ("<tt>&#8217;</tt>") by hand.
80
- #
81
- #
82
- # == Bugs
83
- #
84
- # To file bug reports or feature requests (except see above) please
85
- # send email to: mailto:chneukirchen@gmail.com
86
- #
87
- # If the bug involves quotes being curled the wrong way, please send
88
- # example text to illustrate.
89
- #
90
- #
91
- # == Authors
92
- #
93
- # John Gruber did all of the hard work of writing this software in
94
- # Perl for Movable Type and almost all of this useful documentation.
95
- # Chad Miller ported it to Python to use with Pyblosxom.
96
- #
97
- # Christian Neukirchen provided the Ruby port, as a general-purpose
98
- # library that follows the *Cloth API.
99
- #
100
- #
101
- # == Copyright and License
102
- #
103
- # === SmartyPants license:
104
- #
105
- # Copyright (c) 2003 John Gruber
106
- # (http://daringfireball.net)
107
- # All rights reserved.
108
- #
109
- # Redistribution and use in source and binary forms, with or without
110
- # modification, are permitted provided that the following conditions
111
- # are met:
112
- #
113
- # * Redistributions of source code must retain the above copyright
114
- # notice, this list of conditions and the following disclaimer.
115
- #
116
- # * Redistributions in binary form must reproduce the above copyright
117
- # notice, this list of conditions and the following disclaimer in
118
- # the documentation and/or other materials provided with the
119
- # distribution.
120
- #
121
- # * Neither the name "SmartyPants" nor the names of its contributors
122
- # may be used to endorse or promote products derived from this
123
- # software without specific prior written permission.
124
- #
125
- # This software is provided by the copyright holders and contributors
126
- # "as is" and any express or implied warranties, including, but not
127
- # limited to, the implied warranties of merchantability and fitness
128
- # for a particular purpose are disclaimed. In no event shall the
129
- # copyright owner or contributors be liable for any direct, indirect,
130
- # incidental, special, exemplary, or consequential damages (including,
131
- # but not limited to, procurement of substitute goods or services;
132
- # loss of use, data, or profits; or business interruption) however
133
- # caused and on any theory of liability, whether in contract, strict
134
- # liability, or tort (including negligence or otherwise) arising in
135
- # any way out of the use of this software, even if advised of the
136
- # possibility of such damage.
137
- #
138
- # === RubyPants license
139
- #
140
- # RubyPants is a derivative work of SmartyPants and smartypants.py.
141
- #
142
- # Redistribution and use in source and binary forms, with or without
143
- # modification, are permitted provided that the following conditions
144
- # are met:
145
- #
146
- # * Redistributions of source code must retain the above copyright
147
- # notice, this list of conditions and the following disclaimer.
148
- #
149
- # * Redistributions in binary form must reproduce the above copyright
150
- # notice, this list of conditions and the following disclaimer in
151
- # the documentation and/or other materials provided with the
152
- # distribution.
153
- #
154
- # This software is provided by the copyright holders and contributors
155
- # "as is" and any express or implied warranties, including, but not
156
- # limited to, the implied warranties of merchantability and fitness
157
- # for a particular purpose are disclaimed. In no event shall the
158
- # copyright owner or contributors be liable for any direct, indirect,
159
- # incidental, special, exemplary, or consequential damages (including,
160
- # but not limited to, procurement of substitute goods or services;
161
- # loss of use, data, or profits; or business interruption) however
162
- # caused and on any theory of liability, whether in contract, strict
163
- # liability, or tort (including negligence or otherwise) arising in
164
- # any way out of the use of this software, even if advised of the
165
- # possibility of such damage.
166
- #
167
- #
168
- # == Links
169
- #
170
- # John Gruber:: http://daringfireball.net
171
- # SmartyPants:: http://daringfireball.net/projects/smartypants
172
- #
173
- # Chad Miller:: http://web.chad.org
174
- #
175
- # Christian Neukirchen:: http://kronavita.de/chris
176
- #
177
-
178
-
179
- class RubyPants < String
180
- VERSION = "0.2"
181
-
182
- # Create a new RubyPants instance with the text in +string+.
183
- #
184
- # Allowed elements in the options array:
185
- #
186
- # 0 :: do nothing
187
- # 1 :: enable all, using only em-dash shortcuts
188
- # 2 :: enable all, using old school en- and em-dash shortcuts (*default*)
189
- # 3 :: enable all, using inverted old school en and em-dash shortcuts
190
- # -1 :: stupefy (translate HTML entities to their ASCII-counterparts)
191
- #
192
- # If you don't like any of these defaults, you can pass symbols to change
193
- # RubyPants' behavior:
194
- #
195
- # <tt>:quotes</tt> :: quotes
196
- # <tt>:backticks</tt> :: backtick quotes (``double'' only)
197
- # <tt>:allbackticks</tt> :: backtick quotes (``double'' and `single')
198
- # <tt>:dashes</tt> :: dashes
199
- # <tt>:oldschool</tt> :: old school dashes
200
- # <tt>:inverted</tt> :: inverted old school dashes
201
- # <tt>:ellipses</tt> :: ellipses
202
- # <tt>:convertquotes</tt> :: convert <tt>&quot;</tt> entities to
203
- # <tt>"</tt> for Dreamweaver users
204
- # <tt>:stupefy</tt> :: translate RubyPants HTML entities
205
- # to their ASCII counterparts.
206
- #
207
- def initialize(string, options=[2])
208
- super string
209
- @options = [*options]
210
- end
211
-
212
- # Apply SmartyPants transformations.
213
- def to_html
214
- do_quotes = do_backticks = do_dashes = do_ellipses = do_stupify = nil
215
- convert_quotes = false
216
-
217
- if @options.include? 0
218
- # Do nothing.
219
- return self
220
- elsif @options.include? 1
221
- # Do everything, turn all options on.
222
- do_quotes = do_backticks = do_ellipses = true
223
- do_dashes = :normal
224
- elsif @options.include? 2
225
- # Do everything, turn all options on, use old school dash shorthand.
226
- do_quotes = do_backticks = do_ellipses = true
227
- do_dashes = :oldschool
228
- elsif @options.include? 3
229
- # Do everything, turn all options on, use inverted old school
230
- # dash shorthand.
231
- do_quotes = do_backticks = do_ellipses = true
232
- do_dashes = :inverted
233
- elsif @options.include?(-1)
234
- do_stupefy = true
235
- else
236
- do_quotes = @options.include? :quotes
237
- do_backticks = @options.include? :backticks
238
- do_backticks = :both if @options.include? :allbackticks
239
- do_dashes = :normal if @options.include? :dashes
240
- do_dashes = :oldschool if @options.include? :oldschool
241
- do_dashes = :inverted if @options.include? :inverted
242
- do_ellipses = @options.include? :ellipses
243
- convert_quotes = @options.include? :convertquotes
244
- do_stupefy = @options.include? :stupefy
245
- end
246
-
247
- # Parse the HTML
248
- tokens = tokenize
249
-
250
- # Keep track of when we're inside <pre> or <code> tags.
251
- in_pre = false
252
-
253
- # Here is the result stored in.
254
- result = ""
255
-
256
- # This is a cheat, used to get some context for one-character
257
- # tokens that consist of just a quote char. What we do is remember
258
- # the last character of the previous text token, to use as context
259
- # to curl single- character quote tokens correctly.
260
- prev_token_last_char = nil
261
-
262
- tokens.each { |token|
263
- if token.first == :tag
264
- result << token[1]
265
- if token[1] =~ %r!<(/?)(?:pre|code|kbd|script|math)[\s>]!
266
- in_pre = ($1 != "/") # Opening or closing tag?
267
- end
268
- else
269
- t = token[1]
270
-
271
- # Remember last char of this token before processing.
272
- last_char = t[-1].chr
273
-
274
- unless in_pre
275
- t = process_escapes t
276
-
277
- t.gsub!(/&quot;/, '"') if convert_quotes
278
-
279
- if do_dashes
280
- t = educate_dashes t if do_dashes == :normal
281
- t = educate_dashes_oldschool t if do_dashes == :oldschool
282
- t = educate_dashes_inverted t if do_dashes == :inverted
283
- end
284
-
285
- t = educate_ellipses t if do_ellipses
286
-
287
- # Note: backticks need to be processed before quotes.
288
- if do_backticks
289
- t = educate_backticks t
290
- t = educate_single_backticks t if do_backticks == :both
291
- end
292
-
293
- if do_quotes
294
- if t == "'"
295
- # Special case: single-character ' token
296
- if prev_token_last_char =~ /\S/
297
- t = "&#8217;"
298
- else
299
- t = "&#8216;"
300
- end
301
- elsif t == '"'
302
- # Special case: single-character " token
303
- if prev_token_last_char =~ /\S/
304
- t = "&#8221;"
305
- else
306
- t = "&#8220;"
307
- end
308
- else
309
- # Normal case:
310
- t = educate_quotes t
311
- end
312
- end
313
-
314
- t = stupefy_entities t if do_stupefy
315
- end
316
-
317
- prev_token_last_char = last_char
318
- result << t
319
- end
320
- }
321
-
322
- # Done
323
- result
324
- end
325
-
326
- protected
327
-
328
- # Return the string, with after processing the following backslash
329
- # escape sequences. This is useful if you want to force a "dumb" quote
330
- # or other character to appear.
331
- #
332
- # Escaped are:
333
- # \\ \" \' \. \- \`
334
- #
335
- def process_escapes(str)
336
- str.gsub('\\\\', '&#92;').
337
- gsub('\"', '&#34;').
338
- gsub("\\\'", '&#39;').
339
- gsub('\.', '&#46;').
340
- gsub('\-', '&#45;').
341
- gsub('\`', '&#96;')
342
- end
343
-
344
- # The string, with each instance of "<tt>--</tt>" translated to an
345
- # em-dash HTML entity.
346
- #
347
- def educate_dashes(str)
348
- str.gsub(/--/, '&#8212;')
349
- end
350
-
351
- # The string, with each instance of "<tt>--</tt>" translated to an
352
- # en-dash HTML entity, and each "<tt>---</tt>" translated to an
353
- # em-dash HTML entity.
354
- #
355
- def educate_dashes_oldschool(str)
356
- str.gsub(/---/, '&#8212;').gsub(/--/, '&#8211;')
357
- end
358
-
359
- # Return the string, with each instance of "<tt>--</tt>" translated
360
- # to an em-dash HTML entity, and each "<tt>---</tt>" translated to
361
- # an en-dash HTML entity. Two reasons why: First, unlike the en- and
362
- # em-dash syntax supported by +educate_dashes_oldschool+, it's
363
- # compatible with existing entries written before SmartyPants 1.1,
364
- # back when "<tt>--</tt>" was only used for em-dashes. Second,
365
- # em-dashes are more common than en-dashes, and so it sort of makes
366
- # sense that the shortcut should be shorter to type. (Thanks to
367
- # Aaron Swartz for the idea.)
368
- #
369
- def educate_dashes_inverted(str)
370
- str.gsub(/---/, '&#8211;').gsub(/--/, '&#8212;')
371
- end
372
-
373
- # Return the string, with each instance of "<tt>...</tt>" translated
374
- # to an ellipsis HTML entity. Also converts the case where there are
375
- # spaces between the dots.
376
- #
377
- def educate_ellipses(str)
378
- str.gsub('...', '&#8230;').gsub('. . .', '&#8230;')
379
- end
380
-
381
- # Return the string, with "<tt>``backticks''</tt>"-style single quotes
382
- # translated into HTML curly quote entities.
383
- #
384
- def educate_backticks(str)
385
- str.gsub("``", '&#8220;').gsub("''", '&#8221;')
386
- end
387
-
388
- # Return the string, with "<tt>`backticks'</tt>"-style single quotes
389
- # translated into HTML curly quote entities.
390
- #
391
- def educate_single_backticks(str)
392
- str.gsub("`", '&#8216;').gsub("'", '&#8217;')
393
- end
394
-
395
- # Return the string, with "educated" curly quote HTML entities.
396
- #
397
- def educate_quotes(str)
398
- punct_class = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]'
399
-
400
- str = str.dup
401
-
402
- # Special case if the very first character is a quote followed by
403
- # punctuation at a non-word-break. Close the quotes by brute
404
- # force:
405
- str.gsub!(/^'(?=#{punct_class}\B)/, '&#8217;')
406
- str.gsub!(/^"(?=#{punct_class}\B)/, '&#8221;')
407
-
408
- # Special case for double sets of quotes, e.g.:
409
- # <p>He said, "'Quoted' words in a larger quote."</p>
410
- str.gsub!(/"'(?=\w)/, '&#8220;&#8216;')
411
- str.gsub!(/'"(?=\w)/, '&#8216;&#8220;')
412
-
413
- # Special case for decade abbreviations (the '80s):
414
- str.gsub!(/'(?=\d\ds)/, '&#8217;')
415
-
416
- close_class = %![^\ \t\r\n\\[\{\(\-]!
417
- dec_dashes = '&#8211;|&#8212;'
418
-
419
- # Get most opening single quotes:
420
- str.gsub!(/(\s|&nbsp;|--|&[mn]dash;|#{dec_dashes}|&#x201[34];)'(?=\w)/,
421
- '\1&#8216;')
422
- # Single closing quotes:
423
- str.gsub!(/(#{close_class})'/, '\1&#8217;')
424
- str.gsub!(/'(\s|s\b|$)/, '&#8217;\1')
425
- # Any remaining single quotes should be opening ones:
426
- str.gsub!(/'/, '&#8216;')
427
-
428
- # Get most opening double quotes:
429
- str.gsub!(/(\s|&nbsp;|--|&[mn]dash;|#{dec_dashes}|&#x201[34];)"(?=\w)/,
430
- '\1&#8220;')
431
- # Double closing quotes:
432
- str.gsub!(/(#{close_class})"/, '\1&#8221;')
433
- str.gsub!(/"(\s|s\b|$)/, '&#8221;\1')
434
- # Any remaining quotes should be opening ones:
435
- str.gsub!(/"/, '&#8220;')
436
-
437
- str
438
- end
439
-
440
- # Return the string, with each RubyPants HTML entity translated to
441
- # its ASCII counterpart.
442
- #
443
- # Note: This is not reversible (but exactly the same as in SmartyPants)
444
- #
445
- def stupefy_entities(str)
446
- str.
447
- gsub(/&#8211;/, '-'). # en-dash
448
- gsub(/&#8212;/, '--'). # em-dash
449
-
450
- gsub(/&#8216;/, "'"). # open single quote
451
- gsub(/&#8217;/, "'"). # close single quote
452
-
453
- gsub(/&#8220;/, '"'). # open double quote
454
- gsub(/&#8221;/, '"'). # close double quote
455
-
456
- gsub(/&#8230;/, '...') # ellipsis
457
- end
458
-
459
- # Return an array of the tokens comprising the string. Each token is
460
- # either a tag (possibly with nested, tags contained therein, such
461
- # as <tt><a href="<MTFoo>"></tt>, or a run of text between
462
- # tags. Each element of the array is a two-element array; the first
463
- # is either :tag or :text; the second is the actual value.
464
- #
465
- # Based on the <tt>_tokenize()</tt> subroutine from Brad Choate's
466
- # MTRegex plugin. <http://www.bradchoate.com/past/mtregex.php>
467
- #
468
- # This is actually the easier variant using tag_soup, as used by
469
- # Chad Miller in the Python port of SmartyPants.
470
- #
471
- def tokenize
472
- tag_soup = /([^<]*)(<[^>]*>)/
473
-
474
- tokens = []
475
-
476
- prev_end = 0
477
- scan(tag_soup) {
478
- tokens << [:text, $1] if $1 != ""
479
- tokens << [:tag, $2]
480
-
481
- prev_end = $~.end(0)
482
- }
483
-
484
- if prev_end < size
485
- tokens << [:text, self[prev_end..-1]]
486
- end
487
-
488
- tokens
489
- end
490
- end