maruku 0.2

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 (60) hide show
  1. data/bin/maruku +25 -0
  2. data/bin/marutex +29 -0
  3. data/docs/Makefile +25 -0
  4. data/docs/char_codes.xml +884 -0
  5. data/docs/color-package-demo.aux +1 -0
  6. data/docs/color-package-demo.log +127 -0
  7. data/docs/color-package-demo.tex +149 -0
  8. data/docs/index.html +74 -0
  9. data/docs/markdown_syntax.aux +13 -0
  10. data/docs/markdown_syntax.html +266 -0
  11. data/docs/markdown_syntax.log +287 -0
  12. data/docs/markdown_syntax.md +920 -0
  13. data/docs/markdown_syntax.out +0 -0
  14. data/docs/markdown_syntax.pdf +0 -0
  15. data/docs/markdown_syntax.tex +1203 -0
  16. data/docs/maruku.aux +13 -0
  17. data/docs/maruku.html +74 -0
  18. data/docs/maruku.log +294 -0
  19. data/docs/maruku.md +394 -0
  20. data/docs/maruku.out +0 -0
  21. data/docs/maruku.pdf +0 -0
  22. data/docs/maruku.tex +548 -0
  23. data/docs/style.css +65 -0
  24. data/docs/todo.md +12 -0
  25. data/lib/maruku.rb +20 -0
  26. data/lib/maruku/parse_block.rb +577 -0
  27. data/lib/maruku/parse_span.rb +336 -0
  28. data/lib/maruku/string_utils.rb +270 -0
  29. data/lib/maruku/structures.rb +31 -0
  30. data/lib/maruku/to_html.rb +430 -0
  31. data/lib/maruku/to_latex.rb +345 -0
  32. data/lib/maruku/to_latex_strings.rb +330 -0
  33. data/tests/abbreviations.md +11 -0
  34. data/tests/blank.md +4 -0
  35. data/tests/code.md +5 -0
  36. data/tests/code2.md +8 -0
  37. data/tests/code3.md +16 -0
  38. data/tests/email.md +4 -0
  39. data/tests/entities.md +19 -0
  40. data/tests/escaping.md +14 -0
  41. data/tests/extra_dl.md +101 -0
  42. data/tests/extra_header_id.md +13 -0
  43. data/tests/extra_table1.md +40 -0
  44. data/tests/footnotes.md +17 -0
  45. data/tests/headers.md +10 -0
  46. data/tests/hrule.md +10 -0
  47. data/tests/images.md +20 -0
  48. data/tests/inline_html.md +35 -0
  49. data/tests/links.md +31 -0
  50. data/tests/list1.md +4 -0
  51. data/tests/list2.md +5 -0
  52. data/tests/list3.md +8 -0
  53. data/tests/lists.md +32 -0
  54. data/tests/lists_ol.md +39 -0
  55. data/tests/misc_sw.md +105 -0
  56. data/tests/one.md +1 -0
  57. data/tests/paragraphs.md +13 -0
  58. data/tests/sss06.md +352 -0
  59. data/tests/test.md +4 -0
  60. metadata +113 -0
@@ -0,0 +1,31 @@
1
+
2
+ class MDElement
3
+ # Allowed: :document, :paragraph, :ul, :ol, :li, :li_span, :strong, :emphasis, :link1
4
+ attr_accessor :node_type
5
+ # Children are either Strings or MDElement
6
+ attr_accessor :children
7
+ # Hash for metadata
8
+ # contains :id for :link1
9
+ # :li :want_my_paragraph
10
+ # :header: :level
11
+ # code, inline_code: :raw_code
12
+ attr_accessor :meta
13
+ # reference of containing document (document has list of ref)
14
+ attr_accessor :doc
15
+
16
+ def initialize
17
+ super();
18
+ @children = [];
19
+ @node_type = :unset
20
+ @meta = {};
21
+ end
22
+
23
+ end
24
+
25
+ # The Maruku class holds static data for the document
26
+
27
+ class Maruku < MDElement
28
+ attr_accessor :refs
29
+ attr_accessor :footnotes
30
+ attr_accessor :abbreviations
31
+ end
@@ -0,0 +1,430 @@
1
+ require 'rexml/document'
2
+
3
+ require 'rubygems'
4
+ require 'syntax'
5
+ require 'syntax/convertors/html'
6
+
7
+
8
+ class Maruku
9
+ include REXML
10
+
11
+ # Render as an HTML fragment (no head, just the content of BODY). (returns a string)
12
+ def to_html
13
+ div = Element.new 'dummy'
14
+ children_to_html.each do |e|
15
+ div << e
16
+ end
17
+
18
+ # render footnotes
19
+ if @doc.meta[:footnotes_used]
20
+ div << render_footnotes
21
+ end
22
+
23
+ # REXML Bug? if indent!=-1 whitespace is not respected for 'pre' elements
24
+ # containing code.
25
+ xml =""
26
+ div.write_children(xml,indent=-1,transitive=false,ie_hack=true)
27
+ xml
28
+ end
29
+
30
+ # Render to a complete HTML document (returns a string)
31
+ def to_html_document
32
+ doc = to_html_document_tree
33
+ xml = ""
34
+
35
+ # REXML Bug? if indent!=-1 whitespace is not respected for 'pre' elements
36
+ # containing code.
37
+ doc.write(xml,indent=-1,transitive=false,ie_hack=true);
38
+ xhtml10strict = "<?xml version='1.0'?>
39
+ <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'
40
+ 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>\n"
41
+ xhtml10strict + xml
42
+ end
43
+
44
+ # Render to a complete HTML document (returns a REXML document tree)
45
+ def to_html_document_tree
46
+ doc = Document.new(nil,{:respect_whitespace =>:all})
47
+ # doc << XMLDecl.new
48
+
49
+ root = Element.new('html', doc)
50
+ root.add_namespace('http://www.w3.org/1999/xhtml')
51
+
52
+ lang = @meta[:lang] || 'en'
53
+ root.attributes['lang'] = lang
54
+ root.attributes['xml:lang'] = lang
55
+
56
+ head = Element.new 'head', root
57
+
58
+ # Create title element
59
+ doc_title = @meta[:title] || @meta[:subject] || ""
60
+ title = Element.new 'title'
61
+ title << Text.new(doc_title)
62
+ head << title
63
+
64
+
65
+ css = @meta[:css]
66
+ if css
67
+ # <link type="text/css" rel="stylesheet" href="..." />
68
+ link = Element.new 'link'
69
+ link.attributes['type'] = 'text/css'
70
+ link.attributes['rel'] = 'stylesheet'
71
+ link.attributes['href'] = css
72
+ head << link
73
+ end
74
+
75
+ body = Element.new 'body'
76
+
77
+ children_to_html.each do |e|
78
+ body << e
79
+ end
80
+
81
+ # render footnotes
82
+ if @doc.meta[:footnotes_used]
83
+ body << render_footnotes
84
+ end
85
+
86
+
87
+ root << head
88
+ root << body
89
+
90
+ doc
91
+ end
92
+
93
+ def render_footnotes
94
+ div = Element.new 'div'
95
+ div.attributes['class'] = 'footnotes'
96
+ div << Element.new('hr')
97
+ ol = Element.new 'ol'
98
+ @doc.meta[:footnotes_used].each_with_index do |fid, i| num = i+1
99
+ f = @footnotes[fid]
100
+ if f
101
+ li = f.wrap_as_element('li')
102
+ li.attributes['id'] = "fn:#{num}"
103
+
104
+ a = Element.new 'a'
105
+ a.attributes['href'] = "#fnref:#{num}"
106
+ a.attributes['rev'] = 'footnote'
107
+ a<< Text.new('&#8617;', true, nil, true)
108
+ li.children.last << a
109
+ ol << li
110
+ else
111
+ $stderr.puts "Could not find footnote '#{fid}'"
112
+ end
113
+ end
114
+ div << ol
115
+ div
116
+ end
117
+ end
118
+
119
+ class String
120
+ # A string is rendered into HTML by creating
121
+ # a REXML::Text node. REXML takes care of all the encoding.
122
+ def to_html
123
+ REXML::Text.new(self)
124
+ end
125
+ end
126
+
127
+ class MDElement
128
+
129
+ def to_html_hrule; Element.new 'hr' end
130
+ def to_html_linebreak; Element.new 'br' end
131
+
132
+ # renders children as html and wraps into an element of given name
133
+ #
134
+ # Sets 'id' if meta is set
135
+ def wrap_as_element(name)
136
+ m = create_html_element name
137
+ children_to_html.each do |e| m << e; end
138
+ m
139
+ end
140
+
141
+ def create_html_element(name)
142
+ m = Element.new name
143
+ if @meta[:id] then m.attributes['id'] = @meta[:id].to_s end
144
+ if @meta[:style] then m.attributes['style'] = @meta[:style].to_s end
145
+ if @meta[:class] then m.attributes['class'] = @meta[:class].to_s end
146
+ m
147
+ end
148
+
149
+ def to_html_paragraph; wrap_as_element('p') end
150
+ def to_html_ul; wrap_as_element('ul') end
151
+ def to_html_ol; wrap_as_element('ol') end
152
+ def to_html_li; wrap_as_element('li') end
153
+ def to_html_li_span; wrap_as_element('li') end
154
+ def to_html_quote; wrap_as_element('blockquote') end
155
+ def to_html_strong; wrap_as_element('strong') end
156
+ def to_html_emphasis; wrap_as_element('em') end
157
+ def to_html_header; wrap_as_element "h#{@meta[:level]}" end
158
+
159
+ def source2html(source)
160
+ source = source.gsub(/&/,'&amp;')
161
+ source = Text.normalize(source)
162
+ Text.new(source, true, nil, false )
163
+ end
164
+
165
+ def to_html_code;
166
+ source = self.meta[:raw_code]
167
+
168
+ lang = self.meta[:lang] || @doc.meta[:code_lang]
169
+
170
+ lang = 'xml' if lang=='html'
171
+ use_syntax = @doc.meta[:html_use_syntax]
172
+
173
+ element =
174
+ if use_syntax && lang
175
+ convertor = Syntax::Convertors::HTML.for_syntax lang
176
+ html = convertor.convert( source )
177
+
178
+ show_spaces = get_setting(:code_show_spaces)
179
+ if show_spaces
180
+ s.gsub!(/\t/,'&raquo;'+'&nbsp;'*3)
181
+ s.gsub!(/ /,'&not;')
182
+ end
183
+
184
+ # puts "html: #{html}"
185
+ pre = Document.new(html, {:respect_whitespace =>:all}).root
186
+ pre.attributes['class'] = lang
187
+ # puts "After: #{pre}"
188
+ pre
189
+ else
190
+ pre = Element.new 'pre'
191
+ s = source
192
+
193
+ s = s.gsub(/&/,'&amp;')
194
+ s = Text.normalize(s)
195
+
196
+ show_spaces = get_setting(:code_show_spaces)
197
+ if show_spaces
198
+ s.gsub!(/\t/,'&raquo;'+'&nbsp;'*3)
199
+ s.gsub!(/ /,'&not;')
200
+ end
201
+
202
+ text = Text.new(s, true, nil, false )
203
+
204
+ pre << text
205
+ pre
206
+ end
207
+
208
+ color = get_setting(:code_background_color,DEFAULT_CODE_COLOR)
209
+ if color
210
+ element.attributes['style'] = "background-color: #{color};"
211
+ end
212
+ element
213
+ end
214
+
215
+ def to_html_inline_code;
216
+ pre = Element.new 'tt'
217
+ source = self.meta[:raw_code]
218
+ pre << source2html(source)
219
+
220
+ color = get_setting(:code_background_color, DEFAULT_CODE_COLOR)
221
+ if color
222
+ pre.attributes['style'] = "background-color: #{color};"
223
+ end
224
+
225
+ pre
226
+ end
227
+
228
+ def to_html_immediate_link
229
+ a = Element.new 'a'
230
+ url = @meta[:url]
231
+ text = url
232
+ text = text.gsub(/^mailto:/,'') # don't show mailto
233
+ a << Text.new(text)
234
+ a.attributes['href'] = url
235
+ a
236
+ end
237
+
238
+ def to_html_link
239
+ a = wrap_as_element 'a'
240
+
241
+ id = @meta[:ref_id]
242
+ ref = @doc.refs[id]
243
+ if not ref
244
+ $stderr.puts "Could not find id = '#{id}'"
245
+ else
246
+ url = ref[:url]
247
+ title = ref[:title]
248
+ a.attributes['href'] = url
249
+ a.attributes['title'] = title if title
250
+ end
251
+ a
252
+ end
253
+
254
+ ##### Email address
255
+
256
+ def obfuscate(s)
257
+ res = ''
258
+ s.each_byte do |char|
259
+ res += "&#%03d;" % char
260
+ end
261
+ res
262
+ end
263
+
264
+ def to_html_email_address
265
+ email = @meta[:email]
266
+ a = Element.new 'a'
267
+ #a.attributes['href'] = Text.new("mailto:"+obfuscate(email),false,nil,true)
268
+ #a.attributes.add Attribute.new('href',Text.new(
269
+ #"mailto:"+obfuscate(email),false,nil,true))
270
+ # Sorry, for the moment it doesn't work
271
+ a.attributes['href'] = "mailto:#{email}"
272
+
273
+ a << Text.new(obfuscate(email),false,nil,true)
274
+ a
275
+ end
276
+
277
+ ##### Images
278
+
279
+ def to_html_image
280
+ a = Element.new 'img'
281
+ id = @meta[:ref_id]
282
+ ref = @doc.refs[id]
283
+ if not ref
284
+ $stderr.puts "Could not find id = '#{id}'"
285
+ else
286
+ url = ref[:url]
287
+ a.attributes['src'] = url
288
+ # puts ref.inspect
289
+ [:title, :class, :style].each do |s|
290
+ if ref[s] then
291
+ a.attributes[s.to_s] = ref[s]
292
+ end
293
+ end
294
+
295
+ end
296
+ a
297
+ end
298
+
299
+ def to_html_raw_html
300
+ if @meta[:parsed_html]
301
+ return @meta[:parsed_html].root
302
+ else # invalid
303
+ raw_html = @meta[:raw_html]
304
+ # Creates red box with offending HTML
305
+ $stderr.puts "Malformed HTML: #{raw_html}"
306
+ div = Element.new('pre')
307
+ div.attributes['style'] = 'border: solid 3px red; background-color: pink'
308
+ div.attributes['class'] = 'markdown-html-error'
309
+ div << Text.new("HTML parse error: \n#{raw_html}", true)
310
+ return div
311
+ end
312
+ end
313
+
314
+ def to_html_abbreviation
315
+ abbr = Element.new 'abbr'
316
+ abbr << Text.new(children[0])
317
+ abbr.attributes['title'] = self.meta[:title] if self.meta[:title]
318
+ abbr
319
+ end
320
+
321
+ def to_html_footnote_reference
322
+ id = @meta[:footnote_id]
323
+
324
+ # save the order of used footnotes
325
+ order = (@doc.meta[:footnotes_used] ||= [])
326
+
327
+ # take next number
328
+ order << id
329
+ num = order.size;
330
+
331
+ sup = Element.new 'sup'
332
+ sup.attributes['id'] = "fnref:#{num}"
333
+ a = Element.new 'a'
334
+ a << Text.new(num.to_s)
335
+ a.attributes['href'] = "\#fn:#{num}"
336
+ a.attributes['rel'] = 'footnote'
337
+ sup << a
338
+
339
+ sup
340
+ end
341
+ ## Definition lists ###
342
+ def to_html_definition_list
343
+ wrap_as_element('dl')
344
+ end
345
+ def to_html_definition
346
+ children_to_html
347
+ end
348
+ def to_html_definition_term; wrap_as_element('dt') end
349
+ def to_html_definition_data; wrap_as_element('dd') end
350
+
351
+ ## Table ###
352
+ def to_html_table
353
+ align = @meta[:align]
354
+ num_columns = align.size
355
+
356
+ head = @children.slice(0, num_columns)
357
+ rows = []
358
+ i = num_columns
359
+ while i<@children.size
360
+ rows << @children.slice(i, num_columns)
361
+ i+=num_columns
362
+ end
363
+
364
+ table = create_html_element 'table'
365
+ thead = Element.new 'thead'
366
+ tr = Element.new 'tr'
367
+ array_to_html(head).each do |x| tr<<x end
368
+ thead << tr
369
+ table << thead
370
+
371
+ tbody = Element.new 'tbody'
372
+ rows.each do |row|
373
+ tr = Element.new 'tr'
374
+ array_to_html(row).each_with_index do |x,i|
375
+ x.attributes['style'] ="text-align: #{align[i].to_s};"
376
+ tr<<x
377
+ end
378
+
379
+ tbody << tr
380
+ end
381
+ table << tbody
382
+ table
383
+ end
384
+
385
+ def to_html_head_cell; wrap_as_element('th') end
386
+ def to_html_cell; wrap_as_element('td') end
387
+
388
+
389
+ end
390
+
391
+ # We only want to output the children in Maruku::to_html
392
+ class REXML::Element; public :write_children end
393
+
394
+ # Some utilities
395
+ class MDElement
396
+ include REXML
397
+
398
+ # Convert each child to html
399
+ def children_to_html
400
+ array_to_html(@children)
401
+ end
402
+
403
+ def array_to_html(array)
404
+ e = []
405
+ array.each do |c|
406
+ method = c.kind_of?(MDElement) ?
407
+ "to_html_#{c.node_type}" : "to_html"
408
+
409
+ if not c.respond_to?(method)
410
+ raise "Object does not answer to #{method}: #{c.class} #{c.inspect}"
411
+ end
412
+
413
+ h = c.send(method)
414
+
415
+ if h.nil?
416
+ raise "Nil html for #{c.inspect} created with method #{method}"
417
+ end
418
+
419
+ if h.kind_of?Array
420
+ e = e + h #h.each do |hh| e << hh end
421
+ else
422
+ e << h
423
+ end
424
+ end
425
+ e
426
+ end
427
+
428
+ end
429
+
430
+