WikiCreole 0.1.2 → 0.1.3
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.
- 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
|