creole 0.3.8 → 0.4.0
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/lib/creole.rb +4 -380
- data/lib/creole/parser.rb +379 -0
- data/lib/creole/template.rb +20 -0
- data/lib/creole/version.rb +3 -0
- data/test/{creole_test.rb → parser_test.rb} +1 -1
- data/test/template_test.rb +12 -0
- metadata +17 -12
- data/Manifest.txt +0 -5
data/lib/creole.rb
CHANGED
@@ -1,44 +1,7 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
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
|
-
# Main Creole parser class. Call CreoleParser#parse to parse Creole
|
31
|
-
# formatted text.
|
32
|
-
#
|
33
|
-
# This class is not reentrant. A separate instance is needed for
|
34
|
-
# each thread that needs to convert Creole to HTML.
|
35
|
-
#
|
36
|
-
# Inherit this to provide custom handling of links. The overrideable
|
37
|
-
# methods are: make_local_link
|
38
|
-
class Creole
|
39
|
-
|
40
|
-
VERSION = '0.3.8'
|
1
|
+
require 'creole/parser'
|
2
|
+
require 'creole/version'
|
41
3
|
|
4
|
+
module Creole
|
42
5
|
# Convert the argument in Creole format to HTML and return the
|
43
6
|
# result. Example:
|
44
7
|
#
|
@@ -48,345 +11,6 @@ class Creole
|
|
48
11
|
# This is an alias for calling Creole#parse:
|
49
12
|
# Creole.new(text).to_html
|
50
13
|
def self.creolize(text, options = {})
|
51
|
-
new(text, options).to_html
|
52
|
-
end
|
53
|
-
|
54
|
-
# Allowed url schemes
|
55
|
-
# Examples: http https ftp ftps
|
56
|
-
attr_accessor :allowed_schemes
|
57
|
-
|
58
|
-
# Non-standard wiki text extensions enabled?
|
59
|
-
# E.g. underlined, deleted text etc
|
60
|
-
attr_writer :extensions
|
61
|
-
def extensions?; @extensions; end
|
62
|
-
|
63
|
-
# Disable url escaping for local links
|
64
|
-
# Escaping: [[/Test]] --> %2FTest
|
65
|
-
# No escaping: [[/Test]] --> Test
|
66
|
-
attr_writer :no_escape
|
67
|
-
def no_escape?; @no_escape; end
|
68
|
-
|
69
|
-
# Create a new CreoleParser instance.
|
70
|
-
def initialize(text, options = {})
|
71
|
-
@allowed_schemes = %w(http https ftp ftps)
|
72
|
-
@text = text
|
73
|
-
options.each_pair {|k,v| send("#{k}=", v) }
|
74
|
-
end
|
75
|
-
|
76
|
-
# Convert CCreole text to HTML and return
|
77
|
-
# the result. The resulting HTML does not contain <html> and
|
78
|
-
# <body> tags.
|
79
|
-
#
|
80
|
-
# Example:
|
81
|
-
#
|
82
|
-
# parser = CreoleParser.new("**Hello //World//**", :extensions => true)
|
83
|
-
# parser.to_html
|
84
|
-
# #=> "<p><strong>Hello <em>World</em></strong></p>"
|
85
|
-
def to_html
|
86
|
-
@out = ''
|
87
|
-
@p = false
|
88
|
-
@stack = []
|
89
|
-
parse_block(@text)
|
90
|
-
@out
|
91
|
-
end
|
92
|
-
|
93
|
-
protected
|
94
|
-
|
95
|
-
# Escape any characters with special meaning in HTML using HTML
|
96
|
-
# entities.
|
97
|
-
def escape_html(string)
|
98
|
-
CGI::escapeHTML(string)
|
99
|
-
end
|
100
|
-
|
101
|
-
# Escape any characters with special meaning in URLs using URL
|
102
|
-
# encoding.
|
103
|
-
def escape_url(string)
|
104
|
-
CGI::escape(string)
|
105
|
-
end
|
106
|
-
|
107
|
-
def start_tag(tag)
|
108
|
-
@stack.push(tag)
|
109
|
-
@out << '<' << tag << '>'
|
110
|
-
end
|
111
|
-
|
112
|
-
def end_tag
|
113
|
-
@out << '</' << @stack.pop << '>'
|
114
|
-
end
|
115
|
-
|
116
|
-
def toggle_tag(tag, match)
|
117
|
-
if @stack.include?(tag)
|
118
|
-
if @stack.last == tag
|
119
|
-
end_tag
|
120
|
-
else
|
121
|
-
@out << escape_html(match)
|
122
|
-
end
|
123
|
-
else
|
124
|
-
start_tag(tag)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def end_paragraph
|
129
|
-
end_tag while !@stack.empty?
|
130
|
-
@p = false
|
131
|
-
end
|
132
|
-
|
133
|
-
def start_paragraph
|
134
|
-
if @p
|
135
|
-
@out << ' ' if @out[-1,1] != ' '
|
136
|
-
else
|
137
|
-
end_paragraph
|
138
|
-
start_tag('p')
|
139
|
-
@p = true
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
# Create anchor markup for direct links. This
|
144
|
-
# method can be overridden to generate custom
|
145
|
-
# markup, for example to add html additional attributes.
|
146
|
-
def make_direct_anchor(uri, text)
|
147
|
-
'<a href="' << escape_html(uri) << '">' << escape_html(text) << '</a>'
|
148
|
-
end
|
149
|
-
|
150
|
-
# Create anchor markup for explicit links. This
|
151
|
-
# method can be overridden to generate custom
|
152
|
-
# markup, for example to add html additional attributes.
|
153
|
-
def make_explicit_anchor(uri, text)
|
154
|
-
'<a href="' << escape_html(uri) << '">' << escape_html(text) << '</a>'
|
155
|
-
end
|
156
|
-
|
157
|
-
# Translate an explicit local link to a desired URL that is
|
158
|
-
# properly URL-escaped. The default behaviour is to convert local
|
159
|
-
# links directly, escaping any characters that have special
|
160
|
-
# meaning in URLs. Relative URLs in local links are not handled.
|
161
|
-
#
|
162
|
-
# Examples:
|
163
|
-
#
|
164
|
-
# make_local_link("LocalLink") #=> "LocalLink"
|
165
|
-
# make_local_link("/Foo/Bar") #=> "%2FFoo%2FBar"
|
166
|
-
#
|
167
|
-
# Must ensure that the result is properly URL-escaped. The caller
|
168
|
-
# will handle HTML escaping as necessary. HTML links will not be
|
169
|
-
# inserted if the function returns nil.
|
170
|
-
#
|
171
|
-
# Example custom behaviour:
|
172
|
-
#
|
173
|
-
# make_local_link("LocalLink") #=> "/LocalLink"
|
174
|
-
# make_local_link("Wikipedia:Bread") #=> "http://en.wikipedia.org/wiki/Bread"
|
175
|
-
def make_local_link(link) #:doc:
|
176
|
-
no_escape? ? link : escape_url(link)
|
14
|
+
Parser.new(text, options).to_html
|
177
15
|
end
|
178
|
-
|
179
|
-
# Sanatize a direct url (e.g. http://wikipedia.org/). The default
|
180
|
-
# behaviour returns the original link as-is.
|
181
|
-
#
|
182
|
-
# Must ensure that the result is properly URL-escaped. The caller
|
183
|
-
# will handle HTML escaping as necessary. Links will not be
|
184
|
-
# converted to HTML links if the function returns link.
|
185
|
-
#
|
186
|
-
# Custom versions of this function in inherited classes can
|
187
|
-
# implement specific link handling behaviour, such as redirection
|
188
|
-
# to intermediate pages (for example, for notifing the user that
|
189
|
-
# he is leaving the site).
|
190
|
-
def make_direct_link(url) #:doc:
|
191
|
-
url
|
192
|
-
end
|
193
|
-
|
194
|
-
# Sanatize and prefix image URLs. When images are encountered in
|
195
|
-
# Creole text, this function is called to obtain the actual URL of
|
196
|
-
# the image. The default behaviour is to return the image link
|
197
|
-
# as-is. No image tags are inserted if the function returns nil.
|
198
|
-
#
|
199
|
-
# Custom version of the method can be used to sanatize URLs
|
200
|
-
# (e.g. remove query-parts), inhibit off-site images, or add a
|
201
|
-
# base URL, for example:
|
202
|
-
#
|
203
|
-
# def make_image_link(url)
|
204
|
-
# URI.join("http://mywiki.org/images/", url)
|
205
|
-
# end
|
206
|
-
def make_image_link(url) #:doc:
|
207
|
-
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
|
-
def make_image(uri, alt)
|
215
|
-
if alt
|
216
|
-
'<img src="' << escape_html(uri) << '" alt="' << escape_html(alt) << '"/>'
|
217
|
-
else
|
218
|
-
'<img src="' << escape_html(uri) << '"/>'
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
def make_explicit_link(link)
|
223
|
-
begin
|
224
|
-
uri = URI.parse(link)
|
225
|
-
return uri.to_s if uri.scheme && @allowed_schemes.include?(uri.scheme)
|
226
|
-
rescue URI::InvalidURIError
|
227
|
-
end
|
228
|
-
make_local_link(link)
|
229
|
-
end
|
230
|
-
|
231
|
-
def parse_inline(str)
|
232
|
-
until str.empty?
|
233
|
-
case str
|
234
|
-
when /\A(\~)?((https?|ftps?):\/\/\S+?)(?=([\,.?!:;"'\)]+)?(\s|$))/
|
235
|
-
if $1
|
236
|
-
@out << escape_html($2)
|
237
|
-
else
|
238
|
-
if uri = make_direct_link($2)
|
239
|
-
@out << make_direct_anchor(uri, $2)
|
240
|
-
else
|
241
|
-
@out << escape_html($&)
|
242
|
-
end
|
243
|
-
end
|
244
|
-
when /\A\[\[\s*([^|]*?)\s*(\|\s*(.*?))?\s*\]\]/m
|
245
|
-
link = $1
|
246
|
-
if uri = make_explicit_link(link)
|
247
|
-
@out << make_explicit_anchor(uri, $3 || link)
|
248
|
-
else
|
249
|
-
@out << escape_html($&)
|
250
|
-
end
|
251
|
-
when /\A\{\{\{(.*?\}*)\}\}\}/
|
252
|
-
@out << '<tt>' << escape_html($1) << '</tt>'
|
253
|
-
when /\A\{\{\s*(.*?)\s*(\|\s*(.*?)\s*)?\}\}/
|
254
|
-
if uri = make_image_link($1)
|
255
|
-
@out << make_image(uri, $3)
|
256
|
-
else
|
257
|
-
@out << escape_html($&)
|
258
|
-
end
|
259
|
-
when /\A([:alpha:]|[:digit:])+/
|
260
|
-
@out << $&
|
261
|
-
when /\A\s+/
|
262
|
-
@out << ' ' if @out[-1,1] != ' '
|
263
|
-
when /\A\*\*/
|
264
|
-
toggle_tag 'strong', $&
|
265
|
-
when /\A\/\//
|
266
|
-
toggle_tag 'em', $&
|
267
|
-
when /\A\\\\/
|
268
|
-
@out << '<br/>'
|
269
|
-
else
|
270
|
-
if @extensions
|
271
|
-
case str
|
272
|
-
when /\A__/
|
273
|
-
toggle_tag 'u', $&
|
274
|
-
when /\A\-\-/
|
275
|
-
toggle_tag 'del', $&
|
276
|
-
when /\A\+\+/
|
277
|
-
toggle_tag 'ins', $&
|
278
|
-
when /\A\^\^/
|
279
|
-
toggle_tag 'sup', $&
|
280
|
-
when /\A\~\~/
|
281
|
-
toggle_tag 'sub', $&
|
282
|
-
when /\A\(R\)/i
|
283
|
-
@out << '®'
|
284
|
-
when /\A\(C\)/i
|
285
|
-
@out << '©'
|
286
|
-
when /\A~([^\s])/
|
287
|
-
@out << escape_html($1)
|
288
|
-
when /./
|
289
|
-
@out << escape_html($&)
|
290
|
-
end
|
291
|
-
else
|
292
|
-
case str
|
293
|
-
when /\A~([^\s])/
|
294
|
-
@out << escape_html($1)
|
295
|
-
when /./
|
296
|
-
@out << escape_html($&)
|
297
|
-
end
|
298
|
-
end
|
299
|
-
end
|
300
|
-
str = $'
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
def parse_table_row(str)
|
305
|
-
@out << '<tr>'
|
306
|
-
str.scan(/\s*\|(=)?\s*((\[\[.*?\]\]|\{\{.*?\}\}|[^|~]|~.)*)(?=\||$)/) do
|
307
|
-
if !$2.empty? || !$'.empty?
|
308
|
-
@out << ($1 ? '<th>' : '<td>')
|
309
|
-
parse_inline($2) if $2
|
310
|
-
end_tag while @stack.last != 'table'
|
311
|
-
@out << ($1 ? '</th>' : '</td>')
|
312
|
-
end
|
313
|
-
end
|
314
|
-
@out << '</tr>'
|
315
|
-
end
|
316
|
-
|
317
|
-
def make_nowikiblock(input)
|
318
|
-
input.gsub(/^ (?=\}\}\})/, '')
|
319
|
-
end
|
320
|
-
|
321
|
-
def ulol?(x); x == 'ul' || x == 'ol'; end
|
322
|
-
|
323
|
-
def parse_block(str)
|
324
|
-
until str.empty?
|
325
|
-
case str
|
326
|
-
when /\A\{\{\{\r?\n(.*?)\r?\n\}\}\}/m
|
327
|
-
end_paragraph
|
328
|
-
nowikiblock = make_nowikiblock($1)
|
329
|
-
@out << '<pre>' << escape_html(nowikiblock) << '</pre>'
|
330
|
-
when /\A\s*-{4,}\s*$/
|
331
|
-
end_paragraph
|
332
|
-
@out << '<hr/>'
|
333
|
-
when /\A\s*(={1,6})\s*(.*?)\s*=*\s*$(\r?\n)?/
|
334
|
-
end_paragraph
|
335
|
-
level = $1.size
|
336
|
-
@out << "<h#{level}>" << escape_html($2) << "</h#{level}>"
|
337
|
-
when /\A[ \t]*\|.*$(\r?\n)?/
|
338
|
-
if !@stack.include?('table')
|
339
|
-
end_paragraph
|
340
|
-
start_tag('table')
|
341
|
-
end
|
342
|
-
parse_table_row($&)
|
343
|
-
when /\A\s*$(\r?\n)?/
|
344
|
-
end_paragraph
|
345
|
-
when /\A(\s*([*#]+)\s*(.*?))$(\r?\n)?/
|
346
|
-
line, bullet, item = $1, $2, $3
|
347
|
-
tag = (bullet[0,1] == '*' ? 'ul' : 'ol')
|
348
|
-
if bullet[0,1] == '#' || bullet.size != 2 || @stack.find {|x| ulol?(x) }
|
349
|
-
count = @stack.select { |x| ulol?(x) }.size
|
350
|
-
|
351
|
-
while !@stack.empty? && count > bullet.size
|
352
|
-
count -= 1 if ulol?(@stack.last)
|
353
|
-
end_tag
|
354
|
-
end
|
355
|
-
|
356
|
-
end_tag while !@stack.empty? && @stack.last != 'li'
|
357
|
-
|
358
|
-
if @stack.last == 'li' && count == bullet.size
|
359
|
-
end_tag
|
360
|
-
if @stack.last != tag
|
361
|
-
end_tag
|
362
|
-
count -= 1
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
while count < bullet.size
|
367
|
-
start_tag tag
|
368
|
-
count += 1
|
369
|
-
start_tag 'li' if count < bullet.size
|
370
|
-
end
|
371
|
-
|
372
|
-
@p = true
|
373
|
-
start_tag('li')
|
374
|
-
parse_inline(item)
|
375
|
-
else
|
376
|
-
start_paragraph
|
377
|
-
parse_inline(line)
|
378
|
-
end
|
379
|
-
when /\A([ \t]*\S+.*?)$(\r?\n)?/
|
380
|
-
start_paragraph
|
381
|
-
parse_inline($1)
|
382
|
-
else
|
383
|
-
raise "Parse error at #{str[0,30].inspect}"
|
384
|
-
end
|
385
|
-
#p [$&, $']
|
386
|
-
str = $'
|
387
|
-
end
|
388
|
-
end_paragraph
|
389
|
-
@out
|
390
|
-
end
|
391
|
-
|
392
16
|
end
|
@@ -0,0 +1,379 @@
|
|
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 lightweight 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
|
+
# Main Creole parser class. Call CreoleParser#parse to parse Creole
|
31
|
+
# formatted text.
|
32
|
+
#
|
33
|
+
# This class is not reentrant. A separate instance is needed for
|
34
|
+
# each thread that needs to convert Creole to HTML.
|
35
|
+
#
|
36
|
+
# Inherit this to provide custom handling of links. The overrideable
|
37
|
+
# methods are: make_local_link
|
38
|
+
module Creole
|
39
|
+
class Parser
|
40
|
+
|
41
|
+
# Allowed url schemes
|
42
|
+
# Examples: http https ftp ftps
|
43
|
+
attr_accessor :allowed_schemes
|
44
|
+
|
45
|
+
# Non-standard wiki text extensions enabled?
|
46
|
+
# E.g. underlined, deleted text etc
|
47
|
+
attr_writer :extensions
|
48
|
+
def extensions?; @extensions; end
|
49
|
+
|
50
|
+
# Disable url escaping for local links
|
51
|
+
# Escaping: [[/Test]] --> %2FTest
|
52
|
+
# No escaping: [[/Test]] --> Test
|
53
|
+
attr_writer :no_escape
|
54
|
+
def no_escape?; @no_escape; end
|
55
|
+
|
56
|
+
# Create a new CreoleParser instance.
|
57
|
+
def initialize(text, options = {})
|
58
|
+
@allowed_schemes = %w(http https ftp ftps)
|
59
|
+
@text = text
|
60
|
+
options.each_pair {|k,v| send("#{k}=", v) }
|
61
|
+
end
|
62
|
+
|
63
|
+
# Convert CCreole text to HTML and return
|
64
|
+
# the result. The resulting HTML does not contain <html> and
|
65
|
+
# <body> tags.
|
66
|
+
#
|
67
|
+
# Example:
|
68
|
+
#
|
69
|
+
# parser = CreoleParser.new("**Hello //World//**", :extensions => true)
|
70
|
+
# parser.to_html
|
71
|
+
# #=> "<p><strong>Hello <em>World</em></strong></p>"
|
72
|
+
def to_html
|
73
|
+
@out = ''
|
74
|
+
@p = false
|
75
|
+
@stack = []
|
76
|
+
parse_block(@text)
|
77
|
+
@out
|
78
|
+
end
|
79
|
+
|
80
|
+
protected
|
81
|
+
|
82
|
+
# Escape any characters with special meaning in HTML using HTML
|
83
|
+
# entities.
|
84
|
+
def escape_html(string)
|
85
|
+
CGI::escapeHTML(string)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Escape any characters with special meaning in URLs using URL
|
89
|
+
# encoding.
|
90
|
+
def escape_url(string)
|
91
|
+
CGI::escape(string)
|
92
|
+
end
|
93
|
+
|
94
|
+
def start_tag(tag)
|
95
|
+
@stack.push(tag)
|
96
|
+
@out << '<' << tag << '>'
|
97
|
+
end
|
98
|
+
|
99
|
+
def end_tag
|
100
|
+
@out << '</' << @stack.pop << '>'
|
101
|
+
end
|
102
|
+
|
103
|
+
def toggle_tag(tag, match)
|
104
|
+
if @stack.include?(tag)
|
105
|
+
if @stack.last == tag
|
106
|
+
end_tag
|
107
|
+
else
|
108
|
+
@out << escape_html(match)
|
109
|
+
end
|
110
|
+
else
|
111
|
+
start_tag(tag)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def end_paragraph
|
116
|
+
end_tag while !@stack.empty?
|
117
|
+
@p = false
|
118
|
+
end
|
119
|
+
|
120
|
+
def start_paragraph
|
121
|
+
if @p
|
122
|
+
@out << ' ' if @out[-1,1] != ' '
|
123
|
+
else
|
124
|
+
end_paragraph
|
125
|
+
start_tag('p')
|
126
|
+
@p = true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Create anchor markup for direct links. This
|
131
|
+
# method can be overridden to generate custom
|
132
|
+
# markup, for example to add html additional attributes.
|
133
|
+
def make_direct_anchor(uri, text)
|
134
|
+
'<a href="' << escape_html(uri) << '">' << escape_html(text) << '</a>'
|
135
|
+
end
|
136
|
+
|
137
|
+
# Create anchor markup for explicit links. This
|
138
|
+
# method can be overridden to generate custom
|
139
|
+
# markup, for example to add html additional attributes.
|
140
|
+
def make_explicit_anchor(uri, text)
|
141
|
+
'<a href="' << escape_html(uri) << '">' << escape_html(text) << '</a>'
|
142
|
+
end
|
143
|
+
|
144
|
+
# Translate an explicit local link to a desired URL that is
|
145
|
+
# properly URL-escaped. The default behaviour is to convert local
|
146
|
+
# links directly, escaping any characters that have special
|
147
|
+
# meaning in URLs. Relative URLs in local links are not handled.
|
148
|
+
#
|
149
|
+
# Examples:
|
150
|
+
#
|
151
|
+
# make_local_link("LocalLink") #=> "LocalLink"
|
152
|
+
# make_local_link("/Foo/Bar") #=> "%2FFoo%2FBar"
|
153
|
+
#
|
154
|
+
# Must ensure that the result is properly URL-escaped. The caller
|
155
|
+
# will handle HTML escaping as necessary. HTML links will not be
|
156
|
+
# inserted if the function returns nil.
|
157
|
+
#
|
158
|
+
# Example custom behaviour:
|
159
|
+
#
|
160
|
+
# make_local_link("LocalLink") #=> "/LocalLink"
|
161
|
+
# make_local_link("Wikipedia:Bread") #=> "http://en.wikipedia.org/wiki/Bread"
|
162
|
+
def make_local_link(link) #:doc:
|
163
|
+
no_escape? ? link : escape_url(link)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Sanatize a direct url (e.g. http://wikipedia.org/). The default
|
167
|
+
# behaviour returns the original link as-is.
|
168
|
+
#
|
169
|
+
# Must ensure that the result is properly URL-escaped. The caller
|
170
|
+
# will handle HTML escaping as necessary. Links will not be
|
171
|
+
# converted to HTML links if the function returns link.
|
172
|
+
#
|
173
|
+
# Custom versions of this function in inherited classes can
|
174
|
+
# implement specific link handling behaviour, such as redirection
|
175
|
+
# to intermediate pages (for example, for notifing the user that
|
176
|
+
# he is leaving the site).
|
177
|
+
def make_direct_link(url) #:doc:
|
178
|
+
url
|
179
|
+
end
|
180
|
+
|
181
|
+
# Sanatize and prefix image URLs. When images are encountered in
|
182
|
+
# Creole text, this function is called to obtain the actual URL of
|
183
|
+
# the image. The default behaviour is to return the image link
|
184
|
+
# as-is. No image tags are inserted if the function returns nil.
|
185
|
+
#
|
186
|
+
# Custom version of the method can be used to sanatize URLs
|
187
|
+
# (e.g. remove query-parts), inhibit off-site images, or add a
|
188
|
+
# base URL, for example:
|
189
|
+
#
|
190
|
+
# def make_image_link(url)
|
191
|
+
# URI.join("http://mywiki.org/images/", url)
|
192
|
+
# end
|
193
|
+
def make_image_link(url) #:doc:
|
194
|
+
url
|
195
|
+
end
|
196
|
+
|
197
|
+
# Create image markup. This
|
198
|
+
# method can be overridden to generate custom
|
199
|
+
# markup, for example to add html additional attributes or
|
200
|
+
# to put divs around the imgs.
|
201
|
+
def make_image(uri, alt)
|
202
|
+
if alt
|
203
|
+
'<img src="' << escape_html(uri) << '" alt="' << escape_html(alt) << '"/>'
|
204
|
+
else
|
205
|
+
'<img src="' << escape_html(uri) << '"/>'
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def make_explicit_link(link)
|
210
|
+
begin
|
211
|
+
uri = URI.parse(link)
|
212
|
+
return uri.to_s if uri.scheme && @allowed_schemes.include?(uri.scheme)
|
213
|
+
rescue URI::InvalidURIError
|
214
|
+
end
|
215
|
+
make_local_link(link)
|
216
|
+
end
|
217
|
+
|
218
|
+
def parse_inline(str)
|
219
|
+
until str.empty?
|
220
|
+
case str
|
221
|
+
when /\A(\~)?((https?|ftps?):\/\/\S+?)(?=([\,.?!:;"'\)]+)?(\s|$))/
|
222
|
+
if $1
|
223
|
+
@out << escape_html($2)
|
224
|
+
else
|
225
|
+
if uri = make_direct_link($2)
|
226
|
+
@out << make_direct_anchor(uri, $2)
|
227
|
+
else
|
228
|
+
@out << escape_html($&)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
when /\A\[\[\s*([^|]*?)\s*(\|\s*(.*?))?\s*\]\]/m
|
232
|
+
link = $1
|
233
|
+
if uri = make_explicit_link(link)
|
234
|
+
@out << make_explicit_anchor(uri, $3 || link)
|
235
|
+
else
|
236
|
+
@out << escape_html($&)
|
237
|
+
end
|
238
|
+
when /\A\{\{\{(.*?\}*)\}\}\}/
|
239
|
+
@out << '<tt>' << escape_html($1) << '</tt>'
|
240
|
+
when /\A\{\{\s*(.*?)\s*(\|\s*(.*?)\s*)?\}\}/
|
241
|
+
if uri = make_image_link($1)
|
242
|
+
@out << make_image(uri, $3)
|
243
|
+
else
|
244
|
+
@out << escape_html($&)
|
245
|
+
end
|
246
|
+
when /\A([:alpha:]|[:digit:])+/
|
247
|
+
@out << $&
|
248
|
+
when /\A\s+/
|
249
|
+
@out << ' ' if @out[-1,1] != ' '
|
250
|
+
when /\A\*\*/
|
251
|
+
toggle_tag 'strong', $&
|
252
|
+
when /\A\/\//
|
253
|
+
toggle_tag 'em', $&
|
254
|
+
when /\A\\\\/
|
255
|
+
@out << '<br/>'
|
256
|
+
else
|
257
|
+
if @extensions
|
258
|
+
case str
|
259
|
+
when /\A__/
|
260
|
+
toggle_tag 'u', $&
|
261
|
+
when /\A\-\-/
|
262
|
+
toggle_tag 'del', $&
|
263
|
+
when /\A\+\+/
|
264
|
+
toggle_tag 'ins', $&
|
265
|
+
when /\A\^\^/
|
266
|
+
toggle_tag 'sup', $&
|
267
|
+
when /\A\~\~/
|
268
|
+
toggle_tag 'sub', $&
|
269
|
+
when /\A\(R\)/i
|
270
|
+
@out << '®'
|
271
|
+
when /\A\(C\)/i
|
272
|
+
@out << '©'
|
273
|
+
when /\A~([^\s])/
|
274
|
+
@out << escape_html($1)
|
275
|
+
when /./
|
276
|
+
@out << escape_html($&)
|
277
|
+
end
|
278
|
+
else
|
279
|
+
case str
|
280
|
+
when /\A~([^\s])/
|
281
|
+
@out << escape_html($1)
|
282
|
+
when /./
|
283
|
+
@out << escape_html($&)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
str = $'
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def parse_table_row(str)
|
292
|
+
@out << '<tr>'
|
293
|
+
str.scan(/\s*\|(=)?\s*((\[\[.*?\]\]|\{\{.*?\}\}|[^|~]|~.)*)(?=\||$)/) do
|
294
|
+
if !$2.empty? || !$'.empty?
|
295
|
+
@out << ($1 ? '<th>' : '<td>')
|
296
|
+
parse_inline($2) if $2
|
297
|
+
end_tag while @stack.last != 'table'
|
298
|
+
@out << ($1 ? '</th>' : '</td>')
|
299
|
+
end
|
300
|
+
end
|
301
|
+
@out << '</tr>'
|
302
|
+
end
|
303
|
+
|
304
|
+
def make_nowikiblock(input)
|
305
|
+
input.gsub(/^ (?=\}\}\})/, '')
|
306
|
+
end
|
307
|
+
|
308
|
+
def ulol?(x); x == 'ul' || x == 'ol'; end
|
309
|
+
|
310
|
+
def parse_block(str)
|
311
|
+
until str.empty?
|
312
|
+
case str
|
313
|
+
when /\A\{\{\{\r?\n(.*?)\r?\n\}\}\}/m
|
314
|
+
end_paragraph
|
315
|
+
nowikiblock = make_nowikiblock($1)
|
316
|
+
@out << '<pre>' << escape_html(nowikiblock) << '</pre>'
|
317
|
+
when /\A\s*-{4,}\s*$/
|
318
|
+
end_paragraph
|
319
|
+
@out << '<hr/>'
|
320
|
+
when /\A\s*(={1,6})\s*(.*?)\s*=*\s*$(\r?\n)?/
|
321
|
+
end_paragraph
|
322
|
+
level = $1.size
|
323
|
+
@out << "<h#{level}>" << escape_html($2) << "</h#{level}>"
|
324
|
+
when /\A[ \t]*\|.*$(\r?\n)?/
|
325
|
+
if !@stack.include?('table')
|
326
|
+
end_paragraph
|
327
|
+
start_tag('table')
|
328
|
+
end
|
329
|
+
parse_table_row($&)
|
330
|
+
when /\A\s*$(\r?\n)?/
|
331
|
+
end_paragraph
|
332
|
+
when /\A(\s*([*#]+)\s*(.*?))$(\r?\n)?/
|
333
|
+
line, bullet, item = $1, $2, $3
|
334
|
+
tag = (bullet[0,1] == '*' ? 'ul' : 'ol')
|
335
|
+
if bullet[0,1] == '#' || bullet.size != 2 || @stack.find {|x| ulol?(x) }
|
336
|
+
count = @stack.select { |x| ulol?(x) }.size
|
337
|
+
|
338
|
+
while !@stack.empty? && count > bullet.size
|
339
|
+
count -= 1 if ulol?(@stack.last)
|
340
|
+
end_tag
|
341
|
+
end
|
342
|
+
|
343
|
+
end_tag while !@stack.empty? && @stack.last != 'li'
|
344
|
+
|
345
|
+
if @stack.last == 'li' && count == bullet.size
|
346
|
+
end_tag
|
347
|
+
if @stack.last != tag
|
348
|
+
end_tag
|
349
|
+
count -= 1
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
while count < bullet.size
|
354
|
+
start_tag tag
|
355
|
+
count += 1
|
356
|
+
start_tag 'li' if count < bullet.size
|
357
|
+
end
|
358
|
+
|
359
|
+
@p = true
|
360
|
+
start_tag('li')
|
361
|
+
parse_inline(item)
|
362
|
+
else
|
363
|
+
start_paragraph
|
364
|
+
parse_inline(line)
|
365
|
+
end
|
366
|
+
when /\A([ \t]*\S+.*?)$(\r?\n)?/
|
367
|
+
start_paragraph
|
368
|
+
parse_inline($1)
|
369
|
+
else
|
370
|
+
raise "Parse error at #{str[0,30].inspect}"
|
371
|
+
end
|
372
|
+
#p [$&, $']
|
373
|
+
str = $'
|
374
|
+
end
|
375
|
+
end_paragraph
|
376
|
+
@out
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
require 'creole'
|
3
|
+
|
4
|
+
module Creole
|
5
|
+
class Template < Tilt::Template
|
6
|
+
def prepare
|
7
|
+
@creole = Creole::Parser.new(data,
|
8
|
+
:allowed_schemes => options[:allowed_schemes],
|
9
|
+
:extensions => options[:extensions],
|
10
|
+
:no_escape => options[:no_escape])
|
11
|
+
@output = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def evaluate(scope, locals, &block)
|
15
|
+
@output ||= @creole.to_html
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Tilt.register 'creole', Creole::Template
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'creole/template'
|
2
|
+
|
3
|
+
describe Creole::Template do
|
4
|
+
it 'should be registered for .creole files' do
|
5
|
+
Tilt.mappings['creole'].should.equal Creole::Template
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should prepare and evaluate templates on #render' do
|
9
|
+
template = Creole::Template.new { |t| '= Hello World!' }
|
10
|
+
3.times { template.render.should.equal '<h1>Hello World!</h1>' }
|
11
|
+
end
|
12
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 4
|
8
|
+
- 0
|
9
|
+
version: 0.4.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Lars Christensen
|
@@ -15,13 +15,14 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-03-23 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: bacon
|
23
23
|
prerelease: false
|
24
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
25
26
|
requirements:
|
26
27
|
- - ">="
|
27
28
|
- !ruby/object:Gem::Version
|
@@ -30,7 +31,7 @@ dependencies:
|
|
30
31
|
version: "0"
|
31
32
|
type: :development
|
32
33
|
version_requirements: *id001
|
33
|
-
description: Creole is a
|
34
|
+
description: Creole is a lightweight markup language (http://wikicreole.org/).
|
34
35
|
email:
|
35
36
|
- larsch@belunktum.dk
|
36
37
|
- mail@daniel-mendler.de
|
@@ -39,14 +40,16 @@ executables: []
|
|
39
40
|
extensions: []
|
40
41
|
|
41
42
|
extra_rdoc_files:
|
42
|
-
- Manifest.txt
|
43
43
|
- README.creole
|
44
44
|
files:
|
45
|
-
- Manifest.txt
|
46
45
|
- README.creole
|
47
46
|
- Rakefile
|
48
47
|
- lib/creole.rb
|
49
|
-
-
|
48
|
+
- lib/creole/parser.rb
|
49
|
+
- lib/creole/template.rb
|
50
|
+
- lib/creole/version.rb
|
51
|
+
- test/parser_test.rb
|
52
|
+
- test/template_test.rb
|
50
53
|
has_rdoc: true
|
51
54
|
homepage: http://github.com/minad/creole
|
52
55
|
licenses: []
|
@@ -58,6 +61,7 @@ rdoc_options:
|
|
58
61
|
require_paths:
|
59
62
|
- lib
|
60
63
|
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
61
65
|
requirements:
|
62
66
|
- - ">="
|
63
67
|
- !ruby/object:Gem::Version
|
@@ -65,6 +69,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
69
|
- 0
|
66
70
|
version: "0"
|
67
71
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
68
73
|
requirements:
|
69
74
|
- - ">="
|
70
75
|
- !ruby/object:Gem::Version
|
@@ -74,9 +79,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
79
|
requirements: []
|
75
80
|
|
76
81
|
rubyforge_project: creole
|
77
|
-
rubygems_version: 1.3.
|
82
|
+
rubygems_version: 1.3.7
|
78
83
|
signing_key:
|
79
84
|
specification_version: 3
|
80
|
-
summary:
|
81
|
-
test_files:
|
82
|
-
|
85
|
+
summary: Lightweight markup language
|
86
|
+
test_files: []
|
87
|
+
|