creole 0.3.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/Manifest.txt +6 -0
- data/README.txt +28 -0
- data/Rakefile +11 -0
- data/lib/creole.rb +372 -0
- data/test/test_creole.rb +15 -0
- data/test/testcases.rb +631 -0
- metadata +72 -0
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
= Creole
|
2
|
+
|
3
|
+
* http://creole.rubyforge.org/
|
4
|
+
* http://rubyforge.org/projects/creole/
|
5
|
+
|
6
|
+
== DESCRIPTION:
|
7
|
+
|
8
|
+
Creole is a Creole-to-HTML converter for Creole, the lightwight markup
|
9
|
+
language (http://wikicreole.org/).
|
10
|
+
|
11
|
+
== SYNOPSIS:
|
12
|
+
|
13
|
+
gem 'creole'
|
14
|
+
require 'creole'
|
15
|
+
html = Creole.creolize( ... )
|
16
|
+
|
17
|
+
== BUGS:
|
18
|
+
|
19
|
+
If you found a bug, please report it at the Creole project's tracker
|
20
|
+
on RubyForge:
|
21
|
+
|
22
|
+
http://rubyforge.org/tracker/?group_id=6344
|
23
|
+
|
24
|
+
== LICENSE:
|
25
|
+
|
26
|
+
RDoc is Copyright (c) 2008 Lars Christensen. It is free software, and
|
27
|
+
may be redistributed under the terms specified in the README file of
|
28
|
+
the Ruby distribution.
|
data/Rakefile
ADDED
data/lib/creole.rb
ADDED
@@ -0,0 +1,372 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
# :main: Creole
|
5
|
+
|
6
|
+
# The Creole parses and translates Creole formatted text into
|
7
|
+
# XHTML. Creole is a lightwight markup syntax similar to what many
|
8
|
+
# WikiWikiWebs use. Example syntax:
|
9
|
+
#
|
10
|
+
# = Heading 1 =
|
11
|
+
# == Heading 2 ==
|
12
|
+
# === Heading 3 ===
|
13
|
+
# **Bold text**
|
14
|
+
# //Italic text//
|
15
|
+
# [[Links]]
|
16
|
+
# |=Table|=Heading|
|
17
|
+
# |Table |Cells |
|
18
|
+
# {{image.png}}
|
19
|
+
#
|
20
|
+
# The simplest interface is Creole.creolize. The default handling of
|
21
|
+
# links allow explicit local links using the [[link]] syntax. External
|
22
|
+
# links will only be allowed if specified using http(s) and ftp(s)
|
23
|
+
# schemes. If special link handling is needed, such as inter-wiki or
|
24
|
+
# hierachical local links, you must inherit Creole::CreoleParser and
|
25
|
+
# override make_local_link.
|
26
|
+
#
|
27
|
+
# You can customize the created anchor/image markup by overriding
|
28
|
+
# make_*_anchor/make_image.
|
29
|
+
|
30
|
+
module Creole
|
31
|
+
|
32
|
+
VERSION = '0.3.3'
|
33
|
+
|
34
|
+
# CreoleParseError is raised when the Creole parser encounters
|
35
|
+
# something unexpected. This is generally now thrown unless there is
|
36
|
+
# a bug in the parser.
|
37
|
+
class CreoleParseError < Exception; end
|
38
|
+
|
39
|
+
# Convert the argument in Creole format to HTML and return the
|
40
|
+
# result. Example:
|
41
|
+
#
|
42
|
+
# Creole.creolize("**Hello //World//**")
|
43
|
+
# #=> "<p><strong>Hello <em>World</em></strong></p>"
|
44
|
+
#
|
45
|
+
# This is an alias for calling CreoleParser#parse:
|
46
|
+
# CreoleParser.new.parse(creole)
|
47
|
+
def self.creolize(creole)
|
48
|
+
CreoleParser.new.parse(creole)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Main Creole parser class. Call CreoleParser#parse to parse Creole
|
52
|
+
# formatted text.
|
53
|
+
#
|
54
|
+
# This class is not reentrant. A separate instance is needed for
|
55
|
+
# each thread that needs to convert Creole to HTML.
|
56
|
+
#
|
57
|
+
# Inherit this to provide custom handling of links. The overrideable
|
58
|
+
# methods are: make_local_link
|
59
|
+
class CreoleParser
|
60
|
+
|
61
|
+
# Create a new CreoleParser instance.
|
62
|
+
def initialize
|
63
|
+
@base = nil
|
64
|
+
@allowed_schemes = [ 'http', 'https', 'ftp', 'ftps' ]
|
65
|
+
@uri_scheme_re = @allowed_schemes.join('|')
|
66
|
+
end
|
67
|
+
|
68
|
+
# Parse and convert the argument in Creole text to HTML and return
|
69
|
+
# the result. The resulting HTML does not contain <html> and
|
70
|
+
# <body> tags.
|
71
|
+
#
|
72
|
+
# Example:
|
73
|
+
#
|
74
|
+
# parser = CreoleParser.new
|
75
|
+
# parser.parse("**Hello //World//**")
|
76
|
+
# #=> "<p><strong>Hello <em>World</em></strong></p>"
|
77
|
+
def parse(string)
|
78
|
+
@out = ""
|
79
|
+
@strong = false
|
80
|
+
@p = false
|
81
|
+
@stack = []
|
82
|
+
parse_block(string)
|
83
|
+
return @out
|
84
|
+
end
|
85
|
+
|
86
|
+
# Escape any characters with special meaning in HTML using HTML
|
87
|
+
# entities.
|
88
|
+
private
|
89
|
+
def escape_html(string)
|
90
|
+
CGI::escapeHTML(string)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Escape any characters with special meaning in URLs using URL
|
94
|
+
# encoding.
|
95
|
+
private
|
96
|
+
def escape_url(string)
|
97
|
+
CGI::escape(string)
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def start_tag(tag)
|
103
|
+
@stack.push(tag)
|
104
|
+
@out << '<' << tag << '>'
|
105
|
+
end
|
106
|
+
|
107
|
+
def end_tag
|
108
|
+
@out << '</' << @stack.pop << '>'
|
109
|
+
end
|
110
|
+
|
111
|
+
def toggle_tag(tag, match)
|
112
|
+
if @stack.include?(tag)
|
113
|
+
if @stack.last == tag
|
114
|
+
end_tag
|
115
|
+
else
|
116
|
+
@out << escape_html(match)
|
117
|
+
end
|
118
|
+
else
|
119
|
+
start_tag(tag)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def end_paragraph
|
124
|
+
end_tag while !@stack.empty?
|
125
|
+
@p = false
|
126
|
+
end
|
127
|
+
|
128
|
+
def start_paragraph
|
129
|
+
if @p
|
130
|
+
@out << ' ' if @out[-1,1] != ' '
|
131
|
+
else
|
132
|
+
end_paragraph
|
133
|
+
start_tag('p')
|
134
|
+
@p = true
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Create anchor markup for direct links. This
|
139
|
+
# method can be overridden to generate custom
|
140
|
+
# markup, for example to add html additional attributes.
|
141
|
+
private
|
142
|
+
def make_direct_anchor(uri, text)
|
143
|
+
'<a href="' << escape_html(uri) << '">' << escape_html(text) << '</a>'
|
144
|
+
end
|
145
|
+
|
146
|
+
# Create anchor markup for explicit links. This
|
147
|
+
# method can be overridden to generate custom
|
148
|
+
# markup, for example to add html additional attributes.
|
149
|
+
private
|
150
|
+
def make_explicit_anchor(uri, text)
|
151
|
+
'<a href="' << escape_html(uri) << '">' << escape_html(text) << '</a>'
|
152
|
+
end
|
153
|
+
|
154
|
+
# Translate an explicit local link to a desired URL that is
|
155
|
+
# properly URL-escaped. The default behaviour is to convert local
|
156
|
+
# links directly, escaping any characters that have special
|
157
|
+
# meaning in URLs. Relative URLs in local links are not handled.
|
158
|
+
#
|
159
|
+
# Examples:
|
160
|
+
#
|
161
|
+
# make_local_link("LocalLink") #=> "LocalLink"
|
162
|
+
# make_local_link("/Foo/Bar") #=> "%2FFoo%2FBar"
|
163
|
+
#
|
164
|
+
# Must ensure that the result is properly URL-escaped. The caller
|
165
|
+
# will handle HTML escaping as necessary. HTML links will not be
|
166
|
+
# inserted if the function returns nil.
|
167
|
+
#
|
168
|
+
# Example custom behaviour:
|
169
|
+
#
|
170
|
+
# make_local_link("LocalLink") #=> "/LocalLink"
|
171
|
+
# make_local_link("Wikipedia:Bread") #=> "http://en.wikipedia.org/wiki/Bread"
|
172
|
+
private
|
173
|
+
def make_local_link(link) #:doc:
|
174
|
+
escape_url(link)
|
175
|
+
end
|
176
|
+
|
177
|
+
# Sanatize a direct url (e.g. http://wikipedia.org/). The default
|
178
|
+
# behaviour returns the original link as-is.
|
179
|
+
#
|
180
|
+
# Must ensure that the result is properly URL-escaped. The caller
|
181
|
+
# will handle HTML escaping as necessary. Links will not be
|
182
|
+
# converted to HTML links if the function returns link.
|
183
|
+
#
|
184
|
+
# Custom versions of this function in inherited classes can
|
185
|
+
# implement specific link handling behaviour, such as redirection
|
186
|
+
# to intermediate pages (for example, for notifing the user that
|
187
|
+
# he is leaving the site).
|
188
|
+
private
|
189
|
+
def make_direct_link(url) #:doc:
|
190
|
+
return url
|
191
|
+
end
|
192
|
+
|
193
|
+
# Sanatize and prefix image URLs. When images are encountered in
|
194
|
+
# Creole text, this function is called to obtain the actual URL of
|
195
|
+
# the image. The default behaviour is to return the image link
|
196
|
+
# as-is. No image tags are inserted if the function returns nil.
|
197
|
+
#
|
198
|
+
# Custom version of the method can be used to sanatize URLs
|
199
|
+
# (e.g. remove query-parts), inhibit off-site images, or add a
|
200
|
+
# base URL, for example:
|
201
|
+
#
|
202
|
+
# def make_image_link(url)
|
203
|
+
# URI.join("http://mywiki.org/images/", url)
|
204
|
+
# end
|
205
|
+
private
|
206
|
+
def make_image_link(url) #:doc:
|
207
|
+
return url
|
208
|
+
end
|
209
|
+
|
210
|
+
# Create image markup. This
|
211
|
+
# method can be overridden to generate custom
|
212
|
+
# markup, for example to add html additional attributes or
|
213
|
+
# to put divs around the imgs.
|
214
|
+
private
|
215
|
+
def make_image(uri, alt)
|
216
|
+
if alt
|
217
|
+
'<img src="' << escape_html(uri) << '" alt="' << escape_html(alt) << '"/>'
|
218
|
+
else
|
219
|
+
'<img src="' << escape_html(uri) << '"/>'
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
def make_explicit_link(link)
|
225
|
+
begin
|
226
|
+
uri = URI.parse(link)
|
227
|
+
return uri.to_s if uri.scheme && @allowed_schemes.include?(uri.scheme)
|
228
|
+
rescue URI::InvalidURIError
|
229
|
+
end
|
230
|
+
return make_local_link(link)
|
231
|
+
end
|
232
|
+
|
233
|
+
def parse_inline(str)
|
234
|
+
until str.empty?
|
235
|
+
case str
|
236
|
+
when /\A(\~)?((https?|ftps?):\/\/\S+?)(?=([,.?!:;"'\)])?(\s|$))/
|
237
|
+
if $1
|
238
|
+
@out << escape_html($2)
|
239
|
+
else
|
240
|
+
if uri = make_direct_link($2)
|
241
|
+
@out << make_direct_anchor(uri, $2)
|
242
|
+
else
|
243
|
+
@out << escape_html($&)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
when /\A\[\[\s*([^|]*?)\s*(\|\s*(.*?))?\s*\]\]/m
|
247
|
+
link = $1
|
248
|
+
if uri = make_explicit_link(link)
|
249
|
+
@out << make_explicit_anchor(uri, $3 || link)
|
250
|
+
else
|
251
|
+
@out << escape_html($&)
|
252
|
+
end
|
253
|
+
when /\A\{\{\{(.*)\}\}\}/
|
254
|
+
@out << '<tt>' << escape_html($1) << '</tt>'
|
255
|
+
when /\A\{\{\s*(.*?)\s*(\|\s*(.*?)\s*)?\}\}/
|
256
|
+
if uri = make_image_link($1)
|
257
|
+
@out << make_image(uri, $3)
|
258
|
+
else
|
259
|
+
@out << escape_html($&)
|
260
|
+
end
|
261
|
+
when /\A~([^\s])/
|
262
|
+
@out << escape_html($1)
|
263
|
+
when /\A\w+/
|
264
|
+
@out << $&
|
265
|
+
when /\A\s+/
|
266
|
+
@out << ' ' if @out[-1,1] != ' '
|
267
|
+
when /\A\*\*/
|
268
|
+
toggle_tag 'strong', $&
|
269
|
+
when /\A\/\//
|
270
|
+
toggle_tag 'em', $&
|
271
|
+
when /\A\\\\/
|
272
|
+
@out << '<br/>'
|
273
|
+
when /./
|
274
|
+
@out << escape_html($&)
|
275
|
+
else
|
276
|
+
raise CreoleParseError, "Parse error at #{str[0,30].inspect}"
|
277
|
+
end
|
278
|
+
str = $'
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def parse_table_row(str)
|
283
|
+
@out << '<tr>'
|
284
|
+
str.scan(/\s*\|(=)?\s*((\[\[.*?\]\]|\{\{.*?\}\}|[^|~]|~.)*)(?=\||$)/) do
|
285
|
+
if !$2.empty? || !$'.empty?
|
286
|
+
@out << ($1 ? '<th>' : '<td>')
|
287
|
+
parse_inline($2) if $2
|
288
|
+
end_tag while @stack.last != 'table'
|
289
|
+
@out << ($1 ? '</th>' : '</td>')
|
290
|
+
end
|
291
|
+
end
|
292
|
+
@out << '</tr>'
|
293
|
+
end
|
294
|
+
|
295
|
+
def make_nowikiblock(input)
|
296
|
+
input.gsub(/^ (?=\}\}\})/, '')
|
297
|
+
end
|
298
|
+
|
299
|
+
def ulol?(x); x == 'ul' || x == 'ol'; end
|
300
|
+
|
301
|
+
def parse_block(str)
|
302
|
+
until str.empty?
|
303
|
+
case str
|
304
|
+
when /\A\{\{\{\r?\n(.*?)\r?\n\}\}\}/m
|
305
|
+
end_paragraph
|
306
|
+
nowikiblock = make_nowikiblock($1)
|
307
|
+
@out << '<pre>' << escape_html(nowikiblock) << '</pre>'
|
308
|
+
when /\A\s*-{4,}\s*$/
|
309
|
+
end_paragraph
|
310
|
+
@out << '<hr/>'
|
311
|
+
when /\A\s*(={1,6})\s*(.*?)\s*=*\s*$(\r?\n)?/
|
312
|
+
end_paragraph
|
313
|
+
level = $1.size
|
314
|
+
@out << "<h#{level}>" << escape_html($2) << "</h#{level}>"
|
315
|
+
when /\A[ \t]*\|.*$(\r?\n)?/
|
316
|
+
if !@stack.include?('table')
|
317
|
+
end_paragraph
|
318
|
+
start_tag('table')
|
319
|
+
end
|
320
|
+
parse_table_row($&)
|
321
|
+
when /\A\s*$(\r?\n)?/
|
322
|
+
end_paragraph
|
323
|
+
when /\A(\s*([*#]+)\s*(.*?))$(\r?\n)?/
|
324
|
+
line, bullet, item = $1, $2, $3
|
325
|
+
tag = (bullet[0,1] == '*' ? 'ul' : 'ol')
|
326
|
+
if bullet[0,1] == '#' || bullet.size != 2 || @stack.find {|x| ulol?(x) }
|
327
|
+
count = @stack.select { |x| ulol?(x) }.size
|
328
|
+
|
329
|
+
while !@stack.empty? && count > bullet.size
|
330
|
+
count -= 1 if ulol?(@stack.last)
|
331
|
+
end_tag
|
332
|
+
end
|
333
|
+
|
334
|
+
end_tag while !@stack.empty? && @stack.last != 'li'
|
335
|
+
|
336
|
+
if @stack.last == 'li' && count == bullet.size
|
337
|
+
end_tag
|
338
|
+
if @stack.last != tag
|
339
|
+
end_tag
|
340
|
+
count -= 1
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
while count < bullet.size
|
345
|
+
start_tag tag
|
346
|
+
count += 1
|
347
|
+
start_tag 'li' if count < bullet.size
|
348
|
+
end
|
349
|
+
|
350
|
+
@p = true
|
351
|
+
start_tag('li')
|
352
|
+
parse_inline(item)
|
353
|
+
else
|
354
|
+
start_paragraph
|
355
|
+
parse_inline(line)
|
356
|
+
end
|
357
|
+
when /\A([ \t]*\S+.*?)$(\r?\n)?/
|
358
|
+
start_paragraph
|
359
|
+
parse_inline($1)
|
360
|
+
else
|
361
|
+
raise CreoleParseError, "Parse error at #{str[0,30].inspect}"
|
362
|
+
end
|
363
|
+
#p [$&, $']
|
364
|
+
str = $'
|
365
|
+
end
|
366
|
+
end_paragraph
|
367
|
+
return @out
|
368
|
+
end
|
369
|
+
|
370
|
+
end # class CreoleParser
|
371
|
+
|
372
|
+
end # module Creole
|
data/test/test_creole.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'creole'
|
3
|
+
require 'cgi'
|
4
|
+
require 'testcases'
|
5
|
+
|
6
|
+
$strict = false
|
7
|
+
|
8
|
+
class TestC < Test::Unit::TestCase
|
9
|
+
include TestCases
|
10
|
+
|
11
|
+
def tc(html, creole)
|
12
|
+
output = Creole.creolize(creole)
|
13
|
+
assert html === output, "Parsing: #{creole.inspect}\nExpected: #{html.inspect}\n Was: #{output.inspect}"
|
14
|
+
end
|
15
|
+
end
|
data/test/testcases.rb
ADDED
@@ -0,0 +1,631 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
# Test cases for the creole converter. These are included into the
|
4
|
+
# unittests, but is implemented as a separated module to be able to
|
5
|
+
# import them into demo wikis.
|
6
|
+
#
|
7
|
+
# Each test case should simply call the 'tc' method with the expected
|
8
|
+
# HTML and input Creole formatted text as arguments. The expected HTML
|
9
|
+
# should contain minimal amount of whitespace (only the absolutely
|
10
|
+
# required).
|
11
|
+
|
12
|
+
module TestCases
|
13
|
+
def escape_html(html)
|
14
|
+
CGI::escapeHTML(html)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_bold
|
18
|
+
# Creole1.0: Bold can be used inside paragraphs
|
19
|
+
tc "<p>This <strong>is</strong> bold</p>", "This **is** bold"
|
20
|
+
tc "<p>This <strong>is</strong> bold and <strong>bold</strong>ish</p>", "This **is** bold and **bold**ish"
|
21
|
+
|
22
|
+
# Creole1.0: Bold can be used inside list items
|
23
|
+
tc "<ul><li>This is <strong>bold</strong></li></ul>", "* This is **bold**"
|
24
|
+
|
25
|
+
# Creole1.0: Bold can be used inside table cells
|
26
|
+
tc("<table><tr><td>This is <strong>bold</strong></td></tr></table>",
|
27
|
+
"|This is **bold**|")
|
28
|
+
|
29
|
+
# Creole1.0: Links can appear inside bold text:
|
30
|
+
tc("<p>A bold link: <strong><a href=\"http://wikicreole.org/\">http://wikicreole.org/</a> nice!</strong></p>",
|
31
|
+
"A bold link: **http://wikicreole.org/ nice!**")
|
32
|
+
|
33
|
+
# Creole1.0: Bold will end at the end of paragraph
|
34
|
+
tc "<p>This <strong>is bold</strong></p>", "This **is bold"
|
35
|
+
|
36
|
+
# Creole1.0: Bold will end at the end of list items
|
37
|
+
tc("<ul><li>Item <strong>bold</strong></li><li>Item normal</li></ul>",
|
38
|
+
"* Item **bold\n* Item normal")
|
39
|
+
|
40
|
+
# Creole1.0: Bold will end at the end of table cells
|
41
|
+
tc("<table><tr><td>Item <strong>bold</strong></td><td>Another <strong>bold</strong></td></tr></table>",
|
42
|
+
"|Item **bold|Another **bold")
|
43
|
+
|
44
|
+
# Creole1.0: Bold should not cross paragraphs
|
45
|
+
tc("<p>This <strong>is</strong></p><p>bold<strong> maybe</strong></p>",
|
46
|
+
"This **is\n\nbold** maybe")
|
47
|
+
|
48
|
+
# Creole1.0-Implied: Bold should be able to cross lines
|
49
|
+
tc "<p>This <strong>is bold</strong></p>", "This **is\nbold**"
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_italic
|
53
|
+
# Creole1.0: Italic can be used inside paragraphs
|
54
|
+
tc("<p>This <em>is</em> italic</p>",
|
55
|
+
"This //is// italic")
|
56
|
+
tc("<p>This <em>is</em> italic and <em>italic</em>ish</p>",
|
57
|
+
"This //is// italic and //italic//ish")
|
58
|
+
|
59
|
+
# Creole1.0: Italic can be used inside list items
|
60
|
+
tc "<ul><li>This is <em>italic</em></li></ul>", "* This is //italic//"
|
61
|
+
|
62
|
+
# Creole1.0: Italic can be used inside table cells
|
63
|
+
tc("<table><tr><td>This is <em>italic</em></td></tr></table>",
|
64
|
+
"|This is //italic//|")
|
65
|
+
|
66
|
+
# Creole1.0: Links can appear inside italic text:
|
67
|
+
tc("<p>A italic link: <em><a href=\"http://wikicreole.org/\">http://wikicreole.org/</a> nice!</em></p>",
|
68
|
+
"A italic link: //http://wikicreole.org/ nice!//")
|
69
|
+
|
70
|
+
# Creole1.0: Italic will end at the end of paragraph
|
71
|
+
tc "<p>This <em>is italic</em></p>", "This //is italic"
|
72
|
+
|
73
|
+
# Creole1.0: Italic will end at the end of list items
|
74
|
+
tc("<ul><li>Item <em>italic</em></li><li>Item normal</li></ul>",
|
75
|
+
"* Item //italic\n* Item normal")
|
76
|
+
|
77
|
+
# Creole1.0: Italic will end at the end of table cells
|
78
|
+
tc("<table><tr><td>Item <em>italic</em></td><td>Another <em>italic</em></td></tr></table>",
|
79
|
+
"|Item //italic|Another //italic")
|
80
|
+
|
81
|
+
# Creole1.0: Italic should not cross paragraphs
|
82
|
+
tc("<p>This <em>is</em></p><p>italic<em> maybe</em></p>",
|
83
|
+
"This //is\n\nitalic// maybe")
|
84
|
+
|
85
|
+
# Creole1.0-Implied: Italic should be able to cross lines
|
86
|
+
tc "<p>This <em>is italic</em></p>", "This //is\nitalic//"
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_bold_italics
|
90
|
+
# Creole1.0: By example
|
91
|
+
tc "<p><strong><em>bold italics</em></strong></p>", "**//bold italics//**"
|
92
|
+
|
93
|
+
# Creole1.0: By example
|
94
|
+
tc "<p><em><strong>bold italics</strong></em></p>", "//**bold italics**//"
|
95
|
+
|
96
|
+
# Creole1.0: By example
|
97
|
+
tc "<p><em>This is <strong>also</strong> good.</em></p>", "//This is **also** good.//"
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_headings
|
101
|
+
# Creole1.0: Only three differed sized levels of heading are required.
|
102
|
+
tc "<h1>Heading 1</h1>", "= Heading 1 ="
|
103
|
+
tc "<h2>Heading 2</h2>", "== Heading 2 =="
|
104
|
+
tc "<h3>Heading 3</h3>", "=== Heading 3 ==="
|
105
|
+
unless $strict
|
106
|
+
tc "<h4>Heading 4</h4>", "==== Heading 4 ===="
|
107
|
+
tc "<h5>Heading 5</h5>", "===== Heading 5 ====="
|
108
|
+
tc "<h6>Heading 6</h6>", "====== Heading 6 ======"
|
109
|
+
end
|
110
|
+
|
111
|
+
# Creole1.0: Closing (right-side) equal signs are optional
|
112
|
+
tc "<h1>Heading 1</h1>", "=Heading 1"
|
113
|
+
tc "<h2>Heading 2</h2>", "== Heading 2"
|
114
|
+
tc "<h3>Heading 3</h3>", " === Heading 3"
|
115
|
+
|
116
|
+
# Creole1.0: Closing (right-side) equal signs don't need to be balanced and don't impact the kind of heading generated
|
117
|
+
tc "<h1>Heading 1</h1>", "=Heading 1 ==="
|
118
|
+
tc "<h2>Heading 2</h2>", "== Heading 2 ="
|
119
|
+
tc "<h3>Heading 3</h3>", " === Heading 3 ==========="
|
120
|
+
|
121
|
+
# Creole1.0: Whitespace is allowed before the left-side equal signs.
|
122
|
+
tc "<h1>Heading 1</h1>", " \t= Heading 1 ="
|
123
|
+
tc "<h2>Heading 2</h2>", " \t== Heading 2 =="
|
124
|
+
|
125
|
+
# Creole1.0: Only white-space characters are permitted after the closing equal signs.
|
126
|
+
tc "<h1>Heading 1</h1>", " = Heading 1 = "
|
127
|
+
tc "<h2>Heading 2</h2>", " == Heading 2 == \t "
|
128
|
+
|
129
|
+
# !!Creole1.0 doesn't specify if text after closing equal signs
|
130
|
+
# !!becomes part of the heading or invalidates the entire heading.
|
131
|
+
# tc "<p> == Heading 2 == foo</p>", " == Heading 2 == foo"
|
132
|
+
unless $strict
|
133
|
+
tc "<h2>Heading 2 == foo</h2>", " == Heading 2 == foo"
|
134
|
+
end
|
135
|
+
|
136
|
+
# Creole1.0-Implied: Line must start with equal sign
|
137
|
+
tc "<p>foo = Heading 1 =</p>", "foo = Heading 1 ="
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_links
|
141
|
+
# Creole1.0: Links
|
142
|
+
tc "<p><a href=\"link\">link</a></p>", "[[link]]"
|
143
|
+
|
144
|
+
# Creole1.0: Links can appear in paragraphs (i.e. inline item)
|
145
|
+
tc "<p>Hello, <a href=\"world\">world</a></p>", "Hello, [[world]]"
|
146
|
+
|
147
|
+
# Creole1.0: Named links
|
148
|
+
tc "<p><a href=\"MyBigPage\">Go to my page</a></p>", "[[MyBigPage|Go to my page]]"
|
149
|
+
|
150
|
+
# Creole1.0: URLs
|
151
|
+
tc "<p><a href=\"http://www.wikicreole.org/\">http://www.wikicreole.org/</a></p>", "[[http://www.wikicreole.org/]]"
|
152
|
+
|
153
|
+
# Creole1.0: Free-standing URL's should be turned into links
|
154
|
+
tc "<p><a href=\"http://www.wikicreole.org/\">http://www.wikicreole.org/</a></p>", "http://www.wikicreole.org/"
|
155
|
+
|
156
|
+
# Creole1.0: Single punctuation characters at the end of URLs
|
157
|
+
# should not be considered a part of the URL.
|
158
|
+
[',','.','?','!',':',';','\'','"'].each { |punct|
|
159
|
+
esc_punct = escape_html(punct)
|
160
|
+
tc "<p><a href=\"http://www.wikicreole.org/\">http://www.wikicreole.org/</a>#{esc_punct}</p>", "http://www.wikicreole.org/#{punct}"
|
161
|
+
}
|
162
|
+
# Creole1.0: Nameds URLs (by example)
|
163
|
+
tc("<p><a href=\"http://www.wikicreole.org/\">Visit the WikiCreole website</a></p>",
|
164
|
+
"[[http://www.wikicreole.org/|Visit the WikiCreole website]]")
|
165
|
+
|
166
|
+
unless $strict
|
167
|
+
# Parsing markup within a link is optional
|
168
|
+
tc "<p><a href=\"Weird+Stuff\">**Weird** //Stuff//</a></p>", "[[Weird Stuff|**Weird** //Stuff//]]"
|
169
|
+
end
|
170
|
+
|
171
|
+
# Inside bold
|
172
|
+
tc "<p><strong><a href=\"link\">link</a></strong></p>", "**[[link]]**"
|
173
|
+
|
174
|
+
# Whitespace inside [[ ]] should be ignored
|
175
|
+
tc("<p><a href=\"link\">link</a></p>", "[[ link ]]")
|
176
|
+
tc("<p><a href=\"link+me\">link me</a></p>", "[[ link me ]]")
|
177
|
+
tc("<p><a href=\"http://dot.com/\">dot.com</a></p>", "[[ http://dot.com/ \t| \t dot.com ]]")
|
178
|
+
tc("<p><a href=\"http://dot.com/\">dot.com</a></p>", "[[ http://dot.com/ | dot.com ]]")
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_paragraph
|
182
|
+
# Creole1.0: One or more blank lines end paragraphs.
|
183
|
+
tc "<p>This is my text.</p><p>This is more text.</p>", "This is\nmy text.\n\nThis is\nmore text."
|
184
|
+
tc "<p>This is my text.</p><p>This is more text.</p>", "This is\nmy text.\n\n\nThis is\nmore text."
|
185
|
+
tc "<p>This is my text.</p><p>This is more text.</p>", "This is\nmy text.\n\n\n\nThis is\nmore text."
|
186
|
+
|
187
|
+
# Creole1.0: A list end paragraphs too.
|
188
|
+
tc "<p>Hello</p><ul><li>Item</li></ul>", "Hello\n* Item\n"
|
189
|
+
|
190
|
+
# Creole1.0: A table end paragraphs too.
|
191
|
+
tc "<p>Hello</p><table><tr><td>Cell</td></tr></table>", "Hello\n|Cell|"
|
192
|
+
|
193
|
+
# Creole1.0: A nowiki end paragraphs too.
|
194
|
+
tc "<p>Hello</p><pre>nowiki</pre>", "Hello\n{{{\nnowiki\n}}}\n"
|
195
|
+
|
196
|
+
unless $strict
|
197
|
+
# A heading ends a paragraph (not specced)
|
198
|
+
tc "<p>Hello</p><h1>Heading</h1>", "Hello\n= Heading =\n"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_linebreak
|
203
|
+
# Creole1.0: \\ (wiki-style) for line breaks.
|
204
|
+
tc "<p>This is the first line,<br/>and this is the second.</p>", "This is the first line,\\\\and this is the second."
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_unordered_lists
|
208
|
+
# Creole1.0: List items begin with a * at the beginning of a line.
|
209
|
+
# Creole1.0: An item ends at the next *
|
210
|
+
tc "<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>", "* Item 1\n *Item 2\n *\t\tItem 3\n"
|
211
|
+
|
212
|
+
# Creole1.0: Whitespace is optional before and after the *.
|
213
|
+
tc("<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>",
|
214
|
+
" * Item 1\n*Item 2\n \t*\t\tItem 3\n")
|
215
|
+
|
216
|
+
# Creole1.0: A space is required if if the list element starts with bold text.
|
217
|
+
tc("<ul><li><ul><li><ul><li>Item 1</li></ul></li></ul></li></ul>", "***Item 1")
|
218
|
+
tc("<ul><li><strong>Item 1</strong></li></ul>", "* **Item 1")
|
219
|
+
|
220
|
+
# Creole1.0: An item ends at blank line
|
221
|
+
tc("<ul><li>Item</li></ul><p>Par</p>", "* Item\n\nPar\n")
|
222
|
+
|
223
|
+
# Creole1.0: An item ends at a heading
|
224
|
+
tc("<ul><li>Item</li></ul><h1>Heading</h1>", "* Item\n= Heading =\n")
|
225
|
+
|
226
|
+
# Creole1.0: An item ends at a table
|
227
|
+
tc("<ul><li>Item</li></ul><table><tr><td>Cell</td></tr></table>", "* Item\n|Cell|\n")
|
228
|
+
|
229
|
+
# Creole1.0: An item ends at a nowiki block
|
230
|
+
tc("<ul><li>Item</li></ul><pre>Code</pre>", "* Item\n{{{\nCode\n}}}\n")
|
231
|
+
|
232
|
+
# Creole1.0: An item can span multiple lines
|
233
|
+
tc("<ul><li>The quick brown fox jumps over lazy dog.</li><li>Humpty Dumpty sat on a wall.</li></ul>",
|
234
|
+
"* The quick\nbrown fox\n\tjumps over\nlazy dog.\n*Humpty Dumpty\nsat\t\non a wall.")
|
235
|
+
|
236
|
+
# Creole1.0: An item can contain line breaks
|
237
|
+
tc("<ul><li>The quick brown<br/>fox jumps over lazy dog.</li></ul>",
|
238
|
+
"* The quick brown\\\\fox jumps over lazy dog.")
|
239
|
+
|
240
|
+
# Creole1.0: Nested
|
241
|
+
tc "<ul><li>Item 1<ul><li>Item 2</li></ul></li><li>Item 3</li></ul>", "* Item 1\n **Item 2\n *\t\tItem 3\n"
|
242
|
+
|
243
|
+
# Creole1.0: Nested up to 5 levels
|
244
|
+
tc("<ul><li>Item 1<ul><li>Item 2<ul><li>Item 3<ul><li>Item 4<ul><li>Item 5</li></ul></li></ul></li></ul></li></ul></li></ul>",
|
245
|
+
"*Item 1\n**Item 2\n***Item 3\n****Item 4\n*****Item 5\n")
|
246
|
+
|
247
|
+
# Creole1.0: ** immediatly following a list element will be treated as a nested unordered element.
|
248
|
+
tc("<ul><li>Hello, World!<ul><li>Not bold</li></ul></li></ul>",
|
249
|
+
"*Hello,\nWorld!\n**Not bold\n")
|
250
|
+
|
251
|
+
# Creole1.0: ** immediatly following a list element will be treated as a nested unordered element.
|
252
|
+
tc("<ol><li>Hello, World!<ul><li>Not bold</li></ul></li></ol>",
|
253
|
+
"#Hello,\nWorld!\n**Not bold\n")
|
254
|
+
|
255
|
+
# Creole1.0: [...] otherwise it will be treated as the beginning of bold text.
|
256
|
+
tc("<ul><li>Hello, World!</li></ul><p><strong>Not bold</strong></p>",
|
257
|
+
"*Hello,\nWorld!\n\n**Not bold\n")
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_ordered_lists
|
261
|
+
# Creole1.0: List items begin with a * at the beginning of a line.
|
262
|
+
# Creole1.0: An item ends at the next *
|
263
|
+
tc "<ol><li>Item 1</li><li>Item 2</li><li>Item 3</li></ol>", "# Item 1\n #Item 2\n #\t\tItem 3\n"
|
264
|
+
|
265
|
+
# Creole1.0: Whitespace is optional before and after the #.
|
266
|
+
tc("<ol><li>Item 1</li><li>Item 2</li><li>Item 3</li></ol>",
|
267
|
+
" # Item 1\n#Item 2\n \t#\t\tItem 3\n")
|
268
|
+
|
269
|
+
# Creole1.0: A space is required if if the list element starts with bold text.
|
270
|
+
tc("<ol><li><ol><li><ol><li>Item 1</li></ol></li></ol></li></ol>", "###Item 1")
|
271
|
+
tc("<ol><li><strong>Item 1</strong></li></ol>", "# **Item 1")
|
272
|
+
|
273
|
+
# Creole1.0: An item ends at blank line
|
274
|
+
tc("<ol><li>Item</li></ol><p>Par</p>", "# Item\n\nPar\n")
|
275
|
+
|
276
|
+
# Creole1.0: An item ends at a heading
|
277
|
+
tc("<ol><li>Item</li></ol><h1>Heading</h1>", "# Item\n= Heading =\n")
|
278
|
+
|
279
|
+
# Creole1.0: An item ends at a table
|
280
|
+
tc("<ol><li>Item</li></ol><table><tr><td>Cell</td></tr></table>", "# Item\n|Cell|\n")
|
281
|
+
|
282
|
+
# Creole1.0: An item ends at a nowiki block
|
283
|
+
tc("<ol><li>Item</li></ol><pre>Code</pre>", "# Item\n{{{\nCode\n}}}\n")
|
284
|
+
|
285
|
+
# Creole1.0: An item can span multiple lines
|
286
|
+
tc("<ol><li>The quick brown fox jumps over lazy dog.</li><li>Humpty Dumpty sat on a wall.</li></ol>",
|
287
|
+
"# The quick\nbrown fox\n\tjumps over\nlazy dog.\n#Humpty Dumpty\nsat\t\non a wall.")
|
288
|
+
|
289
|
+
# Creole1.0: An item can contain line breaks
|
290
|
+
tc("<ol><li>The quick brown<br/>fox jumps over lazy dog.</li></ol>",
|
291
|
+
"# The quick brown\\\\fox jumps over lazy dog.")
|
292
|
+
|
293
|
+
# Creole1.0: Nested
|
294
|
+
tc "<ol><li>Item 1<ol><li>Item 2</li></ol></li><li>Item 3</li></ol>", "# Item 1\n ##Item 2\n #\t\tItem 3\n"
|
295
|
+
|
296
|
+
# Creole1.0: Nested up to 5 levels
|
297
|
+
tc("<ol><li>Item 1<ol><li>Item 2<ol><li>Item 3<ol><li>Item 4<ol><li>Item 5</li></ol></li></ol></li></ol></li></ol></li></ol>",
|
298
|
+
"#Item 1\n##Item 2\n###Item 3\n####Item 4\n#####Item 5\n")
|
299
|
+
|
300
|
+
# Creole1.0_Infered: The two-bullet rule only applies to **.
|
301
|
+
tc("<ol><li><ol><li>Item</li></ol></li></ol>", "##Item")
|
302
|
+
end
|
303
|
+
|
304
|
+
def test_ordered_lists2
|
305
|
+
tc "<ol><li>Item 1</li><li>Item 2</li><li>Item 3</li></ol>", "# Item 1\n #Item 2\n #\t\tItem 3\n"
|
306
|
+
# Nested
|
307
|
+
tc "<ol><li>Item 1<ol><li>Item 2</li></ol></li><li>Item 3</li></ol>", "# Item 1\n ##Item 2\n #\t\tItem 3\n"
|
308
|
+
# Multiline
|
309
|
+
tc "<ol><li>Item 1 on multiple lines</li></ol>", "# Item 1\non multiple lines"
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_ambiguity_mixed_lists
|
313
|
+
# ol following ul
|
314
|
+
tc("<ul><li>uitem</li></ul><ol><li>oitem</li></ol>", "*uitem\n#oitem\n")
|
315
|
+
|
316
|
+
# ul following ol
|
317
|
+
tc("<ol><li>uitem</li></ol><ul><li>oitem</li></ul>", "#uitem\n*oitem\n")
|
318
|
+
|
319
|
+
# 2ol following ul
|
320
|
+
tc("<ul><li>uitem<ol><li>oitem</li></ol></li></ul>", "*uitem\n##oitem\n")
|
321
|
+
|
322
|
+
# 2ul following ol
|
323
|
+
tc("<ol><li>uitem<ul><li>oitem</li></ul></li></ol>", "#uitem\n**oitem\n")
|
324
|
+
|
325
|
+
# 3ol following 3ul
|
326
|
+
tc("<ul><li><ul><li><ul><li>uitem</li></ul><ol><li>oitem</li></ol></li></ul></li></ul>", "***uitem\n###oitem\n")
|
327
|
+
|
328
|
+
# 2ul following 2ol
|
329
|
+
tc("<ol><li><ol><li>uitem</li></ol><ul><li>oitem</li></ul></li></ol>", "##uitem\n**oitem\n")
|
330
|
+
|
331
|
+
# ol following 2ol
|
332
|
+
tc("<ol><li><ol><li>oitem1</li></ol></li><li>oitem2</li></ol>", "##oitem1\n#oitem2\n")
|
333
|
+
# ul following 2ol
|
334
|
+
tc("<ol><li><ol><li>oitem1</li></ol></li></ol><ul><li>oitem2</li></ul>", "##oitem1\n*oitem2\n")
|
335
|
+
end
|
336
|
+
|
337
|
+
def test_ambiguity_italics_and_url
|
338
|
+
# Uncommon URL schemes should not be parsed as URLs
|
339
|
+
tc("<p>This is what can go wrong:<em>this should be an italic text</em>.</p>",
|
340
|
+
"This is what can go wrong://this should be an italic text//.")
|
341
|
+
|
342
|
+
# A link inside italic text
|
343
|
+
tc("<p>How about <em>a link, like <a href=\"http://example.org\">http://example.org</a>, in italic</em> text?</p>",
|
344
|
+
"How about //a link, like http://example.org, in italic// text?")
|
345
|
+
|
346
|
+
# Another test from Creole Wiki
|
347
|
+
tc("<p>Formatted fruits, for example:<em>apples</em>, oranges, <strong>pears</strong> ...</p>",
|
348
|
+
"Formatted fruits, for example://apples//, oranges, **pears** ...")
|
349
|
+
|
350
|
+
tc("<p>Blablabala (<a href=\"http://blub.de\">http://blub.de</a>)</p>",
|
351
|
+
"Blablabala (http://blub.de)")
|
352
|
+
end
|
353
|
+
|
354
|
+
def test_ambiguity_bold_and_lists
|
355
|
+
tc "<p><strong> bold text </strong></p>", "** bold text **"
|
356
|
+
tc "<p> <strong> bold text </strong></p>", " ** bold text **"
|
357
|
+
end
|
358
|
+
|
359
|
+
def test_nowiki
|
360
|
+
# ... works as block
|
361
|
+
tc "<pre>Hello</pre>", "{{{\nHello\n}}}\n"
|
362
|
+
|
363
|
+
# ... works inline
|
364
|
+
tc "<p>Hello <tt>world</tt>.</p>", "Hello {{{world}}}."
|
365
|
+
|
366
|
+
# Creole1.0: No wiki markup is interpreted inbetween
|
367
|
+
tc "<pre>**Hello**</pre>", "{{{\n**Hello**\n}}}\n"
|
368
|
+
|
369
|
+
# Creole1.0: Leading whitespaces are not permitted
|
370
|
+
tc("<p> {{{ Hello }}}</p>", " {{{\nHello\n}}}")
|
371
|
+
tc("<p>{{{ Hello }}}</p>", "{{{\nHello\n }}}")
|
372
|
+
|
373
|
+
# Assumed: Should preserve whitespace
|
374
|
+
tc("<pre> \t Hello, \t \n \t World \t </pre>",
|
375
|
+
"{{{\n \t Hello, \t \n \t World \t \n}}}\n")
|
376
|
+
|
377
|
+
# In preformatted blocks ... one leading space is removed
|
378
|
+
tc("<pre>nowikiblock\n}}}</pre>", "{{{\nnowikiblock\n }}}\n}}}\n")
|
379
|
+
|
380
|
+
# In inline nowiki, any trailing closing brace is included in the span
|
381
|
+
tc("<p>this is <tt>nowiki}</tt></p>", "this is {{{nowiki}}}}")
|
382
|
+
tc("<p>this is <tt>nowiki}}</tt></p>", "this is {{{nowiki}}}}}")
|
383
|
+
tc("<p>this is <tt>nowiki}}}</tt></p>", "this is {{{nowiki}}}}}}")
|
384
|
+
tc("<p>this is <tt>nowiki}}}}</tt></p>", "this is {{{nowiki}}}}}}}")
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_html_escaping
|
388
|
+
# Special HTML chars should be escaped
|
389
|
+
tc("<p><b>not bold</b></p>", "<b>not bold</b>")
|
390
|
+
|
391
|
+
# Image tags should be escape
|
392
|
+
tc("<p><img src=\"image.jpg\" alt=\""tag"\"/></p>", "{{image.jpg|\"tag\"}}")
|
393
|
+
|
394
|
+
# Malicious links should not be converted.
|
395
|
+
tc("<p><a href=\"javascript%3Aalert%28%22Boo%21%22%29\">Click</a></p>", "[[javascript:alert(\"Boo!\")|Click]]")
|
396
|
+
end
|
397
|
+
|
398
|
+
def test_escape
|
399
|
+
tc "<p>** Not Bold **</p>", "~** Not Bold ~**"
|
400
|
+
tc "<p>// Not Italic //</p>", "~// Not Italic ~//"
|
401
|
+
tc "<p>* Not Bullet</p>", "~* Not Bullet"
|
402
|
+
# Following char is not a blank (space or line feed)
|
403
|
+
tc "<p>Hello ~ world</p>", "Hello ~ world\n"
|
404
|
+
tc "<p>Hello ~ world</p>", "Hello ~\nworld\n"
|
405
|
+
# Not escaping inside URLs (Creole1.0 not clear on this)
|
406
|
+
tc "<p><a href=\"http://example.org/~user/\">http://example.org/~user/</a></p>", "http://example.org/~user/"
|
407
|
+
|
408
|
+
# Escaping links
|
409
|
+
tc "<p>http://www.wikicreole.org/</p>", "~http://www.wikicreole.org/"
|
410
|
+
end
|
411
|
+
|
412
|
+
def test_horizontal_rule
|
413
|
+
# Creole: Four hyphens make a horizontal rule
|
414
|
+
tc "<hr/>", "----"
|
415
|
+
|
416
|
+
# Creole1.0: Whitespace around them is allowed
|
417
|
+
tc "<hr/>", " ----"
|
418
|
+
tc "<hr/>", "---- "
|
419
|
+
tc "<hr/>", " ---- "
|
420
|
+
tc "<hr/>", " \t ---- \t "
|
421
|
+
|
422
|
+
# Creole1.0: Nothing else than hyphens and whitespace is "allowed"
|
423
|
+
tc "<p>foo ----</p>", "foo ----\n"
|
424
|
+
tc "<p>---- foo</p>", "---- foo\n"
|
425
|
+
|
426
|
+
# Creole1.0: [...] no whitespace is allowed between them
|
427
|
+
tc "<p> -- -- </p>", " -- -- "
|
428
|
+
tc "<p> -- -- </p>", " --\t-- "
|
429
|
+
end
|
430
|
+
|
431
|
+
def test_table
|
432
|
+
tc "<table><tr><td>Hello, World!</td></tr></table>", "|Hello, World!|"
|
433
|
+
# Multiple columns
|
434
|
+
tc "<table><tr><td>c1</td><td>c2</td><td>c3</td></tr></table>", "|c1|c2|c3|"
|
435
|
+
# Multiple rows
|
436
|
+
tc "<table><tr><td>c11</td><td>c12</td></tr><tr><td>c21</td><td>c22</td></tr></table>", "|c11|c12|\n|c21|c22|\n"
|
437
|
+
# End pipe is optional
|
438
|
+
tc "<table><tr><td>c1</td><td>c2</td><td>c3</td></tr></table>", "|c1|c2|c3"
|
439
|
+
# Empty cells
|
440
|
+
tc "<table><tr><td>c1</td><td></td><td>c3</td></tr></table>", "|c1||c3"
|
441
|
+
# Escaping cell separator
|
442
|
+
tc "<table><tr><td>c1|c2</td><td>c3</td></tr></table>", "|c1~|c2|c3"
|
443
|
+
# Escape in last cell + empty cell
|
444
|
+
tc "<table><tr><td>c1</td><td>c2|</td></tr></table>", "|c1|c2~|"
|
445
|
+
tc "<table><tr><td>c1</td><td>c2|</td></tr></table>", "|c1|c2~||"
|
446
|
+
tc "<table><tr><td>c1</td><td>c2|</td><td></td></tr></table>", "|c1|c2~|||"
|
447
|
+
# Equal sign after pipe make a header
|
448
|
+
tc "<table><tr><th>Header</th></tr></table>", "|=Header|"
|
449
|
+
|
450
|
+
tc "<table><tr><td>c1</td><td><a href=\"Link\">Link text</a></td><td><img src=\"Image\" alt=\"Image text\"/></td></tr></table>", "|c1|[[Link|Link text]]|{{Image|Image text}}|"
|
451
|
+
end
|
452
|
+
|
453
|
+
def test_following_table
|
454
|
+
# table followed by heading
|
455
|
+
tc("<table><tr><td>table</td></tr></table><h1>heading</h1>", "|table|\n=heading=\n")
|
456
|
+
tc("<table><tr><td>table</td></tr></table><h1>heading</h1>", "|table|\n\n=heading=\n")
|
457
|
+
# table followed by paragraph
|
458
|
+
tc("<table><tr><td>table</td></tr></table><p>par</p>", "|table|\npar\n")
|
459
|
+
tc("<table><tr><td>table</td></tr></table><p>par</p>", "|table|\n\npar\n")
|
460
|
+
# table followed by unordered list
|
461
|
+
tc("<table><tr><td>table</td></tr></table><ul><li>item</li></ul>", "|table|\n*item\n")
|
462
|
+
tc("<table><tr><td>table</td></tr></table><ul><li>item</li></ul>", "|table|\n\n*item\n")
|
463
|
+
# table followed by ordered list
|
464
|
+
tc("<table><tr><td>table</td></tr></table><ol><li>item</li></ol>", "|table|\n#item\n")
|
465
|
+
tc("<table><tr><td>table</td></tr></table><ol><li>item</li></ol>", "|table|\n\n#item\n")
|
466
|
+
# table followed by horizontal rule
|
467
|
+
tc("<table><tr><td>table</td></tr></table><hr/>", "|table|\n----\n")
|
468
|
+
tc("<table><tr><td>table</td></tr></table><hr/>", "|table|\n\n----\n")
|
469
|
+
# table followed by nowiki block
|
470
|
+
tc("<table><tr><td>table</td></tr></table><pre>pre</pre>", "|table|\n{{{\npre\n}}}\n")
|
471
|
+
tc("<table><tr><td>table</td></tr></table><pre>pre</pre>", "|table|\n\n{{{\npre\n}}}\n")
|
472
|
+
# table followed by table
|
473
|
+
tc("<table><tr><td>table</td></tr><tr><td>table</td></tr></table>", "|table|\n|table|\n")
|
474
|
+
tc("<table><tr><td>table</td></tr></table><table><tr><td>table</td></tr></table>", "|table|\n\n|table|\n")
|
475
|
+
end
|
476
|
+
|
477
|
+
def test_following_heading
|
478
|
+
# heading
|
479
|
+
tc("<h1>heading1</h1><h1>heading2</h1>", "=heading1=\n=heading2\n")
|
480
|
+
tc("<h1>heading1</h1><h1>heading2</h1>", "=heading1=\n\n=heading2\n")
|
481
|
+
# paragraph
|
482
|
+
tc("<h1>heading</h1><p>par</p>", "=heading=\npar\n")
|
483
|
+
tc("<h1>heading</h1><p>par</p>", "=heading=\n\npar\n")
|
484
|
+
# unordered list
|
485
|
+
tc("<h1>heading</h1><ul><li>item</li></ul>", "=heading=\n*item\n")
|
486
|
+
tc("<h1>heading</h1><ul><li>item</li></ul>", "=heading=\n\n*item\n")
|
487
|
+
# ordered list
|
488
|
+
tc("<h1>heading</h1><ol><li>item</li></ol>", "=heading=\n#item\n")
|
489
|
+
tc("<h1>heading</h1><ol><li>item</li></ol>", "=heading=\n\n#item\n")
|
490
|
+
# horizontal rule
|
491
|
+
tc("<h1>heading</h1><hr/>", "=heading=\n----\n")
|
492
|
+
tc("<h1>heading</h1><hr/>", "=heading=\n\n----\n")
|
493
|
+
# nowiki block
|
494
|
+
tc("<h1>heading</h1><pre>nowiki</pre>", "=heading=\n{{{\nnowiki\n}}}\n")
|
495
|
+
tc("<h1>heading</h1><pre>nowiki</pre>", "=heading=\n\n{{{\nnowiki\n}}}\n")
|
496
|
+
# table
|
497
|
+
tc("<h1>heading</h1><table><tr><td>table</td></tr></table>", "=heading=\n|table|\n")
|
498
|
+
tc("<h1>heading</h1><table><tr><td>table</td></tr></table>", "=heading=\n\n|table|\n")
|
499
|
+
end
|
500
|
+
|
501
|
+
def test_following_paragraph
|
502
|
+
# heading
|
503
|
+
tc("<p>par</p><h1>heading</h1>", "par\n=heading=")
|
504
|
+
tc("<p>par</p><h1>heading</h1>", "par\n\n=heading=")
|
505
|
+
# paragraph
|
506
|
+
tc("<p>par par</p>", "par\npar\n")
|
507
|
+
tc("<p>par</p><p>par</p>", "par\n\npar\n")
|
508
|
+
# unordered
|
509
|
+
tc("<p>par</p><ul><li>item</li></ul>", "par\n*item")
|
510
|
+
tc("<p>par</p><ul><li>item</li></ul>", "par\n\n*item")
|
511
|
+
# ordered
|
512
|
+
tc("<p>par</p><ol><li>item</li></ol>", "par\n#item\n")
|
513
|
+
tc("<p>par</p><ol><li>item</li></ol>", "par\n\n#item\n")
|
514
|
+
# horizontal
|
515
|
+
tc("<p>par</p><hr/>", "par\n----\n")
|
516
|
+
tc("<p>par</p><hr/>", "par\n\n----\n")
|
517
|
+
# nowiki
|
518
|
+
tc("<p>par</p><pre>nowiki</pre>", "par\n{{{\nnowiki\n}}}\n")
|
519
|
+
tc("<p>par</p><pre>nowiki</pre>", "par\n\n{{{\nnowiki\n}}}\n")
|
520
|
+
# table
|
521
|
+
tc("<p>par</p><table><tr><td>table</td></tr></table>", "par\n|table|\n")
|
522
|
+
tc("<p>par</p><table><tr><td>table</td></tr></table>", "par\n\n|table|\n")
|
523
|
+
end
|
524
|
+
|
525
|
+
def test_following_unordered_list
|
526
|
+
# heading
|
527
|
+
tc("<ul><li>item</li></ul><h1>heading</h1>", "*item\n=heading=")
|
528
|
+
tc("<ul><li>item</li></ul><h1>heading</h1>", "*item\n\n=heading=")
|
529
|
+
# paragraph
|
530
|
+
tc("<ul><li>item par</li></ul>", "*item\npar\n") # items may span multiple lines
|
531
|
+
tc("<ul><li>item</li></ul><p>par</p>", "*item\n\npar\n")
|
532
|
+
# unordered
|
533
|
+
tc("<ul><li>item</li><li>item</li></ul>", "*item\n*item\n")
|
534
|
+
tc("<ul><li>item</li></ul><ul><li>item</li></ul>", "*item\n\n*item\n")
|
535
|
+
# ordered
|
536
|
+
tc("<ul><li>item</li></ul><ol><li>item</li></ol>", "*item\n#item\n")
|
537
|
+
tc("<ul><li>item</li></ul><ol><li>item</li></ol>", "*item\n\n#item\n")
|
538
|
+
# horizontal rule
|
539
|
+
tc("<ul><li>item</li></ul><hr/>", "*item\n----\n")
|
540
|
+
tc("<ul><li>item</li></ul><hr/>", "*item\n\n----\n")
|
541
|
+
# nowiki
|
542
|
+
tc("<ul><li>item</li></ul><pre>nowiki</pre>", "*item\n{{{\nnowiki\n}}}\n")
|
543
|
+
tc("<ul><li>item</li></ul><pre>nowiki</pre>", "*item\n\n{{{\nnowiki\n}}}\n")
|
544
|
+
# table
|
545
|
+
tc("<ul><li>item</li></ul><table><tr><td>table</td></tr></table>", "*item\n|table|\n")
|
546
|
+
tc("<ul><li>item</li></ul><table><tr><td>table</td></tr></table>", "*item\n\n|table|\n")
|
547
|
+
end
|
548
|
+
|
549
|
+
def test_following_ordered_list
|
550
|
+
# heading
|
551
|
+
tc("<ol><li>item</li></ol><h1>heading</h1>", "#item\n=heading=")
|
552
|
+
tc("<ol><li>item</li></ol><h1>heading</h1>", "#item\n\n=heading=")
|
553
|
+
# paragraph
|
554
|
+
tc("<ol><li>item par</li></ol>", "#item\npar\n") # items may span multiple lines
|
555
|
+
tc("<ol><li>item</li></ol><p>par</p>", "#item\n\npar\n")
|
556
|
+
# unordered
|
557
|
+
tc("<ol><li>item</li></ol><ul><li>item</li></ul>", "#item\n*item\n")
|
558
|
+
tc("<ol><li>item</li></ol><ul><li>item</li></ul>", "#item\n\n*item\n")
|
559
|
+
# ordered
|
560
|
+
tc("<ol><li>item</li><li>item</li></ol>", "#item\n#item\n")
|
561
|
+
tc("<ol><li>item</li></ol><ol><li>item</li></ol>", "#item\n\n#item\n")
|
562
|
+
# horizontal role
|
563
|
+
tc("<ol><li>item</li></ol><hr/>", "#item\n----\n")
|
564
|
+
tc("<ol><li>item</li></ol><hr/>", "#item\n\n----\n")
|
565
|
+
# nowiki
|
566
|
+
tc("<ol><li>item</li></ol><pre>nowiki</pre>", "#item\n{{{\nnowiki\n}}}\n")
|
567
|
+
tc("<ol><li>item</li></ol><pre>nowiki</pre>", "#item\n\n{{{\nnowiki\n}}}\n")
|
568
|
+
# table
|
569
|
+
tc("<ol><li>item</li></ol><table><tr><td>table</td></tr></table>", "#item\n|table|\n")
|
570
|
+
tc("<ol><li>item</li></ol><table><tr><td>table</td></tr></table>", "#item\n\n|table|\n")
|
571
|
+
end
|
572
|
+
|
573
|
+
def test_following_horizontal_rule
|
574
|
+
# heading
|
575
|
+
tc("<hr/><h1>heading</h1>", "----\n=heading=")
|
576
|
+
tc("<hr/><h1>heading</h1>", "----\n\n=heading=")
|
577
|
+
# paragraph
|
578
|
+
tc("<hr/><p>par</p>", "----\npar\n")
|
579
|
+
tc("<hr/><p>par</p>", "----\n\npar\n")
|
580
|
+
# unordered
|
581
|
+
tc("<hr/><ul><li>item</li></ul>", "----\n*item")
|
582
|
+
tc("<hr/><ul><li>item</li></ul>", "----\n*item")
|
583
|
+
# ordered
|
584
|
+
tc("<hr/><ol><li>item</li></ol>", "----\n#item")
|
585
|
+
tc("<hr/><ol><li>item</li></ol>", "----\n#item")
|
586
|
+
# horizontal
|
587
|
+
tc("<hr/><hr/>", "----\n----\n")
|
588
|
+
tc("<hr/><hr/>", "----\n\n----\n")
|
589
|
+
# nowiki
|
590
|
+
tc("<hr/><pre>nowiki</pre>", "----\n{{{\nnowiki\n}}}\n")
|
591
|
+
tc("<hr/><pre>nowiki</pre>", "----\n\n{{{\nnowiki\n}}}\n")
|
592
|
+
# table
|
593
|
+
tc("<hr/><table><tr><td>table</td></tr></table>", "----\n|table|\n")
|
594
|
+
tc("<hr/><table><tr><td>table</td></tr></table>", "----\n\n|table|\n")
|
595
|
+
end
|
596
|
+
|
597
|
+
def test_following_nowiki_block
|
598
|
+
# heading
|
599
|
+
tc("<pre>nowiki</pre><h1>heading</h1>", "{{{\nnowiki\n}}}\n=heading=")
|
600
|
+
tc("<pre>nowiki</pre><h1>heading</h1>", "{{{\nnowiki\n}}}\n\n=heading=")
|
601
|
+
# paragraph
|
602
|
+
tc("<pre>nowiki</pre><p>par</p>", "{{{\nnowiki\n}}}\npar")
|
603
|
+
tc("<pre>nowiki</pre><p>par</p>", "{{{\nnowiki\n}}}\n\npar")
|
604
|
+
# unordered
|
605
|
+
tc("<pre>nowiki</pre><ul><li>item</li></ul>", "{{{\nnowiki\n}}}\n*item\n")
|
606
|
+
tc("<pre>nowiki</pre><ul><li>item</li></ul>", "{{{\nnowiki\n}}}\n\n*item\n")
|
607
|
+
# ordered
|
608
|
+
tc("<pre>nowiki</pre><ol><li>item</li></ol>", "{{{\nnowiki\n}}}\n#item\n")
|
609
|
+
tc("<pre>nowiki</pre><ol><li>item</li></ol>", "{{{\nnowiki\n}}}\n\n#item\n")
|
610
|
+
# horizontal
|
611
|
+
tc("<pre>nowiki</pre><hr/>", "{{{\nnowiki\n}}}\n----\n")
|
612
|
+
tc("<pre>nowiki</pre><hr/>", "{{{\nnowiki\n}}}\n\n----\n")
|
613
|
+
# nowiki
|
614
|
+
tc("<pre>nowiki</pre><pre>nowiki</pre>", "{{{\nnowiki\n}}}\n{{{\nnowiki\n}}}\n")
|
615
|
+
tc("<pre>nowiki</pre><pre>nowiki</pre>", "{{{\nnowiki\n}}}\n\n{{{\nnowiki\n}}}\n")
|
616
|
+
# table
|
617
|
+
tc("<pre>nowiki</pre><table><tr><td>table</td></tr></table>", "{{{\nnowiki\n}}}\n|table|\n")
|
618
|
+
tc("<pre>nowiki</pre><table><tr><td>table</td></tr></table>", "{{{\nnowiki\n}}}\n\n|table|\n")
|
619
|
+
end
|
620
|
+
|
621
|
+
def test_image
|
622
|
+
tc("<p><img src=\"image.jpg\"/></p>", "{{image.jpg}}")
|
623
|
+
tc("<p><img src=\"image.jpg\" alt=\"tag\"/></p>", "{{image.jpg|tag}}")
|
624
|
+
tc("<p><img src=\"http://example.org/image.jpg\"/></p>", "{{http://example.org/image.jpg}}")
|
625
|
+
end
|
626
|
+
|
627
|
+
def test_bold_combo
|
628
|
+
tc("<p><strong>bold and</strong></p><table><tr><td>table</td></tr></table><p>end<strong></strong></p>",
|
629
|
+
"**bold and\n|table|\nend**")
|
630
|
+
end
|
631
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: creole
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Lars Christensen
|
8
|
+
- Daniel Mendler
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-02-16 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: hoe
|
18
|
+
type: :development
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.8.3
|
25
|
+
version:
|
26
|
+
description: Creole is a Creole-to-HTML converter for Creole, the lightwight markup language (http://wikicreole.org/).
|
27
|
+
email:
|
28
|
+
- larsch@belunktum.dk
|
29
|
+
- mail@daniel-mendler.de
|
30
|
+
executables: []
|
31
|
+
|
32
|
+
extensions: []
|
33
|
+
|
34
|
+
extra_rdoc_files:
|
35
|
+
- Manifest.txt
|
36
|
+
- README.txt
|
37
|
+
files:
|
38
|
+
- Manifest.txt
|
39
|
+
- README.txt
|
40
|
+
- Rakefile
|
41
|
+
- lib/creole.rb
|
42
|
+
- test/test_creole.rb
|
43
|
+
- test/testcases.rb
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://github.com/minad/creole
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options:
|
48
|
+
- --main
|
49
|
+
- README.txt
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project: creole
|
67
|
+
rubygems_version: 1.3.1
|
68
|
+
signing_key:
|
69
|
+
specification_version: 2
|
70
|
+
summary: Creole is a Creole-to-HTML converter for Creole, the lightwight markup language (http://wikicreole.org/).
|
71
|
+
test_files:
|
72
|
+
- test/test_creole.rb
|