junebug 0.0.14 → 0.0.15

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.
@@ -0,0 +1,138 @@
1
+ unless defined? RedCloth
2
+ $:.unshift(File.dirname(__FILE__))
3
+ require 'base'
4
+ end
5
+
6
+ class RedCloth < String
7
+
8
+ DEFAULT_RULES << :markdown
9
+
10
+ # == Markdown
11
+ #
12
+ # refs_markdown:: Markdown references (for example: [hobix]: http://hobix.com/)
13
+ # block_markdown_setext:: Markdown setext headers
14
+ # block_markdown_atx:: Markdown atx headers
15
+ # block_markdown_rule:: Markdown horizontal rules
16
+ # block_markdown_bq:: Markdown blockquotes
17
+ # block_markdown_lists:: Markdown lists
18
+ # inline_markdown_link:: Markdown links
19
+ #
20
+
21
+ #######
22
+ private
23
+ #######
24
+
25
+ def block_markdown_setext( text )
26
+ if text =~ SETEXT_RE
27
+ tag = if $2 == "="; "h1"; else; "h2"; end
28
+ blk, cont = "<#{ tag }>#{ $1 }</#{ tag }>", $'
29
+ blocks cont
30
+ text.replace( blk + cont )
31
+ end
32
+ end
33
+
34
+ def block_markdown_atx( text )
35
+ if text =~ ATX_RE
36
+ tag = "h#{ $1.length }"
37
+ blk, cont = "<#{ tag }>#{ $2 }</#{ tag }>\n\n", $'
38
+ blocks cont
39
+ text.replace( blk + cont )
40
+ end
41
+ end
42
+
43
+ MARKDOWN_BQ_RE = /\A(^ *> ?.+$(.+\n)*\n*)+/m
44
+
45
+ def block_markdown_bq( text )
46
+ text.gsub!( MARKDOWN_BQ_RE ) do |blk|
47
+ blk.gsub!( /^ *> ?/, '' )
48
+ flush_left blk
49
+ blocks blk
50
+ blk.gsub!( /^(\S)/, "\t\\1" )
51
+ "<blockquote>\n#{ blk }\n</blockquote>\n\n"
52
+ end
53
+ end
54
+
55
+ MARKDOWN_RULE_RE = /^(.*)( ?[#{
56
+ ['*', '-', '_'].collect { |ch| Regexp::quote( ch ) }.join
57
+ }] ?){3,}(.*)$/
58
+
59
+ def block_markdown_rule( text )
60
+ text.gsub!( MARKDOWN_RULE_RE ) do |blk|
61
+ if $3.empty? && $1 =~ /[#{['*', '-', '_'].collect { |ch| Regexp::quote( ch ) }.join}]*/
62
+ "<hr />"
63
+ else
64
+ blk
65
+ end
66
+ end
67
+ end
68
+
69
+ # XXX TODO XXX
70
+ def block_markdown_lists( text )
71
+ end
72
+
73
+ def inline_markdown_link( text )
74
+ end
75
+
76
+ MARKDOWN_REFLINK_RE = /
77
+ \[([^\[\]]+)\] # $text
78
+ [ ]? # opt. space
79
+ (?:\n[ ]*)? # one optional newline followed by spaces
80
+ \[(.*?)\] # $id
81
+ /x
82
+
83
+ def inline_markdown_reflink( text )
84
+ text.gsub!( MARKDOWN_REFLINK_RE ) do |m|
85
+ text, id = $~[1..2]
86
+
87
+ if id.empty?
88
+ url, title = check_refs( text )
89
+ else
90
+ url, title = check_refs( id )
91
+ end
92
+
93
+ atts = " href=\"#{ url }\""
94
+ atts << " title=\"#{ title }\"" if title
95
+ atts = shelve( atts )
96
+
97
+ "<a#{ atts }>#{ text }</a>"
98
+ end
99
+ end
100
+
101
+ MARKDOWN_LINK_RE = /
102
+ \[([^\[\]]+)\] # $text
103
+ \( # open paren
104
+ [ \t]* # opt space
105
+ <?(.+?)>? # $href
106
+ [ \t]* # opt space
107
+ (?: # whole title
108
+ (['"]) # $quote
109
+ (.*?) # $title
110
+ \3 # matching quote
111
+ )? # title is optional
112
+ \)
113
+ /x
114
+
115
+ def inline_markdown_link( text )
116
+ text.gsub!( MARKDOWN_LINK_RE ) do |m|
117
+ text, url, quote, title = $~[1..4]
118
+
119
+ atts = " href=\"#{ url }\""
120
+ atts << " title=\"#{ title }\"" if title
121
+ atts = shelve( atts )
122
+
123
+ "<a#{ atts }>#{ text }</a>"
124
+ end
125
+ end
126
+
127
+ MARKDOWN_REFS_RE = /(^ *)\[([^\n]+?)\]:\s+<?(#{HYPERLINK})>?(?:\s+"((?:[^"]|\\")+)")?(?=\s|$)/m
128
+
129
+ def refs_markdown( text )
130
+ text.gsub!( MARKDOWN_REFS_RE ) do |m|
131
+ flag, url = $~[2..3]
132
+ title = $~[6]
133
+ @urlrefs[flag.downcase] = [url, title]
134
+ nil
135
+ end
136
+ end
137
+ end
138
+
@@ -0,0 +1,449 @@
1
+ unless defined? RedCloth
2
+ $:.unshift(File.dirname(__FILE__))
3
+ require 'base'
4
+ end
5
+
6
+ class RedCloth < String
7
+
8
+ DEFAULT_RULES << :textile
9
+
10
+ #
11
+ # == Textile Rules
12
+ #
13
+ # The following textile rules can be set individually. Or add the complete
14
+ # set of rules with the single :textile rule, which supplies the rule set in
15
+ # the following precedence:
16
+ #
17
+ # refs_textile:: Textile references (i.e. [hobix]http://hobix.com/)
18
+ # block_textile_table:: Textile table block structures
19
+ # block_textile_lists:: Textile list structures
20
+ # block_textile_prefix:: Textile blocks with prefixes (i.e. bq., h2., etc.)
21
+ # block_textile_defs:: Textile definition lists
22
+ # inline_textile_image:: Textile inline images
23
+ # inline_textile_link:: Textile inline links
24
+ # inline_textile_span:: Textile inline spans
25
+ # glyphs_textile:: Textile entities (such as em-dashes and smart quotes)
26
+ #
27
+
28
+ #######
29
+ private
30
+ #######
31
+ #
32
+ # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents.
33
+ # (from PyTextile)
34
+ #
35
+ TEXTILE_TAGS =
36
+
37
+ [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230],
38
+ [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249],
39
+ [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217],
40
+ [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732],
41
+ [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]].
42
+
43
+ collect! do |a, b|
44
+ [a.chr, ( b.zero? and "" or "&##{ b };" )]
45
+ end
46
+
47
+ def textile_pre_process(text)
48
+ {'w' => 'warning', 'n' => 'note', 'c' => 'comment', 'pro' => 'production', 'dt' => 'dt', 'dd' => 'dd'}.each do |char, word|
49
+ parts = text.split(/^\s*#{char}\./)
50
+ text.replace(parts.first + "\n" + parts[1..-1].map do |part|
51
+ if part =~ /\.#{char}\s*$/
52
+ "div(#{word})." + part.sub(/\.#{char}\s*$/, "div(#{word}). \n")
53
+ else
54
+ "#{char}.#{part}"
55
+ end
56
+ end.join("\n"))
57
+
58
+ self.class.class_eval %!
59
+ def textile_#{char}(tag, atts, cite, content)
60
+ textile_p('p', %{ class=#{word.inspect}}, cite, content)
61
+ end
62
+ !
63
+ end
64
+ {'bq' => 'blockquote'}.each do |char, word|
65
+ parts = text.split(/^\s*#{char}\./)
66
+ text.replace(parts.first + "\n" + parts[1..-1].map do |part|
67
+ if part =~ /\.#{char}\s*$/
68
+ "div(#{word})." + part.sub(/\.#{char}\s*$/, "div(#{word}). ")
69
+ else
70
+ "#{char}.#{part}"
71
+ end
72
+ end.join("\n"))
73
+ end
74
+
75
+ text.gsub!( BACKTICK_CODE_RE ) do |m|
76
+ before,lang,code,after = $~[1..4]
77
+ lang = " lang=\"#{ lang }\"" if lang
78
+ rip_offtags( "#{ before }<pre><code#{ lang }>#{ code.gsub(/\\\`\`\`/,'```') }</code></pre>#{ after }" )
79
+ end
80
+ end
81
+
82
+ def textile_post_process(text)
83
+ post_inline_textile_span(text)
84
+ end
85
+
86
+ # Parses a Textile table block, building HTML from the result.
87
+ def block_textile_table( text )
88
+ text.gsub!( TABLE_RE ) do |matches|
89
+
90
+ caption, id, tatts, fullrow = $~[1..4]
91
+ tatts = pba( tatts, 'table' )
92
+ tatts = shelve( tatts ) if tatts
93
+ rows = []
94
+
95
+ fullrow.
96
+ split( /\|$/m ).
97
+ delete_if {|row|row.empty?}.
98
+ each do |row|
99
+
100
+ ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m
101
+ row << " "
102
+
103
+ cells = []
104
+ row.split( '|' ).each_with_index do |cell, i|
105
+ next if i == 0
106
+
107
+ ctyp = 'd'
108
+ ctyp = 'h' if cell =~ /^_/
109
+
110
+ catts = ''
111
+ catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. ?)(.*)/
112
+
113
+ catts = shelve( catts ) if catts
114
+ cells << "\t\t\t<t#{ ctyp }#{ catts }>#{ cell.strip.empty? ? "&nbsp;" : row.split( '|' ).size-1 != i ? cell : cell[0...cell.length-1] }</t#{ ctyp }>"
115
+ end
116
+ ratts = shelve( ratts ) if ratts
117
+ rows << "\t\t<tr#{ ratts }>\n#{ cells.join( "\n" ) }\n\t\t</tr>"
118
+ end
119
+ caption = "\t<p class=\"caption\">#{caption}</p>\n" if caption
120
+ "#{caption}\t<table#{ tatts }>\n#{ rows.join( "\n" ) }\n\t</table>\n\n"
121
+ end
122
+ end
123
+
124
+ # Parses Textile lists and generates HTML
125
+ def block_textile_lists( text )
126
+ orig_text = text.dup
127
+
128
+ # Take care of _*'s and _#'s to turn them into paragraphs
129
+ text.gsub!(/([\*#] )((.*?\n\s*_[\*#].*?)+)/) do |m|
130
+ "#{$1}<p>"+$2.split(/_[\*#]/).map{|w|w.strip}.delete_if{|w|w.empty?}.join("</p><p>")+"</p>"
131
+ end
132
+
133
+ @last_line ||= -1
134
+
135
+ text.gsub!( LISTS_RE ) do |match|
136
+ if text =~ /^#([_0-9]+).*/m
137
+ if $1 == $1.to_i.to_s # then it is a number, so use it
138
+ @last_line = $1.to_i - 2
139
+ end
140
+ else
141
+ @last_line = -1
142
+ end
143
+ lines = match.split( /\n/ )
144
+ depth = []
145
+ lines.each_with_index do |line, line_id|
146
+ if line =~ LISTS_CONTENT_RE
147
+
148
+ tl,continuation,atts,content = $~[1..4]
149
+ @last_line += 1 if tl.length == 1
150
+
151
+ unless depth.last.nil?
152
+ if depth.last.length > tl.length
153
+ (depth.length - 1).downto(0) do |i|
154
+ break if depth[i].length == tl.length
155
+ lines[line_id - 1] << "</li>\n#{"\t"*(depth.size-1)}</#{ lT( depth[i] ) }l>"
156
+ depth.pop
157
+ tab_in = true
158
+ end
159
+ end
160
+ if depth.last && depth.last.length == tl.length
161
+ lines[line_id - 1] << "</li>"
162
+ end
163
+ end
164
+ unless depth.last == tl
165
+ depth << tl
166
+ atts = pba( atts )
167
+ atts << " start=\"#{@last_line + 1}\"" if lT(tl) == "o" && !continuation.empty? && @last_line > 0
168
+ atts = shelve( atts ) if atts
169
+ lines[line_id] = "#{"\t"*(depth.size-1)}<#{ lT(tl) }l#{ atts }>\n#{"\t"*depth.size}<li>#{ content }"
170
+ else
171
+ lines[line_id] = "#{"\t"*depth.size}<li>#{ content }"
172
+ end
173
+ elsif line =~ /^([_]+)(#{A}#{C}) (.*)$/m
174
+ @last_line += 1
175
+ tl = "u"
176
+ atts,content = $~[2..3]
177
+
178
+ unless depth.last.nil?
179
+ if depth.last.length > tl.length
180
+ (depth.length - 1).downto(0) do |i|
181
+ break if depth[i].length == tl.length
182
+ lines[line_id - 1] << "</li>\n#{"\t"*(depth.size-1)}</#{ lT( depth[i] ) }l>"
183
+ depth.pop
184
+ tab_in = true
185
+ end
186
+ end
187
+ if depth.last and depth.last.length == tl.length
188
+ lines[line_id - 1] << "</li>"
189
+ end
190
+ end
191
+ unless depth.last == tl
192
+ depth << tl
193
+ atts = pba( atts )
194
+ atts = shelve( "#{atts} style=\"list-style-type:none;\"" )
195
+ lines[line_id] = "#{"\t"*(depth.size-1)}<#{ lT(tl) }l#{ atts }>\n#{"\t"*depth.size}<li>#{ content }"
196
+ else
197
+ lines[line_id] = "#{"\t"*depth.size}<li>#{ content }"
198
+ end
199
+ end
200
+
201
+ if line_id == lines.length - 1
202
+ tabs = depth.size-1
203
+ depth.reverse.delete_if do |v|
204
+ lines[-1] << "</li>\n#{"\t"*tabs}</#{ lT( v ) }l>"
205
+ tabs -= 1
206
+ end
207
+ end
208
+ end
209
+ lines.join( "\n" )
210
+ end
211
+
212
+ text != orig_text
213
+ end
214
+
215
+ # Parses Textile definition lists and generates HTML
216
+ def block_textile_defs( text )
217
+ text.gsub!(/^-\s+(.*?):=(.*?)=:\s*$/m) do |m|
218
+ "- #{$1.strip} := <p>"+$2.split(/\n/).map{|w|w.strip}.delete_if{|w|w.empty?}.join("</p><p>")+"</p>"
219
+ end
220
+
221
+ text.gsub!( DEFS_RE ) do |match|
222
+ lines = match.split( /\n/ )
223
+ lines.each_with_index do |line, line_id|
224
+ if line =~ DEFS_CONTENT_RE
225
+ dl,continuation,dt,dd = $~[1..4]
226
+
227
+ atts = pba( atts )
228
+ atts = shelve( atts ) if atts
229
+ lines[line_id] = line_id == 0 ? "<dl#{ atts }>" : ""
230
+ lines[line_id] << "\n\t<dt>#{ dt.strip }</dt>\n\t<dd>#{ dd.strip }</dd>"
231
+ end
232
+
233
+ if line_id == lines.length - 1
234
+ lines[-1] << "\n</dl>"
235
+ end
236
+ end
237
+ lines.join( "\n" )
238
+ end
239
+ end
240
+
241
+ def inline_textile_code( text )
242
+ text.gsub!( CODE_RE ) do |m|
243
+ before,lang,code,after = $~[1..4]
244
+ lang = " lang=\"#{ lang }\"" if lang
245
+ rip_offtags( "#{ before }<code#{ lang }>#{ code.gsub(/\\@(@?)/,'@\1') }</code>#{ after }" )
246
+ end
247
+ end
248
+
249
+ def textile_bq( tag, atts, cite, content )
250
+ cite, cite_title = check_refs( cite )
251
+ cite = " cite=\"#{ cite }\"" if cite
252
+ atts = shelve( atts ) if atts
253
+ "\t<blockquote#{ cite }>\n\t\t<p#{ atts }>#{ content }</p>\n\t</blockquote>"
254
+ end
255
+
256
+ def textile_p( tag, atts, cite, content )
257
+ atts = shelve( atts ) if atts
258
+ "\t<#{ tag }#{ atts }>#{ content }</#{ tag }>"
259
+ end
260
+
261
+ alias textile_h1 textile_p
262
+ alias textile_h2 textile_p
263
+ alias textile_h3 textile_p
264
+ alias textile_h4 textile_p
265
+ alias textile_h5 textile_p
266
+ alias textile_h6 textile_p
267
+
268
+ def textile_fn_( tag, num, atts, cite, content )
269
+ atts << " id=\"fn#{ num }\""
270
+ content = "<sup>#{ num }</sup> #{ content }"
271
+ atts = shelve( atts ) if atts
272
+ "\t<p#{ atts }>#{ content }</p>"
273
+ end
274
+
275
+ def textile_ch( tag, atts, cite, content )
276
+ textile_p("h1", atts, cite, content)
277
+ end
278
+
279
+ def block_textile_prefix( text )
280
+ if text =~ BLOCK_RE
281
+ tag,tagpre,num,atts,cite,content = $~[1..6]
282
+ atts = pba( atts )
283
+
284
+ # pass to prefix handler
285
+ if respond_to? "textile_#{ tag }", true
286
+ text.gsub!( $&, method( "textile_#{ tag }" ).call( tag, atts, cite, content ) )
287
+ elsif respond_to? "textile_#{ tagpre }_", true
288
+ text.gsub!( $&, method( "textile_#{ tagpre }_" ).call( tagpre, num, atts, cite, content ) )
289
+ end
290
+ end
291
+ end
292
+
293
+ def inline_textile_span( text )
294
+ QTAGS.each do |qtag_rc, ht, qtag_re, rtype, escaped_re|
295
+ text.gsub!( qtag_re ) do |m|
296
+
297
+ case rtype
298
+ when :limit
299
+ sta,qtag,atts,cite,content = $~[1..5]
300
+ else
301
+ qtag,atts,cite,content = $~[1..4]
302
+ sta = ''
303
+ end
304
+ atts = pba( atts )
305
+ atts << " cite=\"#{ cite }\"" if cite
306
+ atts = shelve( atts ) if atts
307
+
308
+ "#{ sta }<#{ ht }#{ atts }>#{ content }</#{ ht }>"
309
+ end
310
+ end
311
+ end
312
+
313
+ def post_inline_textile_span( text )
314
+ QTAGS.each do |qtag_rc, ht, qtag_re, rtype, escaped_re|
315
+ text.gsub!( escaped_re ) do |m|
316
+
317
+ case rtype
318
+ when :limit
319
+ sta,qtag,atts,cite,content = $~[1..5]
320
+ else
321
+ qtag,atts,cite,content = $~[1..4]
322
+ sta = ''
323
+ end
324
+ atts = pba( atts )
325
+ atts << " cite=\"#{ cite }\"" if cite
326
+
327
+ "#{ sta }<#{ ht }#{ atts }>#{ content }</#{ ht }>"
328
+ end
329
+ end
330
+ end
331
+
332
+ def inline_textile_link( text )
333
+ text.gsub!( LINK_RE ) do |m|
334
+ pre,atts,text,title,url,slash,post = $~[1..7]
335
+
336
+ url, url_title = check_refs( url )
337
+ title ||= url_title
338
+
339
+ atts = pba( atts )
340
+ atts = " href=\"#{ url }#{ slash }\"#{ atts }"
341
+ atts << " title=\"#{ title }\"" if title
342
+ atts = shelve( atts ) if atts
343
+
344
+ "#{ pre }<a#{ atts }>#{ text }</a>#{ post }"
345
+ end
346
+ end
347
+
348
+ TEXTILE_REFS_RE = /(^ *)\[([^\n\[]+?)\](#{HYPERLINK})(?=\s|$)/
349
+
350
+ def refs_textile( text )
351
+ text.gsub!( TEXTILE_REFS_RE ) do |m|
352
+ flag, url = $~[2..3]
353
+ @urlrefs[flag.downcase] = [url, nil]
354
+ nil
355
+ end
356
+ end
357
+
358
+ def inline_textile_image( text )
359
+ text.gsub!( IMAGE_RE ) do |m|
360
+ stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8]
361
+ atts = pba( atts )
362
+ atts = " src=\"#{ url }\"#{ atts }"
363
+ atts << " title=\"#{ title }\"" if title
364
+ atts << " alt=\"#{ title }\""
365
+ # size = @getimagesize($url);
366
+ # if($size) $atts.= " $size[3]";
367
+
368
+ href, alt_title = check_refs( href ) if href
369
+ url, url_title = check_refs( url )
370
+
371
+ out = ''
372
+ out << "<a#{ shelve( " href=\"#{ href }\"" ) }>" if href
373
+ out << "<img#{ shelve( atts ) } />"
374
+ out << "</a>#{ href_a1 }#{ href_a2 }" if href
375
+
376
+ if algn
377
+ algn = h_align( algn )
378
+ if stln == "<p>"
379
+ out = "<p style=\"float:#{ algn }\">#{ out }"
380
+ else
381
+ out = "#{ stln }<div style=\"float:#{ algn }\">#{ out }</div>"
382
+ end
383
+ else
384
+ out = stln + out
385
+ end
386
+
387
+ out
388
+ end
389
+ end
390
+
391
+ def no_textile( text )
392
+ text.gsub!( /(^|\s)(\\?)==([^=]+.*?)\2==(\s|$)?/ ) do |m|
393
+ $2.empty? ? "#{$1}<notextile>#{$3}</notextile>#{$4}" : "#{$1}==#{$3}==#{$4}"
394
+ end
395
+ text.gsub!( /^ *(\\?)==([^=]+.*?)\1==/m ) do |m|
396
+ $1.empty? ? "<notextile>#{$2}</notextile>" : "==#{$2}=="
397
+ end
398
+ end
399
+
400
+ def glyphs_textile( text, level = 0 )
401
+ if text !~ HASTAG_MATCH
402
+ pgl text
403
+ footnote_ref text
404
+ else
405
+ codepre = 0
406
+ text.gsub!( ALLTAG_MATCH ) do |line|
407
+ ## matches are off if we're between <code>, <pre> etc.
408
+ if $1
409
+ if line =~ OFFTAG_OPEN
410
+ codepre += 1
411
+ elsif line =~ OFFTAG_CLOSE
412
+ codepre -= 1
413
+ codepre = 0 if codepre < 0
414
+ end
415
+ elsif codepre.zero?
416
+ glyphs_textile( line, level + 1 )
417
+ else
418
+ htmlesc( line, :NoQuotes )
419
+ end
420
+ ## p [level, codepre, orig_line, line]
421
+
422
+ line
423
+ end
424
+ end
425
+ end
426
+
427
+ def textile_popup_help( name, windowW, windowH )
428
+ ' <a target="_blank" href="http://hobix.com/textile/#' + helpvar + '" onclick="window.open(this.href, \'popupwindow\', \'width=' + windowW + ',height=' + windowH + ',scrollbars,resizable\'); return false;">' + name + '</a><br />'
429
+ end
430
+
431
+ # Turns all urls into clickable links.
432
+ # Taken from ActionPack's ActionView
433
+ def inline_textile_autolink_urls(text)
434
+ text.gsub!(AUTO_LINK_RE) do
435
+ all, a, b, c, d = $&, $1, $2, $3, $5
436
+ if a =~ /<a\s/i # don't replace URL's that are already linked
437
+ all
438
+ else
439
+ %(#{a}<a href="#{b=="www."?"http://www.":b}#{c}">#{b}#{c}</a>#{d})
440
+ end
441
+ end
442
+ end
443
+
444
+ # Turns all email addresses into clickable links.
445
+ def inline_textile_autolink_emails(text)
446
+ text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/, '<a href="mailto:\1">\1</a>')
447
+ end
448
+ end
449
+