WikiCreole 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +9 -0
- data/Rakefile +6 -0
- data/lib/wiki_creole.rb +180 -241
- data/test/profiling.rb +22 -0
- data/test/test_all.rb +9 -13
- data/test/test_nested_lists.html +10 -0
- data/test/test_nested_lists.markup +4 -0
- metadata +15 -12
data/Changelog
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
2009-02-05 (0.1.3)
|
2
|
+
* nono on github made the Ruby more idiomatic and fixed a section
|
3
|
+
which had eluded Gordon earlier. He also added profiling, which
|
4
|
+
can be run using "rake profiling" then opening profiling.html
|
5
|
+
in a browser.
|
6
|
+
* Raphael Knaus found an infinite loop error while parsing a nested
|
7
|
+
list. He provided a quick fix, but both he and I are dissatisfied
|
8
|
+
by the current workaround.
|
9
|
+
|
1
10
|
2008-12-12 (0.1.2)
|
2
11
|
* Made the usage more clear by adding the "require 'rubygems'" before
|
3
12
|
the require 'wiki_creole' command
|
data/Rakefile
CHANGED
@@ -14,4 +14,10 @@ Rake::TestTask.new(:test_all) do |t|
|
|
14
14
|
t.libs << 'lib'
|
15
15
|
t.warning = true
|
16
16
|
t.test_files = FileList['test/test_all.rb']
|
17
|
+
end
|
18
|
+
|
19
|
+
Rake::TestTask.new(:profiling) do |t|
|
20
|
+
t.libs << 'lib'
|
21
|
+
t.warning = true
|
22
|
+
t.test_files = FileList['test/profiling.rb']
|
17
23
|
end
|
data/lib/wiki_creole.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
# WikiCreole implements the Wiki Creole markup language,
|
1
|
+
# WikiCreole implements the Wiki Creole markup language,
|
2
2
|
# version 1.0, as described at http://www.wikicreole.org. It
|
3
3
|
# reads Creole 1.0 markup and returns XHTML.
|
4
4
|
#
|
5
5
|
# Author:: Gordon McCreight (mailto:wikicreole.to.gordon@mccreight.com)
|
6
6
|
# Copyright:: Copyright (c) 2008 Gordon McCreight
|
7
7
|
# License:: Distributes under the same terms as Ruby (see the LICENSE file)
|
8
|
-
# Version:: 0.1.
|
9
|
-
# Date::
|
8
|
+
# Version:: 0.1.3
|
9
|
+
# Date:: 2009-02-05
|
10
10
|
#
|
11
11
|
# == Synopsis
|
12
12
|
# Most likely you'll just want to do:
|
@@ -18,7 +18,7 @@
|
|
18
18
|
#
|
19
19
|
# == Official Markup
|
20
20
|
#
|
21
|
-
# Here is a summary of the official Creole 1.0 markup
|
21
|
+
# Here is a summary of the official Creole 1.0 markup
|
22
22
|
# elements. See http://www.wikicreole.org for the full
|
23
23
|
# details.
|
24
24
|
#
|
@@ -62,7 +62,7 @@
|
|
62
62
|
# ~** not bold ** -> ** not bold **
|
63
63
|
# tilde: ~~ -> tilde: ~
|
64
64
|
#
|
65
|
-
# Paragraphs are separated by other blocks and blank lines.
|
65
|
+
# Paragraphs are separated by other blocks and blank lines.
|
66
66
|
# Inline markup can usually be combined, overlapped, etc. List
|
67
67
|
# items and plugin text can span lines.
|
68
68
|
#
|
@@ -104,7 +104,7 @@
|
|
104
104
|
# converter which can be found here:
|
105
105
|
# http://search.cpan.org/~jburnett/Text-WikiCreole/
|
106
106
|
# He, in turn, acknowledges the Document::Parser perl module.
|
107
|
-
#
|
107
|
+
#
|
108
108
|
# Also, some of the tests are taken from Lars Christensen's implementation of
|
109
109
|
# the Creole parser. You can find his code at:
|
110
110
|
# http://github.com/larsch/creole/tree/master
|
@@ -113,83 +113,67 @@
|
|
113
113
|
# http://www.wikicreole.org/
|
114
114
|
|
115
115
|
class WikiCreole
|
116
|
-
|
116
|
+
|
117
117
|
# Reads Creole 1.0 markup and return XHTML.
|
118
118
|
#
|
119
119
|
# xhtml = WikiCreole.creole_parse(wiki_creole_markup)
|
120
120
|
def self.creole_parse(s)
|
121
|
-
return ""
|
122
|
-
return "" if s.
|
121
|
+
return "" unless String === s
|
122
|
+
return "" if s.empty?
|
123
123
|
|
124
124
|
init
|
125
|
-
|
125
|
+
parse(s, :top)
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
# Creole 1.0 supports two plugin syntaxes: << plugin content >> and
|
129
129
|
# <<< plugin content >>>
|
130
|
-
#
|
131
|
-
# Write a function that receives the text between the <<>>
|
132
|
-
# delimiters (not including the delimiters) and
|
133
|
-
# returns the text to be displayed. For example, here is a
|
130
|
+
#
|
131
|
+
# Write a function that receives the text between the <<>>
|
132
|
+
# delimiters (not including the delimiters) and
|
133
|
+
# returns the text to be displayed. For example, here is a
|
134
134
|
# simple plugin that converts plugin text to uppercase:
|
135
135
|
#
|
136
|
-
#
|
137
|
-
# s.upcase!
|
138
|
-
# s
|
139
|
-
# }
|
140
|
-
# WikiCreole.creole_plugin(uppercase)
|
136
|
+
# WikiCreole.creole_plugin {|s| s.upcase }
|
141
137
|
#
|
142
138
|
# If you do not register a plugin function, plugin markup will be left
|
143
139
|
# as is, including the surrounding << >>.
|
144
|
-
def self.creole_plugin(
|
145
|
-
@plugin_function =
|
140
|
+
def self.creole_plugin(&blk)
|
141
|
+
@plugin_function = blk
|
146
142
|
end
|
147
143
|
|
148
144
|
# You may wish to customize [[ links ]], such as to prefix a hostname,
|
149
145
|
# port, etc.
|
150
146
|
#
|
151
147
|
# Write a function, similar to the plugin function, which receives the
|
152
|
-
# URL part of the link (with leading and trailing whitespace stripped)
|
153
|
-
# and returns the customized link. For example, to prepend
|
148
|
+
# URL part of the link (with leading and trailing whitespace stripped)
|
149
|
+
# and returns the customized link. For example, to prepend
|
154
150
|
# http://my.domain/
|
155
151
|
# to pagename:
|
156
152
|
#
|
157
|
-
#
|
158
|
-
|
159
|
-
|
160
|
-
# }
|
161
|
-
# WikiCreole.creole_link(mylink)
|
162
|
-
def self.creole_link(func)
|
163
|
-
@link_function = func
|
153
|
+
# WikiCreole.creole_link {|s| "http://my.domain/#{s}" }
|
154
|
+
def self.creole_link(&blk)
|
155
|
+
@link_function = blk
|
164
156
|
end
|
165
|
-
|
157
|
+
|
166
158
|
# Same purpose as creole_link, but for "bare" link markup. Bare links are
|
167
159
|
# the links which are in the text but not surrounded by brackets.
|
168
160
|
#
|
169
|
-
#
|
170
|
-
|
171
|
-
|
172
|
-
# }
|
173
|
-
# WikiCreole.creole_barelink(mybarelink)
|
174
|
-
def self.creole_barelink(func)
|
175
|
-
@barelink_function = func
|
161
|
+
# WikiCreole.creole_barelink {|s| "#{s}.html" }
|
162
|
+
def self.creole_barelink(&blk)
|
163
|
+
@barelink_function = blk
|
176
164
|
end
|
177
165
|
|
178
166
|
# Same purpose as creole_link, but for image URLs.
|
179
167
|
#
|
180
|
-
#
|
181
|
-
|
182
|
-
|
183
|
-
# }
|
184
|
-
# WikiCreole.creole_img(myimg)
|
185
|
-
def self.creole_img(func)
|
186
|
-
@img_function = func
|
168
|
+
# WikiCreole.creole_img {|s| "http://my.domain/#{s}" }
|
169
|
+
def self.creole_img(&blk)
|
170
|
+
@img_function = blk
|
187
171
|
end
|
188
|
-
|
172
|
+
|
189
173
|
# If you want complete control over links, rather than just modifying
|
190
174
|
# the URL, register your link markup function with WikiCreole.creole_link()
|
191
175
|
# as above and then call creole_customlinks(). Now your function will receive
|
192
|
-
# the entire link markup chunk, such as <tt>[[ some_wiki_page | page description ]]</tt>
|
176
|
+
# the entire link markup chunk, such as <tt>[[ some_wiki_page | page description ]]</tt>
|
193
177
|
# and must return HTML.
|
194
178
|
#
|
195
179
|
# This has no effect on "bare" link markup, such as
|
@@ -200,10 +184,8 @@ class WikiCreole
|
|
200
184
|
@@chunks_hash[:link][:open] = ""
|
201
185
|
@@chunks_hash[:link][:close] = ""
|
202
186
|
@@chunks_hash[:link].delete(:contains)
|
203
|
-
@@chunks_hash[:link][:filter] = Proc.new {|s|
|
204
|
-
if @link_function
|
205
|
-
s = @link_function.call(s)
|
206
|
-
end
|
187
|
+
@@chunks_hash[:link][:filter] = Proc.new {|s|
|
188
|
+
s = @link_function.call(s) if @link_function
|
207
189
|
s
|
208
190
|
}
|
209
191
|
end
|
@@ -212,10 +194,8 @@ class WikiCreole
|
|
212
194
|
def self.creole_custombarelinks
|
213
195
|
@@chunks_hash[:ilink][:open] = ""
|
214
196
|
@@chunks_hash[:ilink][:close] = ""
|
215
|
-
@@chunks_hash[:ilink][:filter] = Proc.new {|s|
|
216
|
-
if @barelink_function
|
217
|
-
s = @barelink_function.call(s)
|
218
|
-
end
|
197
|
+
@@chunks_hash[:ilink][:filter] = Proc.new {|s|
|
198
|
+
s = @barelink_function.call(s) if @barelink_function
|
219
199
|
s
|
220
200
|
}
|
221
201
|
end
|
@@ -225,28 +205,23 @@ class WikiCreole
|
|
225
205
|
@@chunks_hash[:img][:open] = ""
|
226
206
|
@@chunks_hash[:img][:close] = ""
|
227
207
|
@@chunks_hash[:img].delete(:contains)
|
228
|
-
@@chunks_hash[:img][:filter] = Proc.new {|s|
|
229
|
-
if @img_function
|
230
|
-
s = @img_function.call(s)
|
231
|
-
end
|
208
|
+
@@chunks_hash[:img][:filter] = Proc.new {|s|
|
209
|
+
s = @img_function.call(s) if @img_function
|
232
210
|
s
|
233
211
|
}
|
234
212
|
end
|
235
|
-
|
213
|
+
|
236
214
|
# You may wish to customize the opening and/or closing tags
|
237
215
|
# for the various bits of Creole markup. For example, to
|
238
216
|
# assign a CSS class to list items:
|
239
217
|
# WikiCreole.creole_tag(:li, :open, "<li class=myclass>")
|
240
218
|
#
|
241
|
-
# Or to see all current tags:
|
242
|
-
# puts WikiCreole.creole_tag()
|
243
|
-
#
|
244
219
|
# The tags that may be of interest are:
|
245
220
|
#
|
246
221
|
# br dd dl
|
247
222
|
# dt em h1
|
248
223
|
# h2 h3 h4
|
249
|
-
# h5 h6 hr
|
224
|
+
# h5 h6 hr
|
250
225
|
# ilink img inowiki
|
251
226
|
# ip li link
|
252
227
|
# mono nowiki ol
|
@@ -258,71 +233,68 @@ class WikiCreole
|
|
258
233
|
# Those should be self-explanatory, except for inowiki (inline nowiki),
|
259
234
|
# ilink (bare links, e.g.
|
260
235
|
# http://www.cpan.org
|
261
|
-
# and ip (indented paragraph).
|
262
|
-
def self.creole_tag(
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
type =
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
else
|
284
|
-
return if ! type
|
285
|
-
type = type.to_sym
|
286
|
-
return if type != :open && type != :close
|
287
|
-
return if !@@chunks_hash.has_key?(tag)
|
288
|
-
@@chunks_hash[tag][type] = text ? text : ""
|
236
|
+
# ) and ip (indented paragraph).
|
237
|
+
def self.creole_tag(tag, type, text="")
|
238
|
+
type = type.to_sym
|
239
|
+
return unless [:open, :close].include?(type)
|
240
|
+
return unless @@chunks_hash.has_key?(tag)
|
241
|
+
@@chunks_hash[tag][type] = text
|
242
|
+
end
|
243
|
+
|
244
|
+
# See all current tags:
|
245
|
+
# puts WikiCreole.creole_tags()
|
246
|
+
#
|
247
|
+
def self.creole_tags
|
248
|
+
tags = []
|
249
|
+
keys = @@chunks_hash.keys.collect{|x| x.to_s}.sort
|
250
|
+
keys.each do |key|
|
251
|
+
key = key.to_sym
|
252
|
+
o = @@chunks_hash[key][:open] || ""
|
253
|
+
c = @@chunks_hash[key][:close] || ""
|
254
|
+
next if o !~ /</m
|
255
|
+
o, c = [o, c].map {|x| x.gsub(/\n/m,"\\n") }
|
256
|
+
this_tag = "#{key}: open(#{o}) close(#{c})\n"
|
257
|
+
tags << this_tag
|
289
258
|
end
|
259
|
+
tags.join
|
290
260
|
end
|
291
|
-
|
292
|
-
|
293
|
-
|
261
|
+
|
262
|
+
private
|
263
|
+
|
294
264
|
# characters that may indicate inline wiki markup
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
# plain characters
|
299
|
-
|
265
|
+
SPECIALCHARS = ['^', '\\', '*', '/', '_', ',', '{', '[',
|
266
|
+
'<', '~', '|', "\n", '#', ':', ';', '(', '-', '.']
|
267
|
+
|
268
|
+
# plain characters
|
269
|
+
# build an array of "plain content" characters by subtracting SPECIALCHARS
|
270
|
+
# from ascii printable (ascii 32 to 126)
|
271
|
+
PLAINCHARS = (32..126).map{|c| c.chr}.reject{|c| SPECIALCHARS.index(c)}
|
300
272
|
|
301
273
|
# non-plain text inline widgets
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
274
|
+
INLINE = %w{strong em br esc img link ilink inowiki
|
275
|
+
sub sup mono u plug plug2 tm reg copy ndash ellipsis amp}
|
276
|
+
|
277
|
+
ALL_INLINE = [INLINE, 'plain', 'any'].flatten # including plain text
|
278
|
+
|
279
|
+
BLOCKS = %w{h1 h2 h3 hr nowiki h4 h5 h6 ul ol table p ip dl plug plug2 blank}
|
306
280
|
|
307
|
-
@@blocks = %w{h1 h2 h3 hr nowiki h4 h5 h6 ul ol table p ip dl plug plug2 blank}
|
308
|
-
|
309
281
|
# handy - used several times in %chunks
|
310
|
-
|
311
|
-
|
282
|
+
EOL = '(?:\n|$)'.freeze # end of line (or string)
|
283
|
+
|
312
284
|
@plugin_function = nil
|
313
285
|
@barelink_function = nil
|
314
286
|
@link_function = nil
|
315
287
|
@img_function = nil
|
316
|
-
|
288
|
+
|
317
289
|
@is_initialized = false
|
318
290
|
|
319
291
|
@@chunks_hash = {
|
320
292
|
:top => {
|
321
|
-
:contains =>
|
293
|
+
:contains => BLOCKS,
|
322
294
|
},
|
323
295
|
:blank => {
|
324
|
-
:curpat => "(?= *#{
|
325
|
-
:fwpat => "(?=(?:^|\n) *#{
|
296
|
+
:curpat => "(?= *#{EOL})",
|
297
|
+
:fwpat => "(?=(?:^|\n) *#{EOL})",
|
326
298
|
:stops => '(?=\S)',
|
327
299
|
:hint => ["\n"],
|
328
300
|
:filter => Proc.new { "" }, # whitespace into the bit bucket
|
@@ -331,8 +303,8 @@ class WikiCreole
|
|
331
303
|
:p => {
|
332
304
|
:curpat => '(?=.)',
|
333
305
|
:stops => ['blank', 'ip', 'h', 'hr', 'nowiki', 'ul', 'ol', 'dl', 'table'],
|
334
|
-
:hint =>
|
335
|
-
:contains =>
|
306
|
+
:hint => PLAINCHARS,
|
307
|
+
:contains => ALL_INLINE,
|
336
308
|
:filter => Proc.new {|s| s.chomp },
|
337
309
|
:open => "<p>", :close => "</p>\n\n",
|
338
310
|
},
|
@@ -362,7 +334,7 @@ class WikiCreole
|
|
362
334
|
:fwpat => '\n(?=;)',
|
363
335
|
:stops => '(?=:|\n)',
|
364
336
|
:hint => [';'],
|
365
|
-
:contains =>
|
337
|
+
:contains => ALL_INLINE,
|
366
338
|
:filter => Proc.new {|s|
|
367
339
|
s.sub!(/^;\s*/, '')
|
368
340
|
s
|
@@ -372,9 +344,9 @@ class WikiCreole
|
|
372
344
|
:dd => {
|
373
345
|
:curpat => '(?=\n|:)',
|
374
346
|
:fwpat => '(?:\n|:)',
|
375
|
-
:stops => '(?=:)|\n(?=;)',
|
347
|
+
:stops => '.(?=:)|\n(?=;)',
|
376
348
|
:hint => [':', "\n"],
|
377
|
-
:contains =>
|
349
|
+
:contains => ALL_INLINE,
|
378
350
|
:filter => Proc.new {|s|
|
379
351
|
s.sub!(/(?:\n|:)\s*/m, '')
|
380
352
|
s.sub!(/\s*$/m, '')
|
@@ -406,7 +378,7 @@ class WikiCreole
|
|
406
378
|
:curpat => '(?=\|[^=])',
|
407
379
|
# this gnarly regex fixes ambiguous '|' for links/imgs/nowiki in tables
|
408
380
|
:stops => '[^~](?=\|(?!(?:[^\[]*\]\])|(?:[^\{]*\}\})))',
|
409
|
-
:contains =>
|
381
|
+
:contains => ALL_INLINE,
|
410
382
|
:hint => ['|'],
|
411
383
|
:filter => Proc.new {|s|
|
412
384
|
s.sub!(/^ *\| */, '')
|
@@ -419,7 +391,7 @@ class WikiCreole
|
|
419
391
|
:curpat => '(?=\|=)',
|
420
392
|
# this gnarly regex fixes ambiguous '|' for links/imgs/nowiki in tables
|
421
393
|
:stops => '[^~](?=\|(?!(?:[^\[]*\]\])|(?:[^\{]*\}\})))',
|
422
|
-
:contains =>
|
394
|
+
:contains => ALL_INLINE,
|
423
395
|
:hint => ['|'],
|
424
396
|
:filter => Proc.new {|s|
|
425
397
|
s.sub!(/^ *\|= */, '')
|
@@ -462,13 +434,13 @@ class WikiCreole
|
|
462
434
|
s.chomp!
|
463
435
|
s
|
464
436
|
},
|
465
|
-
:contains =>
|
437
|
+
:contains => ALL_INLINE,
|
466
438
|
:open => " <li>", :close => "</li>\n",
|
467
439
|
},
|
468
440
|
:nowiki => {
|
469
441
|
:curpat => '(?=\{\{\{ *\n)',
|
470
442
|
:fwpat => '\n(?=\{\{\{ *\n)',
|
471
|
-
:stops => "\n\\}\\}\\} *#{
|
443
|
+
:stops => "\n\\}\\}\\} *#{EOL}",
|
472
444
|
:hint => ['{'],
|
473
445
|
:filter => Proc.new {|s|
|
474
446
|
s[0,3] = ''
|
@@ -481,19 +453,19 @@ class WikiCreole
|
|
481
453
|
:open => "<pre>", :close => "</pre>\n\n",
|
482
454
|
},
|
483
455
|
:hr => {
|
484
|
-
:curpat => "(?= *-{4,} *#{
|
485
|
-
:fwpat => "\n(?= *-{4,} *#{
|
456
|
+
:curpat => "(?= *-{4,} *#{EOL})",
|
457
|
+
:fwpat => "\n(?= *-{4,} *#{EOL})",
|
486
458
|
:hint => ['-', ' '],
|
487
|
-
:stops =>
|
459
|
+
:stops => EOL,
|
488
460
|
:open => "<hr />\n\n", :close => "",
|
489
461
|
:filter => Proc.new { "" } # ----- into the bit bucket
|
490
462
|
},
|
491
463
|
:h => { :curpat => '(?=(?:^|\n) *=)' }, # matches any heading
|
492
464
|
:h1 => {
|
493
465
|
:curpat => '(?= *=[^=])',
|
494
|
-
:hint => ['=', ' '],
|
466
|
+
:hint => ['=', ' '],
|
495
467
|
:stops => '\n',
|
496
|
-
:contains =>
|
468
|
+
:contains => ALL_INLINE,
|
497
469
|
:open => "<h1>", :close => "</h1>\n\n",
|
498
470
|
:filter => Proc.new {|s|
|
499
471
|
s = strip_leading_and_trailing_eq_and_whitespace(s)
|
@@ -502,9 +474,9 @@ class WikiCreole
|
|
502
474
|
},
|
503
475
|
:h2 => {
|
504
476
|
:curpat => '(?= *={2}[^=])',
|
505
|
-
:hint => ['=', ' '],
|
477
|
+
:hint => ['=', ' '],
|
506
478
|
:stops => '\n',
|
507
|
-
:contains =>
|
479
|
+
:contains => ALL_INLINE,
|
508
480
|
:open => "<h2>", :close => "</h2>\n\n",
|
509
481
|
:filter => Proc.new {|s|
|
510
482
|
s = strip_leading_and_trailing_eq_and_whitespace(s)
|
@@ -513,9 +485,9 @@ class WikiCreole
|
|
513
485
|
},
|
514
486
|
:h3 => {
|
515
487
|
:curpat => '(?= *={3}[^=])',
|
516
|
-
:hint => ['=', ' '],
|
488
|
+
:hint => ['=', ' '],
|
517
489
|
:stops => '\n',
|
518
|
-
:contains =>
|
490
|
+
:contains => ALL_INLINE,
|
519
491
|
:open => "<h3>", :close => "</h3>\n\n",
|
520
492
|
:filter => Proc.new {|s|
|
521
493
|
s = strip_leading_and_trailing_eq_and_whitespace(s)
|
@@ -524,9 +496,9 @@ class WikiCreole
|
|
524
496
|
},
|
525
497
|
:h4 => {
|
526
498
|
:curpat => '(?= *={4}[^=])',
|
527
|
-
:hint => ['=', ' '],
|
499
|
+
:hint => ['=', ' '],
|
528
500
|
:stops => '\n',
|
529
|
-
:contains =>
|
501
|
+
:contains => ALL_INLINE,
|
530
502
|
:open => "<h4>", :close => "</h4>\n\n",
|
531
503
|
:filter => Proc.new {|s|
|
532
504
|
s = strip_leading_and_trailing_eq_and_whitespace(s)
|
@@ -535,9 +507,9 @@ class WikiCreole
|
|
535
507
|
},
|
536
508
|
:h5 => {
|
537
509
|
:curpat => '(?= *={5}[^=])',
|
538
|
-
:hint => ['=', ' '],
|
510
|
+
:hint => ['=', ' '],
|
539
511
|
:stops => '\n',
|
540
|
-
:contains =>
|
512
|
+
:contains => ALL_INLINE,
|
541
513
|
:open => "<h5>", :close => "</h5>\n\n",
|
542
514
|
:filter => Proc.new {|s|
|
543
515
|
s = strip_leading_and_trailing_eq_and_whitespace(s)
|
@@ -546,9 +518,9 @@ class WikiCreole
|
|
546
518
|
},
|
547
519
|
:h6 => {
|
548
520
|
:curpat => '(?= *={6,})',
|
549
|
-
:hint => ['=', ' '],
|
521
|
+
:hint => ['=', ' '],
|
550
522
|
:stops => '\n',
|
551
|
-
:contains =>
|
523
|
+
:contains => ALL_INLINE,
|
552
524
|
:open => "<h6>", :close => "</h6>\n\n",
|
553
525
|
:filter => Proc.new {|s|
|
554
526
|
s = strip_leading_and_trailing_eq_and_whitespace(s)
|
@@ -557,13 +529,13 @@ class WikiCreole
|
|
557
529
|
},
|
558
530
|
:plain => {
|
559
531
|
:curpat => '(?=[^\*\/_\,\^\\\\{\[\<\|])',
|
560
|
-
:stops =>
|
561
|
-
:hint =>
|
532
|
+
:stops => INLINE,
|
533
|
+
:hint => PLAINCHARS,
|
562
534
|
:open => '', :close => ''
|
563
535
|
},
|
564
536
|
:any => { # catch-all
|
565
537
|
:curpat => '(?=.)',
|
566
|
-
:stops =>
|
538
|
+
:stops => INLINE,
|
567
539
|
:open => '', :close => ''
|
568
540
|
},
|
569
541
|
:br => {
|
@@ -604,7 +576,7 @@ class WikiCreole
|
|
604
576
|
:filter => Proc.new {|s|
|
605
577
|
s[0,3] = ''
|
606
578
|
s.sub!(/\>{3}$/, '')
|
607
|
-
if
|
579
|
+
if @plugin_function
|
608
580
|
s = @plugin_function.call(s)
|
609
581
|
else
|
610
582
|
s = "<<<#{s}>>>"
|
@@ -620,7 +592,7 @@ class WikiCreole
|
|
620
592
|
:filter => Proc.new {|s|
|
621
593
|
s[0,2] = ''
|
622
594
|
s.sub!(/\>{2}$/, '')
|
623
|
-
if
|
595
|
+
if @plugin_function
|
624
596
|
s = @plugin_function.call(s)
|
625
597
|
else
|
626
598
|
s = "<<#{s}>>"
|
@@ -640,9 +612,9 @@ class WikiCreole
|
|
640
612
|
:filter => Proc.new {|s|
|
641
613
|
s.sub!(/^\s*/, '')
|
642
614
|
s.sub!(/\s*$/, '')
|
643
|
-
if
|
615
|
+
if @barelink_function
|
644
616
|
s = @barelink_function.call(s)
|
645
|
-
end
|
617
|
+
end
|
646
618
|
s = "href=\"#{s}\">#{s}"
|
647
619
|
s
|
648
620
|
},
|
@@ -657,7 +629,7 @@ class WikiCreole
|
|
657
629
|
s[0,2] = ''
|
658
630
|
s[-2,2] = ''
|
659
631
|
s += "|#{s}" if ! s.index(/\|/) # text = url unless given
|
660
|
-
s
|
632
|
+
s
|
661
633
|
},
|
662
634
|
:open => "<a ", :close => "</a>",
|
663
635
|
},
|
@@ -667,7 +639,7 @@ class WikiCreole
|
|
667
639
|
:filter => Proc.new {|s|
|
668
640
|
s.sub!(/^\s*/, '')
|
669
641
|
s.sub!(/\s*$/, '')
|
670
|
-
if
|
642
|
+
if @link_function
|
671
643
|
s = @link_function.call(s)
|
672
644
|
end
|
673
645
|
s
|
@@ -678,7 +650,7 @@ class WikiCreole
|
|
678
650
|
:curpat => '(?=\|)',
|
679
651
|
:stops => '\n',
|
680
652
|
:hint => ['|'],
|
681
|
-
:contains =>
|
653
|
+
:contains => ALL_INLINE,
|
682
654
|
:filter => Proc.new {|s|
|
683
655
|
s.sub!(/^\|\s*/, '')
|
684
656
|
s.sub!(/\s*$/, '')
|
@@ -715,7 +687,7 @@ class WikiCreole
|
|
715
687
|
:filter => Proc.new {|s|
|
716
688
|
s.sub!(/^\|\s*/, '')
|
717
689
|
s.sub!(/\s*$/, '')
|
718
|
-
if
|
690
|
+
if @img_function
|
719
691
|
s = @img_function.call(s)
|
720
692
|
end
|
721
693
|
s
|
@@ -726,7 +698,7 @@ class WikiCreole
|
|
726
698
|
:curpat => '(?=\*\*)',
|
727
699
|
:stops => '\*\*.*?\*\*',
|
728
700
|
:hint => ['*'],
|
729
|
-
:contains =>
|
701
|
+
:contains => ALL_INLINE,
|
730
702
|
:filter => Proc.new {|s|
|
731
703
|
s[0,2] = ''
|
732
704
|
s.sub!(/\*\*$/, '')
|
@@ -737,7 +709,7 @@ class WikiCreole
|
|
737
709
|
:em => {
|
738
710
|
# This could use a negative lookback assertion to let you know whether
|
739
711
|
# it's part of a URL or not. That would be helpful if the URL had been
|
740
|
-
# escaped. Currently, it will just become italic after the // since
|
712
|
+
# escaped. Currently, it will just become italic after the // since
|
741
713
|
# it didn't process the URL.
|
742
714
|
:curpat => '(?=\/\/)',
|
743
715
|
# Removed a negative lookback assertion (?<!:) from the Perl version
|
@@ -746,7 +718,7 @@ class WikiCreole
|
|
746
718
|
# I had to do it.
|
747
719
|
:stops => '\/\/.*?[^:]\/\/',
|
748
720
|
:hint => ['/'],
|
749
|
-
:contains =>
|
721
|
+
:contains => ALL_INLINE,
|
750
722
|
:filter => Proc.new {|s|
|
751
723
|
s[0,2] = ''
|
752
724
|
s.sub!(/\/\/$/, '')
|
@@ -758,7 +730,7 @@ class WikiCreole
|
|
758
730
|
:curpat => '(?=\#\#)',
|
759
731
|
:stops => '\#\#.*?\#\#',
|
760
732
|
:hint => ['#'],
|
761
|
-
:contains =>
|
733
|
+
:contains => ALL_INLINE,
|
762
734
|
:filter => Proc.new {|s|
|
763
735
|
s[0,2] = ''
|
764
736
|
s.sub!(/\#\#$/, '')
|
@@ -770,7 +742,7 @@ class WikiCreole
|
|
770
742
|
:curpat => '(?=,,)',
|
771
743
|
:stops => ',,.*?,,',
|
772
744
|
:hint => [','],
|
773
|
-
:contains =>
|
745
|
+
:contains => ALL_INLINE,
|
774
746
|
:filter => Proc.new {|s|
|
775
747
|
s[0,2] = ''
|
776
748
|
s.sub!(/\,\,$/, '')
|
@@ -782,7 +754,7 @@ class WikiCreole
|
|
782
754
|
:curpat => '(?=\^\^)',
|
783
755
|
:stops => '\^\^.*?\^\^',
|
784
756
|
:hint => ['^'],
|
785
|
-
:contains =>
|
757
|
+
:contains => ALL_INLINE,
|
786
758
|
:filter => Proc.new {|s|
|
787
759
|
s[0,2] = ''
|
788
760
|
s.sub!(/\^\^$/, '')
|
@@ -794,7 +766,7 @@ class WikiCreole
|
|
794
766
|
:curpat => '(?=__)',
|
795
767
|
:stops => '__.*?__',
|
796
768
|
:hint => ['_'],
|
797
|
-
:contains =>
|
769
|
+
:contains => ALL_INLINE,
|
798
770
|
:filter => Proc.new {|s|
|
799
771
|
s[0,2] = ''
|
800
772
|
s.sub!(/__$/, '')
|
@@ -845,93 +817,77 @@ class WikiCreole
|
|
845
817
|
:open => "", :close => "",
|
846
818
|
},
|
847
819
|
}
|
848
|
-
|
820
|
+
|
849
821
|
def self.strip_leading_and_trailing_eq_and_whitespace(s)
|
850
822
|
s.sub!(/^\s*=*\s*/, '')
|
851
823
|
s.sub!(/\s*=*\s*$/, '')
|
852
|
-
|
824
|
+
s
|
853
825
|
end
|
854
826
|
|
855
827
|
def self.strip_list(s)
|
856
828
|
s.sub!(/(?:`*| *)[\*\#]/, '`')
|
857
829
|
s.gsub!(/\n(?:`*| *)[\*\#]/m, "\n`")
|
858
|
-
|
830
|
+
s
|
859
831
|
end
|
860
|
-
|
832
|
+
|
861
833
|
def self.filter_string_x_with_chunk_filter_y(str, chunk)
|
862
|
-
|
834
|
+
@@chunks_hash[chunk][:filter].call(str)
|
863
835
|
end
|
864
|
-
|
836
|
+
|
865
837
|
def self.parse(tref, chunk)
|
866
|
-
|
838
|
+
|
867
839
|
sub_chunk = nil
|
868
840
|
pos = 0
|
869
841
|
last_pos = 0
|
870
|
-
html =
|
842
|
+
html = []
|
843
|
+
first_try = true
|
871
844
|
|
872
845
|
loop do
|
873
846
|
|
874
847
|
if sub_chunk # we've determined what type of sub_chunk this is
|
875
|
-
|
876
|
-
if sub_chunk == :dd
|
877
|
-
# Yuck... I don't exactly understand why I need this section, but
|
878
|
-
# without it the parser will go into an infinite loop on the :dd's in
|
879
|
-
# the test suite. Please, if you're a most excellent Ruby hacker,
|
880
|
-
# find the issue, clean this up, and remove the comment here, m'kay?
|
881
|
-
|
882
|
-
while tref.index(Regexp.compile('\G.*' + @@chunks_hash[sub_chunk][:delim], Regexp::MULTILINE), pos)
|
883
|
-
end_of_match = Regexp.last_match.end(0)
|
884
|
-
if end_of_match == pos
|
885
|
-
break
|
886
|
-
else
|
887
|
-
pos = end_of_match
|
888
|
-
end
|
889
|
-
end
|
890
848
|
|
891
|
-
|
892
|
-
|
893
|
-
|
849
|
+
# This is a little slower than it could be. The delim should be
|
850
|
+
# pre-compiled, but see the issue in the comment above.
|
851
|
+
if tref.index(@@chunks_hash[sub_chunk][:delim], pos)
|
852
|
+
pos = Regexp.last_match.end(0)
|
894
853
|
else
|
895
|
-
|
896
|
-
# pre-compiled, but see the issue in the comment above.
|
897
|
-
if tref.index(Regexp.compile(@@chunks_hash[sub_chunk][:delim], Regexp::MULTILINE), pos)
|
898
|
-
pos = Regexp.last_match.end(0)
|
899
|
-
else
|
900
|
-
pos = tref.length
|
901
|
-
end
|
854
|
+
pos = tref.length
|
902
855
|
end
|
903
856
|
|
904
|
-
html
|
857
|
+
html << @@chunks_hash[sub_chunk][:open]
|
905
858
|
|
906
859
|
t = tref[last_pos, pos - last_pos] # grab the chunk
|
907
860
|
|
908
861
|
if @@chunks_hash[sub_chunk].has_key?(:filter) # filter it, if applicable
|
909
862
|
t = @@chunks_hash[sub_chunk][:filter].call(t)
|
910
863
|
end
|
911
|
-
|
864
|
+
|
912
865
|
last_pos = pos # remember where this chunk ends (where next begins)
|
913
|
-
|
866
|
+
|
914
867
|
if t && @@chunks_hash[sub_chunk].has_key?(:contains) # if it contains other chunks...
|
915
|
-
html
|
868
|
+
html << parse(t, sub_chunk) # recurse.
|
916
869
|
else
|
917
|
-
html
|
870
|
+
html << t # otherwise, print it
|
918
871
|
end
|
872
|
+
|
873
|
+
html << @@chunks_hash[sub_chunk][:close] # print the close tag
|
919
874
|
|
920
|
-
|
921
|
-
|
875
|
+
else
|
876
|
+
if !first_try
|
877
|
+
$stderr.puts "ERROR: endless loop detected"
|
878
|
+
break
|
879
|
+
end
|
880
|
+
first_try = false
|
922
881
|
end
|
923
882
|
|
924
|
-
if pos && pos == tref.length # we've eaten the whole string
|
925
|
-
|
926
|
-
|
927
|
-
sub_chunk = get_sub_chunk_for(tref, chunk, pos)
|
928
|
-
end
|
929
|
-
|
883
|
+
break if pos && pos == tref.length # we've eaten the whole string
|
884
|
+
sub_chunk = get_sub_chunk_for(tref, chunk, pos) # more string to come
|
885
|
+
|
930
886
|
end
|
931
|
-
|
932
|
-
|
887
|
+
|
888
|
+
html.join
|
933
889
|
end
|
934
|
-
|
890
|
+
|
935
891
|
def self.get_sub_chunk_for(tref, chunk, pos)
|
936
892
|
|
937
893
|
first_char = tref[pos, 1] # get a hint about the next chunk
|
@@ -949,17 +905,17 @@ class WikiCreole
|
|
949
905
|
return contained_chunk.to_sym
|
950
906
|
end
|
951
907
|
end
|
952
|
-
|
953
|
-
|
908
|
+
|
909
|
+
nil
|
954
910
|
end
|
955
|
-
|
911
|
+
|
956
912
|
# compile a regex that matches any of the patterns that interrupt the
|
957
913
|
# current chunk.
|
958
914
|
def self.delim(chunk)
|
959
915
|
chunk = @@chunks_hash[chunk]
|
960
|
-
if chunk[:stops]
|
916
|
+
if Array === chunk[:stops]
|
961
917
|
regex = ''
|
962
|
-
|
918
|
+
chunk[:stops].each do |stop|
|
963
919
|
stop = stop.to_sym
|
964
920
|
if @@chunks_hash[stop].has_key?(:fwpat)
|
965
921
|
regex += @@chunks_hash[stop][:fwpat] + "|"
|
@@ -968,59 +924,42 @@ class WikiCreole
|
|
968
924
|
end
|
969
925
|
end
|
970
926
|
regex.chop!
|
971
|
-
|
927
|
+
regex
|
972
928
|
else
|
973
|
-
|
929
|
+
chunk[:stops]
|
974
930
|
end
|
975
931
|
end
|
976
|
-
|
932
|
+
|
977
933
|
# one-time optimization of the grammar - speeds the parser up a ton
|
978
|
-
def self.init
|
934
|
+
def self.init
|
979
935
|
return if @is_initialized
|
980
936
|
|
981
937
|
@is_initialized = true
|
982
938
|
|
983
|
-
#
|
984
|
-
|
985
|
-
for charnum in 32..126 do
|
986
|
-
char = charnum.chr
|
987
|
-
if @@specialchars.index(char).nil?
|
988
|
-
@@plainchars << char
|
989
|
-
end
|
990
|
-
end
|
991
|
-
|
992
|
-
# precompile a bunch of regexes
|
993
|
-
for k in @@chunks_hash.keys do
|
939
|
+
# precompile a bunch of regexes
|
940
|
+
@@chunks_hash.keys.each do |k|
|
994
941
|
c = @@chunks_hash[k]
|
995
942
|
if c.has_key?(:curpat)
|
996
943
|
c[:curpatcmp] = Regexp.compile('\G' + c[:curpat], Regexp::MULTILINE)
|
997
944
|
end
|
998
|
-
|
945
|
+
|
999
946
|
if c.has_key?(:stops)
|
1000
|
-
c[:delim] = delim(k)
|
947
|
+
c[:delim] = Regexp.compile(delim(k), Regexp::MULTILINE)
|
1001
948
|
end
|
1002
|
-
|
949
|
+
|
1003
950
|
if c.has_key?(:contains) # store hints about each chunk to speed id
|
1004
951
|
c[:calculated_hint_array_for] = {}
|
1005
|
-
|
1006
|
-
|
952
|
+
|
953
|
+
c[:contains].each do |ct|
|
1007
954
|
ct = ct.to_sym
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
if !c[:calculated_hint_array_for].has_key?(hint)
|
1012
|
-
c[:calculated_hint_array_for][hint] = []
|
1013
|
-
end
|
1014
|
-
c[:calculated_hint_array_for][hint] << ct
|
1015
|
-
end
|
955
|
+
|
956
|
+
(@@chunks_hash[ct][:hint] || []).each do |hint|
|
957
|
+
(c[:calculated_hint_array_for][hint] ||= []) << ct
|
1016
958
|
end
|
1017
959
|
|
1018
960
|
end
|
1019
961
|
end
|
1020
962
|
end
|
1021
|
-
|
1022
963
|
end
|
1023
|
-
|
1024
|
-
|
1025
964
|
|
1026
|
-
end
|
965
|
+
end
|
data/test/profiling.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'wiki_creole'
|
5
|
+
require 'ruby-prof'
|
6
|
+
|
7
|
+
WikiCreole.init
|
8
|
+
|
9
|
+
result = RubyProf.profile do
|
10
|
+
10.times do
|
11
|
+
%w(amp block escape inline specialchars jsp_wiki).each do |name|
|
12
|
+
markup = File.read("./test/test_#{name}.markup")
|
13
|
+
parsed = WikiCreole.parse(markup, :top)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
printer = RubyProf::GraphHtmlPrinter.new(result)
|
19
|
+
File.open("profiling.html", "w") do |file|
|
20
|
+
printer.print(file)
|
21
|
+
end
|
22
|
+
|
data/test/test_all.rb
CHANGED
@@ -119,11 +119,7 @@ class TC_WikiCreole < Test::Unit::TestCase
|
|
119
119
|
|
120
120
|
def test_user_supplied_creole_link_function
|
121
121
|
|
122
|
-
|
123
|
-
s.upcase!
|
124
|
-
s
|
125
|
-
}
|
126
|
-
WikiCreole.creole_link(uppercase)
|
122
|
+
WikiCreole.creole_link {|s| s.upcase }
|
127
123
|
|
128
124
|
markup = "This is a paragraph with an uppercased [[ link ]].\nCheck it out."
|
129
125
|
goodhtml = %Q{<p>This is a paragraph with an uppercased <a href="LINK">link</a>.\nCheck it out.</p>\n\n}
|
@@ -132,12 +128,12 @@ class TC_WikiCreole < Test::Unit::TestCase
|
|
132
128
|
|
133
129
|
# set the link function back to being nil so that the rest of the tests
|
134
130
|
# are not affected by the custom link function
|
135
|
-
WikiCreole.creole_link
|
131
|
+
WikiCreole.creole_link
|
136
132
|
|
137
133
|
end
|
138
134
|
|
139
135
|
def test_puts_existing_creole_tags
|
140
|
-
tags = WikiCreole.
|
136
|
+
tags = WikiCreole.creole_tags
|
141
137
|
assert tags.index(/u: open\(<u>\) close\(<\/u>\)/)
|
142
138
|
end
|
143
139
|
|
@@ -152,11 +148,7 @@ class TC_WikiCreole < Test::Unit::TestCase
|
|
152
148
|
end
|
153
149
|
|
154
150
|
def test_user_supplied_plugin_function
|
155
|
-
|
156
|
-
s.upcase!
|
157
|
-
s
|
158
|
-
}
|
159
|
-
WikiCreole.creole_plugin(uppercase)
|
151
|
+
WikiCreole.creole_plugin {|s| s.upcase }
|
160
152
|
|
161
153
|
markup = "This is a paragraph with an uppercasing << plugin >>.\nCheck it out."
|
162
154
|
goodhtml = %Q{<p>This is a paragraph with an uppercasing PLUGIN .\nCheck it out.</p>\n\n}
|
@@ -165,7 +157,7 @@ class TC_WikiCreole < Test::Unit::TestCase
|
|
165
157
|
|
166
158
|
# set the link function back to being nil so that the rest of the tests
|
167
159
|
# are not affected by the custom link function
|
168
|
-
WikiCreole.creole_plugin
|
160
|
+
WikiCreole.creole_plugin
|
169
161
|
end
|
170
162
|
|
171
163
|
#-----------------------------------------------------------------------------
|
@@ -198,6 +190,10 @@ class TC_WikiCreole < Test::Unit::TestCase
|
|
198
190
|
# are the same as they were in the original test.
|
199
191
|
run_testfile("jsp_wiki")
|
200
192
|
end
|
193
|
+
|
194
|
+
def test_nested_lists
|
195
|
+
run_testfile("nested_lists")
|
196
|
+
end
|
201
197
|
|
202
198
|
def run_testfile(name)
|
203
199
|
name = "test_" + name
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: WikiCreole
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gordon McCreight
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-02-05 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -28,19 +28,22 @@ files:
|
|
28
28
|
- LICENSE
|
29
29
|
- Rakefile
|
30
30
|
- lib/wiki_creole.rb
|
31
|
+
- test/profiling.rb
|
31
32
|
- test/test_all.rb
|
32
|
-
- test/test_escape.html
|
33
|
-
- test/test_jsp_wiki.markup
|
34
|
-
- test/test_amp.html
|
35
|
-
- test/test_escape.markup
|
36
|
-
- test/test_specialchars.html
|
37
33
|
- test/test_amp.markup
|
38
|
-
- test/
|
39
|
-
- test/
|
34
|
+
- test/test_amp.html
|
35
|
+
- test/test_block.markup
|
40
36
|
- test/test_block.html
|
37
|
+
- test/test_escape.markup
|
38
|
+
- test/test_escape.html
|
41
39
|
- test/test_inline.markup
|
42
|
-
- test/
|
40
|
+
- test/test_inline.html
|
41
|
+
- test/test_jsp_wiki.markup
|
43
42
|
- test/test_jsp_wiki.html
|
43
|
+
- test/test_nested_lists.markup
|
44
|
+
- test/test_nested_lists.html
|
45
|
+
- test/test_specialchars.markup
|
46
|
+
- test/test_specialchars.html
|
44
47
|
has_rdoc: true
|
45
48
|
homepage: http://github.com/gmccreight/wikicreole/tree/master
|
46
49
|
post_install_message:
|
@@ -62,8 +65,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
65
|
version:
|
63
66
|
requirements: []
|
64
67
|
|
65
|
-
rubyforge_project:
|
66
|
-
rubygems_version: 1.
|
68
|
+
rubyforge_project: wikicreole
|
69
|
+
rubygems_version: 1.3.1
|
67
70
|
signing_key:
|
68
71
|
specification_version: 2
|
69
72
|
summary: A Creole-to-XHTML converter written in pure Ruby
|