maruku 0.2.13 → 0.3.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.
Files changed (86) hide show
  1. data/bin/maruku +23 -15
  2. data/bin/maruku0.3 +37 -0
  3. data/bin/marutest +277 -0
  4. data/docs/changelog-0.3.html +99 -0
  5. data/docs/changelog-0.3.md +84 -0
  6. data/docs/faq.html +46 -0
  7. data/docs/faq.md +32 -0
  8. data/docs/index.html +629 -64
  9. data/docs/markdown_extra2.html +67 -14
  10. data/docs/markdown_syntax.html +631 -94
  11. data/docs/markdown_syntax_2.html +152 -0
  12. data/docs/maruku.html +629 -64
  13. data/docs/maruku.md +108 -105
  14. data/docs/proposal.html +362 -55
  15. data/docs/proposal.md +133 -169
  16. data/docs/todo.html +30 -0
  17. data/lib/maruku.rb +13 -3
  18. data/lib/maruku/errors_management.rb +75 -0
  19. data/lib/maruku/helpers.rb +164 -0
  20. data/lib/maruku/html_helper.rb +33 -13
  21. data/lib/maruku/parse_block.rb +89 -92
  22. data/lib/maruku/parse_doc.rb +43 -18
  23. data/lib/maruku/parse_span.rb +17 -46
  24. data/lib/maruku/parse_span_better.rb +681 -0
  25. data/lib/maruku/string_utils.rb +17 -10
  26. data/lib/maruku/structures.rb +62 -35
  27. data/lib/maruku/structures_iterators.rb +39 -0
  28. data/lib/maruku/tests/benchmark.rb +12 -4
  29. data/lib/maruku/tests/new_parser.rb +318 -0
  30. data/lib/maruku/to_html.rb +113 -44
  31. data/lib/maruku/to_latex.rb +32 -14
  32. data/lib/maruku/to_markdown.rb +110 -0
  33. data/lib/maruku/toc.rb +35 -1
  34. data/lib/maruku/version.rb +10 -1
  35. data/lib/test.rb +29 -0
  36. data/tests/others/escaping.md +6 -4
  37. data/tests/others/links.md +1 -1
  38. data/tests/others/lists_after_paragraph.md +44 -0
  39. data/tests/unittest/abbreviations.md +71 -0
  40. data/tests/unittest/blank.md +43 -0
  41. data/tests/unittest/blanks_in_code.md +131 -0
  42. data/tests/unittest/code.md +64 -0
  43. data/tests/unittest/code2.md +59 -0
  44. data/tests/unittest/code3.md +121 -0
  45. data/tests/unittest/easy.md +36 -0
  46. data/tests/unittest/email.md +39 -0
  47. data/tests/unittest/encoding/iso-8859-1.md +9 -0
  48. data/tests/unittest/encoding/utf-8.md +38 -0
  49. data/tests/unittest/entities.md +174 -0
  50. data/tests/unittest/escaping.md +97 -0
  51. data/tests/unittest/extra_dl.md +81 -0
  52. data/tests/unittest/extra_header_id.md +96 -0
  53. data/tests/unittest/extra_table1.md +78 -0
  54. data/tests/unittest/footnotes.md +120 -0
  55. data/tests/unittest/headers.md +64 -0
  56. data/tests/unittest/hrule.md +77 -0
  57. data/tests/unittest/images.md +114 -0
  58. data/tests/unittest/inline_html.md +185 -0
  59. data/tests/unittest/links.md +162 -0
  60. data/tests/unittest/list1.md +80 -0
  61. data/tests/unittest/list2.md +75 -0
  62. data/tests/unittest/list3.md +111 -0
  63. data/tests/unittest/list4.md +43 -0
  64. data/tests/unittest/lists.md +262 -0
  65. data/tests/unittest/lists_after_paragraph.md +280 -0
  66. data/tests/unittest/lists_ol.md +323 -0
  67. data/tests/unittest/misc_sw.md +751 -0
  68. data/tests/unittest/notyet/escape.md +46 -0
  69. data/tests/unittest/notyet/header_after_par.md +85 -0
  70. data/tests/unittest/notyet/ticks.md +67 -0
  71. data/tests/unittest/notyet/triggering.md +210 -0
  72. data/tests/unittest/one.md +33 -0
  73. data/tests/unittest/paragraph.md +34 -0
  74. data/tests/unittest/paragraph_rules/dont_merge_ref.md +60 -0
  75. data/tests/unittest/paragraph_rules/tab_is_blank.md +43 -0
  76. data/tests/unittest/paragraphs.md +84 -0
  77. data/tests/unittest/recover/recover_links.md +32 -0
  78. data/tests/unittest/references/long_example.md +87 -0
  79. data/tests/unittest/references/spaces_and_numbers.md +27 -0
  80. data/tests/unittest/syntax_hl.md +99 -0
  81. data/tests/unittest/test.md +36 -0
  82. data/tests/unittest/wrapping.md +88 -0
  83. data/tests/utf8-files/simple.md +1 -0
  84. metadata +139 -86
  85. data/lib/maruku/maruku.rb +0 -50
  86. data/tests/a.md +0 -10
@@ -28,7 +28,10 @@ class Maruku
28
28
  include REXML
29
29
 
30
30
  # Render as an HTML fragment (no head, just the content of BODY). (returns a string)
31
- def to_html
31
+ def to_html(context={})
32
+ indent = context[:indent] || -1
33
+ ie_hack = context[:ie_hack] ||true
34
+
32
35
  div = Element.new 'dummy'
33
36
  children_to_html.each do |e|
34
37
  div << e
@@ -39,26 +42,32 @@ class Maruku
39
42
  div << render_footnotes
40
43
  end
41
44
 
45
+ doc = Document.new(nil,{:respect_whitespace =>:all})
46
+ doc << div
47
+ add_whitespace(doc)
48
+
42
49
  # REXML Bug? if indent!=-1 whitespace is not respected for 'pre' elements
43
50
  # containing code.
44
51
  xml =""
45
- div.write_children(xml,indent=-1,transitive=false,ie_hack=true)
52
+ div.write_children(xml,indent,transitive=true,ie_hack)
46
53
  xml
47
54
  end
48
55
 
49
56
  # Render to a complete HTML document (returns a string)
50
- def to_html_document
57
+ def to_html_document(context={})
58
+ indent = context[:indent] || -1
59
+ ie_hack = context[:ie_hack] ||true
51
60
  doc = to_html_document_tree
52
61
  xml = ""
53
62
 
54
63
  # REXML Bug? if indent!=-1 whitespace is not respected for 'pre' elements
55
64
  # containing code.
56
- doc.write(xml,indent=-1,transitive=false,ie_hack=true);
65
+ doc.write(xml,indent,transitive=true,ie_hack);
57
66
 
58
- encoding = ( (enc=@meta[:encoding]) ?
59
- "encoding='#{enc}'" : "")
67
+ # encoding = ( (enc=@meta[:encoding]) ?
68
+ # "encoding='#{enc}'" : "")
60
69
 
61
- xhtml10strict = "<?xml version='1.0' #{encoding}?>
70
+ xhtml10strict = "<?xml version='1.0' encoding='utf-8'?>
62
71
  <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'
63
72
  'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>\n"
64
73
  xhtml10strict + xml
@@ -110,12 +119,30 @@ class Maruku
110
119
  # at the bottom.
111
120
  body << maruku_html_signature
112
121
 
113
- root << head
114
122
  root << body
115
123
 
124
+ add_whitespace(doc)
116
125
  doc
117
126
  end
118
127
 
128
+ def add_whitespace(element)
129
+ blocks = ['p','pre','h1','h2','h3','h4','h5','h6',
130
+ 'style','table','div','ul','ol','li','dl','dt',
131
+ 'head','blockquote','tr','thead','td','dd','title',
132
+ 'link','hr']
133
+
134
+ element.get_elements( "//*" ).each do |e|
135
+ if blocks.include? e.name
136
+ e.parent.insert_before(e, Text.new("\n"))
137
+ e.parent.insert_after(e, Text.new("\n"))
138
+ end
139
+ end
140
+
141
+ element.get_elements( "//br" ).each do |e|
142
+ e.parent.insert_after(e, Text.new("\n"))
143
+ end
144
+ end
145
+
119
146
  # returns "st","nd","rd" or "th" as appropriate
120
147
  def day_suffix(day)
121
148
  case day%10
@@ -168,7 +195,7 @@ class Maruku
168
195
  li.children.last << a
169
196
  ol << li
170
197
  else
171
- $stderr.puts "Could not find footnote '#{fid}'"
198
+ maruku_error"Could not find footnote '#{fid}'"
172
199
  end
173
200
  end
174
201
  div << ol
@@ -230,7 +257,7 @@ class MDElement
230
257
  def section_number
231
258
  return nil if not @doc.meta[:use_numbered_headers]
232
259
 
233
- if (s = @meta[:section]) and not s.section_number.empty?
260
+ if (s = @section) and not s.section_number.empty?
234
261
  s.section_number.join('.')+". "
235
262
  else
236
263
  nil
@@ -272,12 +299,16 @@ class MDElement
272
299
  lang = self.meta[:lang] || @doc.meta[:code_lang]
273
300
 
274
301
  lang = 'xml' if lang=='html'
275
- use_syntax = @doc.meta[:html_use_syntax]
302
+ use_syntax = get_setting(:html_use_syntax)
276
303
 
277
304
  element =
278
305
  if use_syntax && lang
279
306
  begin
280
307
  convertor = Syntax::Convertors::HTML.for_syntax lang
308
+
309
+ # eliminate trailing newlines otherwise Syntax crashes
310
+ source = source.gsub(/\n*\Z/,'')
311
+
281
312
  html = convertor.convert( source )
282
313
 
283
314
  show_spaces = get_setting(:code_show_spaces)
@@ -290,10 +321,12 @@ class MDElement
290
321
  pre.attributes['class'] = lang
291
322
  pre
292
323
  rescue Object => e
293
- $stderr.puts "Error while using the syntax library for code:\n#{source.inspect}"
294
- $stderr.puts "Lang is #{lang} object is: "
295
- $stderr.puts @meta.inspect
296
- $stderr.puts "Exception: #{e.class}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
324
+ maruku_error"Error while using the syntax library for code:\n#{source.inspect}"+
325
+ "Lang is #{lang} object is: "+
326
+ @meta.inspect +
327
+ "Exception: #{e.class}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
328
+
329
+ tell_user("Using normal PRE because the syntax library did not work.")
297
330
  to_html_code_using_pre(source)
298
331
  end
299
332
  else
@@ -301,7 +334,7 @@ class MDElement
301
334
  end
302
335
 
303
336
  color = get_setting(:code_background_color,DEFAULT_CODE_COLOR)
304
- if color
337
+ if color != DEFAULT_CODE_COLOR
305
338
  element.attributes['style'] = "background-color: #{color};"
306
339
  end
307
340
  element
@@ -309,6 +342,7 @@ class MDElement
309
342
 
310
343
  def to_html_code_using_pre(source)
311
344
  pre = Element.new 'pre'
345
+ code = Element.new 'code', pre
312
346
  s = source
313
347
 
314
348
  s = s.gsub(/&/,'&amp;')
@@ -322,17 +356,17 @@ class MDElement
322
356
 
323
357
  text = Text.new(s, true, nil, false )
324
358
 
325
- pre << text
359
+ code << text
326
360
  pre
327
361
  end
328
362
 
329
363
  def to_html_inline_code;
330
- pre = Element.new 'tt'
364
+ pre = Element.new 'code'
331
365
  source = self.meta[:raw_code]
332
366
  pre << source2html(source)
333
367
 
334
368
  color = get_setting(:code_background_color, DEFAULT_CODE_COLOR)
335
- if color
369
+ if color != DEFAULT_CODE_COLOR
336
370
  pre.attributes['style'] = "background-color: #{color};"
337
371
  end
338
372
 
@@ -352,15 +386,33 @@ class MDElement
352
386
  def to_html_link
353
387
  a = wrap_as_element 'a'
354
388
 
355
- id = @meta[:ref_id]
356
- ref = @doc.refs[id]
357
- if not ref
358
- $stderr.puts "Could not find id = '#{id}'"
389
+ if id = @meta[:ref_id]
390
+ # if empty, use text
391
+ if id.size == 0
392
+ id = children.to_s.downcase
393
+ end
394
+ ref = @doc.refs[id]
395
+ if not ref
396
+ maruku_error"Could not find ref_id = #{id.inspect} for #{self.inspect}"
397
+ tell_user "Not creating a link for ref_id = #{id.inspect}."
398
+ return wrap_as_element('span')
399
+ else
400
+ url = ref[:url]
401
+ title = ref[:title]
402
+ a.attributes['href'] = url
403
+ a.attributes['title'] = title if title
404
+ end
359
405
  else
360
- url = ref[:url]
361
- title = ref[:title]
362
- a.attributes['href'] = url
363
- a.attributes['title'] = title if title
406
+ url = @meta[:url]
407
+ title = @meta[:title]
408
+ if url
409
+ a.attributes['href'] = url
410
+ a.attributes['title'] = title if title
411
+ else
412
+ maruku_error"Could not find url in #{self.inspect}"
413
+ tell_user "Not creating a link for ref_id = #{id.inspect}."
414
+ return wrap_as_element('span')
415
+ end
364
416
  end
365
417
  a
366
418
  end
@@ -392,42 +444,56 @@ class MDElement
392
444
 
393
445
  def to_html_image
394
446
  a = Element.new 'img'
395
- id = @meta[:ref_id]
396
- ref = @doc.refs[id]
397
- if not ref
398
- $stderr.puts "Could not find id = '#{id}'"
399
- else
400
- url = ref[:url]
401
- a.attributes['src'] = url
402
- # puts ref.inspect
403
- [:title, :class, :style].each do |s|
404
- if ref[s] then
405
- a.attributes[s.to_s] = ref[s]
447
+ if id = @meta[:ref_id]
448
+ ref = @doc.refs[id]
449
+ if not ref
450
+ maruku_error"Could not find id = #{id.inspect} for\n #{self.inspect}"
451
+ tell_user "Could not create image with ref_id = #{id.inspect};"+
452
+ +" Using SPAN element as replacement."
453
+ return wrap_as_element('span')
454
+ else
455
+ url = ref[:url]
456
+ a.attributes['src'] = url
457
+ # puts ref.inspect
458
+ [:title, :class, :style].each do |s|
459
+ if ref[s] then
460
+ a.attributes[s.to_s] = ref[s]
461
+ end
406
462
  end
407
463
  end
408
-
464
+ else
465
+ url = @meta[:url]
466
+ title = @meta[:title]
467
+ if not url
468
+ maruku_error"Image with no ID or url: #{self.inspect}"
469
+ tell_user "Could not create image with ref_id = #{id.inspect};"+
470
+ +" Using SPAN element as replacement."
471
+ return wrap_as_element('span')
472
+ end
473
+ a.attributes['src'] = url
474
+ a.attributes['title'] = title if title
409
475
  end
410
476
  a
411
477
  end
412
478
 
413
479
  def to_html_raw_html
414
480
  raw_html = @meta[:raw_html]
415
- if rexml_doc = @meta[:parsed_html]
481
+ if rexml_doc = @parsed_html
416
482
  root = rexml_doc.root
417
483
  if root.nil?
418
484
  s = "Bug in REXML: root() of Document is nil: \n#{rexml_doc.inspect}\n"+
419
485
  "Raw HTML:\n#{raw_html.inspect}"
420
- # $stderr.puts s
486
+ maruku_error s
487
+ tell_user 'The REXML version you have has a bug, omitting HTML'
421
488
  div = Element.new 'div'
422
- # div << Text.new(s)
489
+ #div << Text.new(s)
423
490
  return div
424
-
425
491
  end
426
492
 
427
493
  return root
428
494
  else # invalid
429
495
  # Creates red box with offending HTML
430
- $stderr.puts "Malformed HTML: #{raw_html}"
496
+ tell_user 'Wrapping bad html in a PRE with class "markdown-html-error"'
431
497
  pre = Element.new('pre')
432
498
  pre.attributes['style'] = 'border: solid 3px red; background-color: pink'
433
499
  pre.attributes['class'] = 'markdown-html-error'
@@ -554,6 +620,9 @@ class MDElement
554
620
  e
555
621
  end
556
622
 
623
+ def to_html_ref_definition; [] end
624
+ def to_latex_ref_definition; [] end
625
+
557
626
  end
558
627
 
559
628
 
@@ -37,14 +37,14 @@ class Maruku
37
37
  body += render_latex_signature
38
38
 
39
39
  "\\documentclass{article}
40
-
41
40
  #{header}
42
41
  \\usepackage{hyperref}
43
42
  \\usepackage{xspace}
44
- %\\usepackage[x11names]{xcolor}
45
43
  \\usepackage[usenames,dvipsnames]{color}
46
44
  \\usepackage[margin=1in]{geometry}
47
45
  \\hypersetup{colorlinks=true}
46
+ %\\usepackage{ucs}
47
+ %\\usepackage[utf8x]{inputenc}
48
48
  \\begin{document}
49
49
  #{body}
50
50
  \\end{document}
@@ -176,6 +176,7 @@ class MDElement
176
176
  def wrap_as_span(c)
177
177
  "{#{c} #{children_to_latex}}"
178
178
  end
179
+
179
180
  def wrap_as_environment(name)
180
181
  "\\begin{#{name}}%
181
182
  #{children_to_latex}
@@ -183,6 +184,7 @@ class MDElement
183
184
  end
184
185
 
185
186
  # the ultimate escaping
187
+ # (is much better than using \verb)
186
188
  def latex_escape(source)
187
189
  s="";
188
190
  source.each_byte do |b| s+= "\\char%d" % b end
@@ -192,12 +194,13 @@ class MDElement
192
194
  def to_latex_inline_code;
193
195
  source = self.meta[:raw_code]
194
196
 
195
- # Convert to printable latex chars (is much better than using \verb)
196
- s=latex_escape(source)
197
-
198
- color = latex_color(get_setting(:code_background_color,DEFAULT_CODE_COLOR),'colorbox')
197
+ # Convert to printable latex chars
198
+ s = latex_escape(source)
199
+
200
+ color = get_setting(:code_background_color,DEFAULT_CODE_COLOR)
201
+ colorspec = latex_color(color, 'colorbox')
199
202
 
200
- "#{color}{\\tt #{s}}"
203
+ "#{colorspec}{\\tt #{s}}"
201
204
  end
202
205
 
203
206
  def to_latex_immediate_link
@@ -206,14 +209,29 @@ class MDElement
206
209
  end
207
210
 
208
211
  def to_latex_link
209
- id = @meta[:ref_id]
210
- ref = @doc.refs[id]
211
- if not ref
212
- $stderr.puts "Could not find id = '#{id}'"
213
- return children_to_latex
212
+ if id = @meta[:ref_id]
213
+ # if empty, use text
214
+ if id.size == 0
215
+ id = children.to_s.downcase
216
+ end
217
+
218
+ ref = @doc.refs[id]
219
+ if not ref
220
+ $stderr.puts "Could not find id = '#{id}'"
221
+ return children_to_latex
222
+ else
223
+ url = ref[:url]
224
+ #title = ref[:title] || 'no title'
225
+
226
+ if url[0,1] == '#'
227
+ url = url[1,url.size]
228
+ return "\\hyperlink{#{url}}{#{children_to_latex}}"
229
+ else
230
+ return "\\href{#{url}}{#{children_to_latex}}"
231
+ end
232
+ end
214
233
  else
215
- url = ref[:url]
216
- #title = ref[:title] || 'no title'
234
+ url = @meta[:url]
217
235
 
218
236
  if url[0,1] == '#'
219
237
  url = url[1,url.size]
@@ -0,0 +1,110 @@
1
+ class String
2
+ # XXX: markdown escaping
3
+ def to_md(c=nil)
4
+ to_s
5
+ end
6
+
7
+ # " andrea censi " => [" andrea ", "censi "]
8
+ def mysplit
9
+ split.map{|x| x+" "}
10
+ end
11
+ end
12
+
13
+
14
+ class MDElement
15
+
16
+ DefaultLineLength = 50
17
+
18
+ def to_md(context={})
19
+ children_to_md(context)
20
+ end
21
+
22
+ def to_md_paragraph(context)
23
+ line_length = context[:line_length] || DefaultLineLength
24
+ wrap(@children, line_length)
25
+ end
26
+
27
+ def to_md_li_span(context)
28
+ len = (context[:line_length] || DefaultLineLength) - 2
29
+ s = add_tabs(wrap(@children, len-2), 1, ' ')
30
+ s[0] = ?*
31
+ s + "\n"
32
+ end
33
+ end
34
+
35
+ # Some utilities
36
+ class MDElement
37
+
38
+ # Convert each child to html
39
+ def children_to_md(context)
40
+ array_to_md(@children, context)
41
+ end
42
+
43
+ def wrap(array, line_length)
44
+ out = ""
45
+ line = ""
46
+ array.each do |c|
47
+ if c.kind_of?(MDElement) && c.node_type == :linebreak
48
+ out << line.strip << " \n"; line="";
49
+ next
50
+ end
51
+
52
+ pieces =
53
+ if c.kind_of? String
54
+ c.to_md.mysplit
55
+ else
56
+ [c.to_md].flatten
57
+ end
58
+
59
+ # puts "Pieces: #{pieces.inspect}"
60
+ pieces.each do |p|
61
+ if p.size + line.size > line_length
62
+ out << line.strip << "\n";
63
+ line = ""
64
+ end
65
+ line << p
66
+ end
67
+ end
68
+ out << line.strip << "\n" if line.size > 0
69
+ out
70
+ end
71
+
72
+
73
+ def array_to_md(array, context, join_char='')
74
+ e = []
75
+ array.each do |c|
76
+ method = c.kind_of?(MDElement) ?
77
+ "to_md_#{c.node_type}" : "to_md"
78
+
79
+ if not c.respond_to?(method)
80
+ #raise "Object does not answer to #{method}: #{c.class} #{c.inspect[0,100]}"
81
+ tell_user "Using default for #{c.node_type}"
82
+ method = 'to_md'
83
+ end
84
+
85
+ # puts "#{c.inspect} created with method #{method}"
86
+ h = c.send(method, context)
87
+
88
+ if h.nil?
89
+ raise "Nil md for #{c.inspect} created with method #{method}"
90
+ end
91
+
92
+ if h.kind_of?Array
93
+ e = e + h
94
+ else
95
+ e << h
96
+ end
97
+ end
98
+ e.join(join_char)
99
+ end
100
+
101
+ end
102
+
103
+ class Maruku
104
+ alias old_md to_md
105
+ def to_md(context={})
106
+ s = old_md(context)
107
+ # puts s
108
+ s
109
+ end
110
+ end