kramdown 0.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of kramdown might be problematic. Click here for more details.

Files changed (201) hide show
  1. data/AUTHORS +1 -0
  2. data/COPYING +24 -0
  3. data/ChangeLog +1416 -0
  4. data/GPL +674 -0
  5. data/README +20 -0
  6. data/Rakefile +300 -0
  7. data/VERSION +1 -0
  8. data/benchmark/benchmark.rb +33 -0
  9. data/benchmark/mdbasics.text +306 -0
  10. data/benchmark/mdsyntax.text +888 -0
  11. data/benchmark/testing.sh +9 -0
  12. data/benchmark/timing.sh +10 -0
  13. data/bin/kramdown +26 -0
  14. data/doc/default.css +293 -0
  15. data/doc/default.template +78 -0
  16. data/doc/index.page +89 -0
  17. data/doc/installation.page +90 -0
  18. data/doc/news.feed +10 -0
  19. data/doc/news.page +27 -0
  20. data/doc/quickref.page +474 -0
  21. data/doc/syntax.page +1089 -0
  22. data/doc/tests.page +44 -0
  23. data/doc/virtual +2 -0
  24. data/lib/kramdown.rb +23 -0
  25. data/lib/kramdown/converter.rb +215 -0
  26. data/lib/kramdown/document.rb +150 -0
  27. data/lib/kramdown/error.rb +27 -0
  28. data/lib/kramdown/extension.rb +73 -0
  29. data/lib/kramdown/parser.rb +1056 -0
  30. data/lib/kramdown/parser/registry.rb +62 -0
  31. data/setup.rb +1585 -0
  32. data/test/run_tests.rb +58 -0
  33. data/test/test_files.rb +39 -0
  34. data/test/testcases/block/01_blank_line/spaces.html +1 -0
  35. data/test/testcases/block/01_blank_line/spaces.text +3 -0
  36. data/test/testcases/block/01_blank_line/tabs.html +1 -0
  37. data/test/testcases/block/01_blank_line/tabs.text +6 -0
  38. data/test/testcases/block/02_eob/beginning.html +1 -0
  39. data/test/testcases/block/02_eob/beginning.text +3 -0
  40. data/test/testcases/block/02_eob/end.html +1 -0
  41. data/test/testcases/block/02_eob/end.text +3 -0
  42. data/test/testcases/block/02_eob/middle.html +1 -0
  43. data/test/testcases/block/02_eob/middle.text +5 -0
  44. data/test/testcases/block/03_paragraph/indented.html +18 -0
  45. data/test/testcases/block/03_paragraph/indented.text +19 -0
  46. data/test/testcases/block/03_paragraph/no_newline_at_end.html +5 -0
  47. data/test/testcases/block/03_paragraph/no_newline_at_end.text +5 -0
  48. data/test/testcases/block/03_paragraph/one_para.html +1 -0
  49. data/test/testcases/block/03_paragraph/one_para.text +1 -0
  50. data/test/testcases/block/03_paragraph/two_para.html +4 -0
  51. data/test/testcases/block/03_paragraph/two_para.text +4 -0
  52. data/test/testcases/block/04_header/atx_header.html +26 -0
  53. data/test/testcases/block/04_header/atx_header.text +24 -0
  54. data/test/testcases/block/04_header/atx_header_no_newline_at_end.html +1 -0
  55. data/test/testcases/block/04_header/atx_header_no_newline_at_end.text +1 -0
  56. data/test/testcases/block/04_header/setext_header.html +25 -0
  57. data/test/testcases/block/04_header/setext_header.text +27 -0
  58. data/test/testcases/block/04_header/setext_header_no_newline_at_end.html +1 -0
  59. data/test/testcases/block/04_header/setext_header_no_newline_at_end.text +2 -0
  60. data/test/testcases/block/04_header/with_auto_ids.html +17 -0
  61. data/test/testcases/block/04_header/with_auto_ids.options +1 -0
  62. data/test/testcases/block/04_header/with_auto_ids.text +19 -0
  63. data/test/testcases/block/05_blockquote/indented.html +25 -0
  64. data/test/testcases/block/05_blockquote/indented.text +14 -0
  65. data/test/testcases/block/05_blockquote/nested.html +9 -0
  66. data/test/testcases/block/05_blockquote/nested.text +5 -0
  67. data/test/testcases/block/05_blockquote/no_newline_at_end.html +4 -0
  68. data/test/testcases/block/05_blockquote/no_newline_at_end.text +2 -0
  69. data/test/testcases/block/05_blockquote/only_first_quoted.html +8 -0
  70. data/test/testcases/block/05_blockquote/only_first_quoted.text +4 -0
  71. data/test/testcases/block/05_blockquote/with_code_blocks.html +15 -0
  72. data/test/testcases/block/05_blockquote/with_code_blocks.text +11 -0
  73. data/test/testcases/block/06_codeblock/error.html +4 -0
  74. data/test/testcases/block/06_codeblock/error.text +4 -0
  75. data/test/testcases/block/06_codeblock/no_newline_at_end.html +2 -0
  76. data/test/testcases/block/06_codeblock/no_newline_at_end.text +1 -0
  77. data/test/testcases/block/06_codeblock/normal.html +13 -0
  78. data/test/testcases/block/06_codeblock/normal.text +10 -0
  79. data/test/testcases/block/06_codeblock/tilde_syntax.html +7 -0
  80. data/test/testcases/block/06_codeblock/tilde_syntax.text +9 -0
  81. data/test/testcases/block/06_codeblock/whitespace.html +3 -0
  82. data/test/testcases/block/06_codeblock/whitespace.text +3 -0
  83. data/test/testcases/block/06_codeblock/with_blank_line.html +13 -0
  84. data/test/testcases/block/06_codeblock/with_blank_line.text +11 -0
  85. data/test/testcases/block/06_codeblock/with_eob_marker.html +6 -0
  86. data/test/testcases/block/06_codeblock/with_eob_marker.text +5 -0
  87. data/test/testcases/block/07_horizontal_rule/error.html +7 -0
  88. data/test/testcases/block/07_horizontal_rule/error.text +7 -0
  89. data/test/testcases/block/07_horizontal_rule/normal.html +19 -0
  90. data/test/testcases/block/07_horizontal_rule/normal.text +19 -0
  91. data/test/testcases/block/08_list/escaping.html +17 -0
  92. data/test/testcases/block/08_list/escaping.text +17 -0
  93. data/test/testcases/block/08_list/list_and_hr.html +9 -0
  94. data/test/testcases/block/08_list/list_and_hr.text +5 -0
  95. data/test/testcases/block/08_list/list_and_others.html +38 -0
  96. data/test/testcases/block/08_list/list_and_others.text +25 -0
  97. data/test/testcases/block/08_list/mixed.html +111 -0
  98. data/test/testcases/block/08_list/mixed.text +66 -0
  99. data/test/testcases/block/08_list/nested.html +17 -0
  100. data/test/testcases/block/08_list/nested.text +7 -0
  101. data/test/testcases/block/08_list/other_first_element.html +39 -0
  102. data/test/testcases/block/08_list/other_first_element.text +18 -0
  103. data/test/testcases/block/08_list/simple_ol.html +19 -0
  104. data/test/testcases/block/08_list/simple_ol.text +13 -0
  105. data/test/testcases/block/08_list/simple_ul.html +61 -0
  106. data/test/testcases/block/08_list/simple_ul.text +43 -0
  107. data/test/testcases/block/08_list/single_item.html +3 -0
  108. data/test/testcases/block/08_list/single_item.text +1 -0
  109. data/test/testcases/block/08_list/special_cases.html +29 -0
  110. data/test/testcases/block/08_list/special_cases.text +19 -0
  111. data/test/testcases/block/09_html/auto_parse_block_html.html +17 -0
  112. data/test/testcases/block/09_html/auto_parse_block_html.options +1 -0
  113. data/test/testcases/block/09_html/auto_parse_block_html.text +14 -0
  114. data/test/testcases/block/09_html/comment.html +12 -0
  115. data/test/testcases/block/09_html/comment.text +12 -0
  116. data/test/testcases/block/09_html/filtered_html.html +1 -0
  117. data/test/testcases/block/09_html/filtered_html.options +1 -0
  118. data/test/testcases/block/09_html/filtered_html.text +1 -0
  119. data/test/testcases/block/09_html/html_and_codeblocks.html +15 -0
  120. data/test/testcases/block/09_html/html_and_codeblocks.options +1 -0
  121. data/test/testcases/block/09_html/html_and_codeblocks.text +13 -0
  122. data/test/testcases/block/09_html/invalid_html_1.html +5 -0
  123. data/test/testcases/block/09_html/invalid_html_1.text +5 -0
  124. data/test/testcases/block/09_html/invalid_html_2.html +6 -0
  125. data/test/testcases/block/09_html/invalid_html_2.text +5 -0
  126. data/test/testcases/block/09_html/parse_as_raw.html +26 -0
  127. data/test/testcases/block/09_html/parse_as_raw.text +16 -0
  128. data/test/testcases/block/09_html/parse_as_span.html +12 -0
  129. data/test/testcases/block/09_html/parse_as_span.text +7 -0
  130. data/test/testcases/block/09_html/processing_instruction.html +12 -0
  131. data/test/testcases/block/09_html/processing_instruction.text +12 -0
  132. data/test/testcases/block/09_html/simple.html +78 -0
  133. data/test/testcases/block/09_html/simple.text +56 -0
  134. data/test/testcases/block/10_ald/simple.html +2 -0
  135. data/test/testcases/block/10_ald/simple.text +8 -0
  136. data/test/testcases/block/11_ial/simple.html +17 -0
  137. data/test/testcases/block/11_ial/simple.text +25 -0
  138. data/test/testcases/block/12_extension/comment.html +5 -0
  139. data/test/testcases/block/12_extension/comment.text +11 -0
  140. data/test/testcases/block/12_extension/ignored.html +6 -0
  141. data/test/testcases/block/12_extension/ignored.text +11 -0
  142. data/test/testcases/block/12_extension/kdoptions.html +15 -0
  143. data/test/testcases/block/12_extension/kdoptions.text +18 -0
  144. data/test/testcases/block/12_extension/kdoptions2.html +10 -0
  145. data/test/testcases/block/12_extension/kdoptions2.text +5 -0
  146. data/test/testcases/block/12_extension/nokramdown.html +6 -0
  147. data/test/testcases/block/12_extension/nokramdown.text +11 -0
  148. data/test/testcases/span/01_link/empty.html +3 -0
  149. data/test/testcases/span/01_link/empty.text +3 -0
  150. data/test/testcases/span/01_link/image_in_a.html +5 -0
  151. data/test/testcases/span/01_link/image_in_a.text +5 -0
  152. data/test/testcases/span/01_link/imagelinks.html +12 -0
  153. data/test/testcases/span/01_link/imagelinks.text +14 -0
  154. data/test/testcases/span/01_link/inline.html +40 -0
  155. data/test/testcases/span/01_link/inline.text +42 -0
  156. data/test/testcases/span/01_link/link_defs.html +8 -0
  157. data/test/testcases/span/01_link/link_defs.text +22 -0
  158. data/test/testcases/span/01_link/links_with_angle_brackets.html +3 -0
  159. data/test/testcases/span/01_link/links_with_angle_brackets.text +3 -0
  160. data/test/testcases/span/01_link/reference.html +32 -0
  161. data/test/testcases/span/01_link/reference.text +42 -0
  162. data/test/testcases/span/02_emphasis/empty.html +3 -0
  163. data/test/testcases/span/02_emphasis/empty.text +3 -0
  164. data/test/testcases/span/02_emphasis/errors.html +9 -0
  165. data/test/testcases/span/02_emphasis/errors.text +9 -0
  166. data/test/testcases/span/02_emphasis/nesting.html +34 -0
  167. data/test/testcases/span/02_emphasis/nesting.text +30 -0
  168. data/test/testcases/span/02_emphasis/normal.html +42 -0
  169. data/test/testcases/span/02_emphasis/normal.text +42 -0
  170. data/test/testcases/span/03_codespan/empty.html +5 -0
  171. data/test/testcases/span/03_codespan/empty.text +5 -0
  172. data/test/testcases/span/03_codespan/errors.html +1 -0
  173. data/test/testcases/span/03_codespan/errors.text +1 -0
  174. data/test/testcases/span/03_codespan/normal.html +16 -0
  175. data/test/testcases/span/03_codespan/normal.text +16 -0
  176. data/test/testcases/span/04_footnote/definitions.html +14 -0
  177. data/test/testcases/span/04_footnote/definitions.text +18 -0
  178. data/test/testcases/span/04_footnote/footnote_nr.html +12 -0
  179. data/test/testcases/span/04_footnote/footnote_nr.options +1 -0
  180. data/test/testcases/span/04_footnote/footnote_nr.text +4 -0
  181. data/test/testcases/span/04_footnote/markers.html +46 -0
  182. data/test/testcases/span/04_footnote/markers.text +26 -0
  183. data/test/testcases/span/05_html/normal.html +17 -0
  184. data/test/testcases/span/05_html/normal.text +17 -0
  185. data/test/testcases/span/autolinks/url_links.html +9 -0
  186. data/test/testcases/span/autolinks/url_links.text +9 -0
  187. data/test/testcases/span/escaped_chars/normal.html +33 -0
  188. data/test/testcases/span/escaped_chars/normal.text +33 -0
  189. data/test/testcases/span/ial/simple.html +5 -0
  190. data/test/testcases/span/ial/simple.text +5 -0
  191. data/test/testcases/span/line_breaks/normal.html +11 -0
  192. data/test/testcases/span/line_breaks/normal.text +11 -0
  193. data/test/testcases/span/text_substitutions/entities.html +4 -0
  194. data/test/testcases/span/text_substitutions/entities.text +4 -0
  195. data/test/testcases/span/text_substitutions/greaterthan.html +1 -0
  196. data/test/testcases/span/text_substitutions/greaterthan.text +1 -0
  197. data/test/testcases/span/text_substitutions/lowerthan.html +1 -0
  198. data/test/testcases/span/text_substitutions/lowerthan.text +1 -0
  199. data/test/testcases/span/text_substitutions/typography.html +3 -0
  200. data/test/testcases/span/text_substitutions/typography.text +3 -0
  201. metadata +259 -0
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Tests and Benchmark
3
+ ---
4
+
5
+ # Tests
6
+
7
+ There exist several test suites for testing the correctness of a Markdown implementation. The
8
+ original [Markdown Test Suite] is the standard which one needs to test against. The [PHP Markdown
9
+ suite][MDTest] contains the original test suite and several more tests (some specifically geared
10
+ towards the extension of the PHP Markdown Extra package). I have used the latter test tool to
11
+ roughly verify that kramdown is able to parse standard Markdown. However, since the syntax used by
12
+ kramdown varies slightly from standard Markdown most of the tests fail - which is fine. When looking
13
+ at the differences one can see that the failures result from these differences.
14
+
15
+ Besides using the above mentioned test suite kramdown comes with its own set of tests which is used
16
+ to verify that the implementation matches the kramdown specification.
17
+
18
+ If you believe you have found a bug in the implementation, please follow these steps:
19
+
20
+ * Check the syntax page and see if the behaviour is not intended.
21
+
22
+ * If the behaviour is not intended and it seems that kramdown should parse some text in another
23
+ fashion, please open a bug report and attach two files: one with the text and one with the HTML
24
+ conversion you think is correct.
25
+
26
+ ^
27
+
28
+ # Benchmark
29
+
30
+ kramdown comes with a small benchmark to test how fast it is in regard to four other Ruby Markdown
31
+ implementations: Maruku, BlueFeather, BlueCloth and RDiscount. The first two are written using only
32
+ Ruby, the latter two use the C discount library for the actual hard work (which makes them really
33
+ fast but they do not provide additional syntax elements). As one can see below, kramdown is
34
+ currently (November 2009) ~5x faster than Maruku, ~10x faster than BlueFeather but ~30x slower than
35
+ BlueCloth and rdiscount:
36
+
37
+ {::nokramdown:}
38
+ <pre><code>
39
+ {execute_cmd: {command: "ruby -Ilib -rubygems benchmark/benchmark.rb", process_output: false, escape_html: true}}
40
+ </code></pre>
41
+ {::nokramdown:}
42
+
43
+ [Markdown Test Suite]: http://daringfireball.net/projects/downloads/MarkdownTest_1.0.zip
44
+ [MDTest]: http://www.michelf.com/docs/projets/mdtest-1.0.zip
@@ -0,0 +1,2 @@
1
+ rdoc/index.html:
2
+ title: API Documentation
@@ -0,0 +1,23 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown.
7
+ #
8
+ # kramdown is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #++
21
+ #
22
+
23
+ require 'kramdown/document'
@@ -0,0 +1,215 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown.
7
+ #
8
+ # kramdown is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #++
21
+ #
22
+
23
+ require 'rexml/parsers/baseparser'
24
+
25
+ module Kramdown
26
+
27
+ # This module contains all available converters, i.e. classes that take a document and convert the
28
+ # document tree to a string in a specific format, for example, HTML.
29
+ module Converter
30
+
31
+ # Converts a Kramdown::Document to HTML.
32
+ class Html
33
+
34
+ # Initialize the HTML converter with the given Kramdown document +doc+.
35
+ def initialize(doc)
36
+ @doc = doc
37
+ @footnote_counter = @footnote_start = @doc.options[:footnote_nr]
38
+ @footnotes = []
39
+ end
40
+ private_class_method(:new, :allocate)
41
+
42
+ # Convert the Kramdown document +doc+ to HTML.
43
+ def self.convert(doc)
44
+ new(doc).convert(doc.tree)
45
+ end
46
+
47
+ # Convert the element tree +el+, setting the indentation level to +indent+.
48
+ def convert(el, indent = -2)
49
+ result = ''
50
+ el.children.each do |inner_el|
51
+ result << convert(inner_el, indent + 2)
52
+ end
53
+ send("convert_#{el.type}", el, result, indent)
54
+ end
55
+
56
+ def convert_blank(el, inner, indent)
57
+ "\n"
58
+ end
59
+
60
+ def convert_text(el, inner, indent)
61
+ escape_html(el.value, false)
62
+ end
63
+
64
+ def convert_p(el, inner, indent)
65
+ "#{' '*indent}<p#{options_for_element(el)}>#{inner}</p>\n"
66
+ end
67
+
68
+ def convert_codeblock(el, inner, indent)
69
+ result = escape_html(el.value)
70
+ if el.options[:attr] && el.options[:attr].has_key?('class') && el.options[:attr]['class'] =~ /\bshow-whitespaces\b/
71
+ result.gsub!(/(?:(^[ \t]+)|([ \t]+$)|([ \t]+))/) do |m|
72
+ suffix = ($1 ? '-l' : ($2 ? '-r' : ''))
73
+ m.scan(/./).map do |c|
74
+ case c
75
+ when "\t" then "<span class=\"ws-tab#{suffix}\">\t</span>"
76
+ when " " then "<span class=\"ws-space#{suffix}\">&sdot;</span>"
77
+ end
78
+ end.join('')
79
+ end
80
+ end
81
+ "#{' '*indent}<pre#{options_for_element(el)}><code>#{result}#{result =~ /\n\Z/ ? '' : "\n"}</code></pre>\n"
82
+ end
83
+
84
+ def convert_blockquote(el, inner, indent)
85
+ "#{' '*indent}<blockquote#{options_for_element(el)}>\n#{inner}#{' '*indent}</blockquote>\n"
86
+ end
87
+
88
+ def convert_header(el, inner, indent)
89
+ "#{' '*indent}<h#{el.options[:level]}#{options_for_element(el)}>#{inner}</h#{el.options[:level]}>\n"
90
+ end
91
+
92
+ def convert_hr(el, inner, indent)
93
+ "#{' '*indent}<hr />\n"
94
+ end
95
+
96
+ def convert_ul(el, inner, indent)
97
+ "#{' '*indent}<#{el.type}#{options_for_element(el)}>\n#{inner}#{' '*indent}</#{el.type}>\n"
98
+ end
99
+ alias :convert_ol :convert_ul
100
+
101
+ def convert_li(el, inner, indent)
102
+ output = ' '*indent << "<li" << options_for_element(el) << ">"
103
+ if el.options[:first_as_block]
104
+ output << "\n" << inner << ' '*indent
105
+ else
106
+ output << inner << (inner =~ /\n\Z/ ? ' '*indent : '')
107
+ end
108
+ output << "</li>\n"
109
+ end
110
+
111
+ def convert_html_raw(el, inner, indent)
112
+ el.value + (el.options[:type] == :block ? "\n" : '')
113
+ end
114
+
115
+ HTML_TAGS_WITH_BODY=['div']
116
+
117
+ def convert_html_element(el, inner, indent)
118
+ if @doc.options[:filter_html].include?(el.value)
119
+ inner.chomp + (el.options[:type] == :block ? "\n" : '')
120
+ elsif el.options[:type] == :span
121
+ "<#{el.value}#{options_for_element(el)}" << (!inner.empty? ? ">#{inner}</#{el.value}>" : " />")
122
+ else
123
+ output = ' '*indent << "<#{el.value}#{options_for_element(el)}"
124
+ if !inner.empty?
125
+ output << ">\n#{inner.chomp}\n" << ' '*indent << "</#{el.value}>"
126
+ elsif HTML_TAGS_WITH_BODY.include?(el.value)
127
+ output << "></#{el.value}>"
128
+ else
129
+ output << " />"
130
+ end
131
+ output << "\n"
132
+ end
133
+ end
134
+
135
+ def convert_br(el, inner, indent)
136
+ "<br />"
137
+ end
138
+
139
+ def convert_a(el, inner, indent)
140
+ "<a#{options_for_element(el)}>#{inner}</a>"
141
+ end
142
+
143
+ def convert_img(el, inner, indent)
144
+ "<img#{options_for_element(el)} />"
145
+ end
146
+
147
+ def convert_codespan(el, inner, indent)
148
+ "<code#{options_for_element(el)}>#{escape_html(el.value)}</code>"
149
+ end
150
+
151
+ def convert_footnote(el, inner, indent)
152
+ number = @footnote_counter
153
+ @footnote_counter += 1
154
+ @footnotes << [el.options[:name], @doc.parse_infos[:footnotes][el.options[:name]]]
155
+ "<sup id=\"fnref:#{el.options[:name]}\"><a href=\"#fn:#{el.options[:name]}\" rel=\"footnote\">#{number}</a></sup>"
156
+ end
157
+
158
+ def convert_raw(el, inner, indent)
159
+ el.value
160
+ end
161
+
162
+ def convert_em(el, inner, indent)
163
+ "<#{el.type}#{options_for_element(el)}>#{inner}</#{el.type}>"
164
+ end
165
+ alias :convert_strong :convert_em
166
+
167
+ def convert_root(el, inner, indent)
168
+ inner << footnote_content
169
+ end
170
+
171
+
172
+ # Return a HTML list with the footnote content for the used footnotes.
173
+ def footnote_content
174
+ ol = Element.new(:ol)
175
+ ol.options[:attr] = {'start' => @footnote_start} if @footnote_start != 1
176
+ @footnotes.each do |name, data|
177
+ li = Element.new(:li, nil, {:attr => {:id => "fn:#{name}"}, :first_as_block => true})
178
+ li.children = Marshal.load(Marshal.dump(data[:content].children)) #TODO: probably remove this!!!!
179
+ ol.children << li
180
+
181
+ ref = Element.new(:raw, "<a href=\"#fnref:#{name}\" rev=\"footnote\">&#8617;</a>")
182
+ if li.children.last.type == :p
183
+ para = li.children.last
184
+ else
185
+ li.children << (para = Element.new(:p))
186
+ end
187
+ para.children << ref
188
+ end
189
+ (ol.children.empty? ? '' : "<div class=\"kramdown-footnotes\">\n#{convert(ol, 2)}</div>\n")
190
+ end
191
+
192
+ # Return the string with the attributes of the element +el+.
193
+ def options_for_element(el)
194
+ (el.options[:attr] || {}).map {|k,v| v.nil? ? '' : " #{k}=\"#{escape_html(v.to_s, false)}\"" }.sort.join('')
195
+ end
196
+
197
+ ESCAPE_MAP = {
198
+ '<' => '&lt;',
199
+ '>' => '&gt;',
200
+ '"' => '&quot;',
201
+ '&' => '&amp;'
202
+ }
203
+ ESCAPE_ALL_RE = Regexp.union(*ESCAPE_MAP.collect {|k,v| Regexp.escape(k)})
204
+ ESCAPE_ALL_NOT_ENTITIES_RE = Regexp.union(REXML::Parsers::BaseParser::REFERENCE_RE, ESCAPE_ALL_RE)
205
+
206
+ # Escape the special HTML characters in the string +str+. If +all+ is +true+ then all
207
+ # characters are escaped, if +all+ is +false+
208
+ def escape_html(str, all = true)
209
+ str.gsub(all ? ESCAPE_ALL_RE : ESCAPE_ALL_NOT_ENTITIES_RE) {|m| ESCAPE_MAP[m] || m}
210
+ end
211
+
212
+ end
213
+
214
+ end
215
+ end
@@ -0,0 +1,150 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown.
7
+ #
8
+ # kramdown is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #++
21
+ #
22
+
23
+ require 'kramdown/error'
24
+ require 'kramdown/parser'
25
+ require 'kramdown/converter'
26
+ require 'kramdown/extension'
27
+
28
+ module Kramdown
29
+
30
+ # The kramdown version.
31
+ VERSION = '0.1.0'
32
+
33
+ # The main interface to kramdown.
34
+ #
35
+ # This class provides a one-stop-shop for using kramdown to convert text into various output
36
+ # formats. Use it like this:
37
+ #
38
+ # require 'kramdown'
39
+ # doc = Kramdown::Document.new('This *is* some kramdown text')
40
+ # puts doc.to_html
41
+ #
42
+ # The #to_html method is a shortcut for using the Converter::ToHtml class. If other converters are
43
+ # added later, there may be additional shortcut methods.
44
+ #
45
+ # The second argument to the #new method is an options hash for customizing the behaviour of
46
+ # kramdown.
47
+ class Document
48
+
49
+ # Currently available options are:
50
+ #
51
+ # [:auto_ids (used by the parser)]
52
+ # A boolean value deciding whether automatic header ID generation is used. Default: +false+.
53
+ # When using the +kdoptions+ extension, the string 'false' will be the value +false+, every
54
+ # other non-empty string will be +true+.
55
+ # [:filter_html (used by the HTML converter)]
56
+ # An array of HTML tag names that defines which tags should be filtered from the output. For
57
+ # example, if the value contains +iframe+, then all HTML +iframe+ tags are filtered out and
58
+ # only the body is displayed. Default: empty array. When using the +kdoptions+ extension, the
59
+ # string value needs to hold the HTML tag names separated by one or more spaces.
60
+ # [:footnote_nr (used by the HTML converter)]
61
+ # The initial number used for creating the link to the first footnote. Default: +1+. When
62
+ # using the +kdoptions+ extension, the string value needs to be a valid number.
63
+ DEFAULT_OPTIONS={
64
+ :footnote_nr => 1,
65
+ :filter_html => [],
66
+ :auto_ids => false
67
+ }
68
+
69
+
70
+ # The element tree of the document. It is immediately available after the #new method has been
71
+ # called.
72
+ attr_accessor :tree
73
+
74
+ # The options hash which holds the options for parsing/converting the Kramdown document. It is
75
+ # possible that these values get changed during the parsing phase.
76
+ attr_accessor :options
77
+
78
+ # An array of warning messages. It is filled with warnings during the parsing phase (i.e. in
79
+ # #new) and the converting phase.
80
+ attr_reader :warnings
81
+
82
+ # Holds needed parse information like ALDs, link definitions and so on.
83
+ attr_reader :parse_infos
84
+
85
+ # Holds an instance of the extension class.
86
+ attr_reader :extension
87
+
88
+
89
+ # Create a new Kramdown document from the string +source+ and use the provided +options+ (see
90
+ # DEFAULT_OPTIONS for a list of available options). The +source+ is immediately parsed by the
91
+ # kramdown parser sothat after this call the output can be generated.
92
+ #
93
+ # The parameter +ext+ can be used to set a custom extension class. Note that the default
94
+ # kramdown extensions should be available in the custom extension class.
95
+ def initialize(source, options = {}, ext = nil)
96
+ @options = DEFAULT_OPTIONS.merge(options)
97
+ @warnings = []
98
+ @parse_infos = {}
99
+ @extension = extension || Kramdown::Extension.new
100
+ @tree = Parser::Kramdown.parse(source, self)
101
+ end
102
+
103
+ # Convert the document to HTML. Uses the Converter::ToHtml class for doing the conversion.
104
+ def to_html
105
+ Converter::Html.convert(self)
106
+ end
107
+
108
+ def inspect #:nodoc:
109
+ "<KD:Document: options=#{@options.inspect} tree=#{@tree.inspect} warnings=#{@warnings.inspect}>"
110
+ end
111
+
112
+ end
113
+
114
+
115
+ # Represents all elements in the parse tree.
116
+ #
117
+ # kramdown only uses this one class for representing all available elements in a parse tree
118
+ # (paragraphs, headers, emphasis, ...). The type of element can be set via the #type accessor.
119
+ class Element
120
+
121
+ # A symbol representing the element type. For example, +:p+ or +:blockquote+.
122
+ attr_accessor :type
123
+
124
+ # The value of the element. The interpretation of this field depends on the type of the element.
125
+ # Many elements don't use this field.
126
+ attr_accessor :value
127
+
128
+ # The options hash for the element. It is used for storing arbitray options as well as the
129
+ # *attributes* of the element under the <tt>:attr</tt> key.
130
+ attr_accessor :options
131
+
132
+ # The child elements of this element.
133
+ attr_accessor :children
134
+
135
+
136
+ # Create a new Element object of type +type+. The optional parameters +value+ and +options+ can
137
+ # also be set in this constructor for convenience.
138
+ def initialize(type, value = nil, options = {})
139
+ @type, @value, @options = type, value, options
140
+ @children = []
141
+ end
142
+
143
+ def inspect #:nodoc:
144
+ "<kd:#{@type}#{@value.nil? ? '' : ' ' + @value.inspect}#{options.empty? ? '' : ' ' + @options.inspect}#{@children.empty? ? '' : ' ' + @children.inspect}>"
145
+ end
146
+
147
+ end
148
+
149
+ end
150
+
@@ -0,0 +1,27 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown.
7
+ #
8
+ # kramdown is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #++
21
+ #
22
+
23
+ module Kramdown
24
+
25
+ class Error < RuntimeError; end
26
+
27
+ end