greenmat 3.2.0.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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +14 -0
  3. data/Gemfile +9 -0
  4. data/README.md +36 -0
  5. data/Rakefile +62 -0
  6. data/bin/greenmat +7 -0
  7. data/ext/greenmat/autolink.c +296 -0
  8. data/ext/greenmat/autolink.h +49 -0
  9. data/ext/greenmat/buffer.c +196 -0
  10. data/ext/greenmat/buffer.h +83 -0
  11. data/ext/greenmat/extconf.rb +6 -0
  12. data/ext/greenmat/gm_markdown.c +161 -0
  13. data/ext/greenmat/gm_render.c +534 -0
  14. data/ext/greenmat/greenmat.h +30 -0
  15. data/ext/greenmat/houdini.h +29 -0
  16. data/ext/greenmat/houdini_href_e.c +108 -0
  17. data/ext/greenmat/houdini_html_e.c +83 -0
  18. data/ext/greenmat/html.c +826 -0
  19. data/ext/greenmat/html.h +84 -0
  20. data/ext/greenmat/html_blocks.h +229 -0
  21. data/ext/greenmat/html_smartypants.c +445 -0
  22. data/ext/greenmat/markdown.c +2912 -0
  23. data/ext/greenmat/markdown.h +138 -0
  24. data/ext/greenmat/stack.c +62 -0
  25. data/ext/greenmat/stack.h +26 -0
  26. data/greenmat.gemspec +72 -0
  27. data/lib/greenmat.rb +92 -0
  28. data/lib/greenmat/compat.rb +73 -0
  29. data/lib/greenmat/render_man.rb +65 -0
  30. data/lib/greenmat/render_strip.rb +48 -0
  31. data/test/benchmark.rb +24 -0
  32. data/test/custom_render_test.rb +28 -0
  33. data/test/greenmat_compat_test.rb +38 -0
  34. data/test/html5_test.rb +69 -0
  35. data/test/html_render_test.rb +241 -0
  36. data/test/html_toc_render_test.rb +76 -0
  37. data/test/markdown_test.rb +337 -0
  38. data/test/pathological_inputs_test.rb +34 -0
  39. data/test/safe_render_test.rb +36 -0
  40. data/test/smarty_html_test.rb +45 -0
  41. data/test/smarty_pants_test.rb +48 -0
  42. data/test/stripdown_render_test.rb +40 -0
  43. data/test/test_helper.rb +33 -0
  44. metadata +158 -0
@@ -0,0 +1,65 @@
1
+ module Greenmat
2
+ module Render
3
+ class ManPage < Base
4
+
5
+ def normal_text(text)
6
+ text.gsub('-', '\\-').strip
7
+ end
8
+
9
+ def block_code(code, language)
10
+ "\n.nf\n#{normal_text(code)}\n.fi\n"
11
+ end
12
+
13
+ def codespan(code)
14
+ block_code(code, nil)
15
+ end
16
+
17
+ def header(title, level)
18
+ case level
19
+ when 1
20
+ "\n.TH #{title}\n"
21
+
22
+ when 2
23
+ "\n.SH #{title}\n"
24
+
25
+ when 3
26
+ "\n.SS #{title}\n"
27
+ end
28
+ end
29
+
30
+ def double_emphasis(text)
31
+ "\\fB#{text}\\fP"
32
+ end
33
+
34
+ def emphasis(text)
35
+ "\\fI#{text}\\fP"
36
+ end
37
+
38
+ def linebreak
39
+ "\n.LP\n"
40
+ end
41
+
42
+ def paragraph(text)
43
+ "\n.TP\n#{text}\n"
44
+ end
45
+
46
+ def list(content, list_type)
47
+ case list_type
48
+ when :ordered
49
+ "\n\n.nr step 0 1\n#{content}\n"
50
+ when :unordered
51
+ "\n.\n#{content}\n"
52
+ end
53
+ end
54
+
55
+ def list_item(content, list_type)
56
+ case list_type
57
+ when :ordered
58
+ ".IP \\n+[step]\n#{content.strip}\n"
59
+ when :unordered
60
+ ".IP \\[bu] 2 \n#{content.strip}\n"
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,48 @@
1
+ module Greenmat
2
+ module Render
3
+ # Markdown-stripping renderer. Turns Markdown into plaintext
4
+ # Thanks to @toupeira (Markus Koller)
5
+ class StripDown < Base
6
+ # Methods where the first argument is the text content
7
+ [
8
+ # block-level calls
9
+ :block_code, :block_quote,
10
+ :block_html, :list, :list_item,
11
+
12
+ # span-level calls
13
+ :autolink, :codespan, :double_emphasis,
14
+ :emphasis, :underline, :raw_html,
15
+ :triple_emphasis, :strikethrough,
16
+ :superscript,
17
+
18
+ # footnotes
19
+ :footnotes, :footnote_def, :footnote_ref,
20
+
21
+ # low level rendering
22
+ :entity, :normal_text
23
+ ].each do |method|
24
+ define_method method do |*args|
25
+ args.first
26
+ end
27
+ end
28
+
29
+ # Other methods where we don't return only a specific argument
30
+ def link(link, title, content)
31
+ "#{content} (#{link})"
32
+ end
33
+
34
+ def image(link, title, content)
35
+ content &&= content + " "
36
+ "#{content}#{link}"
37
+ end
38
+
39
+ def paragraph(text)
40
+ text + "\n"
41
+ end
42
+
43
+ def header(text, header_level)
44
+ text + "\n"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ # coding: UTF-8
2
+ # Thanks Kramdown for the inspiration!
3
+ require 'benchmark/ips'
4
+
5
+ require 'greenmat'
6
+ require 'bluecloth'
7
+ require 'kramdown'
8
+
9
+ markdown = File.read(File.join(File.dirname(__FILE__), "fixtures/benchmark.md"))
10
+
11
+ # Let's bench!
12
+ Benchmark.ips do |bench|
13
+ bench.report("Greenmat") do
14
+ Greenmat::Markdown.new(Greenmat::Render::HTML).render(markdown)
15
+ end
16
+
17
+ bench.report("BlueCloth") do
18
+ BlueCloth.new(markdown).to_html
19
+ end
20
+
21
+ bench.report("Kramdown") do
22
+ Kramdown::Document.new(markdown).to_html
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ # coding: UTF-8
2
+ require 'test_helper'
3
+
4
+ class CustomRenderTest < Greenmat::TestCase
5
+ class SimpleRender < Greenmat::Render::HTML
6
+ def emphasis(text)
7
+ "<em class=\"cool\">#{text}</em>"
8
+ end
9
+ end
10
+
11
+ def test_simple_overload
12
+ md = Greenmat::Markdown.new(SimpleRender)
13
+ assert_equal "<p>This is <em class=\"cool\">just</em> a test</p>\n",
14
+ md.render("This is *just* a test")
15
+ end
16
+
17
+ class NilPreprocessRenderer < Greenmat::Render::HTML
18
+ def preprocess(fulldoc)
19
+ nil
20
+ end
21
+ end
22
+
23
+ def test_preprocess_returning_nil
24
+ md = Greenmat::Markdown.new(NilPreprocessRenderer)
25
+ assert_equal(nil,md.render("Anything"))
26
+ end
27
+
28
+ end
@@ -0,0 +1,38 @@
1
+ # coding: UTF-8
2
+ require 'test_helper'
3
+
4
+ class GreenmatCompatTest < Greenmat::TestCase
5
+ def test_simple_compat_api
6
+ html = GreenmatCompat.new("This is_just_a test").to_html
7
+ assert_equal "<p>This is<em>just</em>a test</p>\n", html
8
+ end
9
+
10
+ def test_compat_api_enables_extensions
11
+ html = GreenmatCompat.new("This is_just_a test", :no_intra_emphasis).to_html
12
+ assert_equal "<p>This is_just_a test</p>\n", html
13
+ end
14
+
15
+ def test_compat_api_knows_fenced_code_extension
16
+ text = "```ruby\nx = 'foo'\n```"
17
+ html = GreenmatCompat.new(text, :fenced_code).to_html
18
+ assert_equal "<pre><code class=\"ruby\">x = &#39;foo&#39;\n</code></pre>\n", html
19
+ end
20
+
21
+ def test_compat_api_ignores_gh_blockcode_extension
22
+ text = "```ruby\nx = 'foo'\n```"
23
+ html = GreenmatCompat.new(text, :fenced_code, :gh_blockcode).to_html
24
+ assert_equal "<pre><code class=\"ruby\">x = &#39;foo&#39;\n</code></pre>\n", html
25
+ end
26
+
27
+ def test_compat_api_knows_no_intraemphasis_extension
28
+ html = GreenmatCompat.new("This is_just_a test", :no_intraemphasis).to_html
29
+ assert_equal "<p>This is_just_a test</p>\n", html
30
+ end
31
+
32
+ def test_translate_outdated_extensions
33
+ # these extensions are no longer used
34
+ exts = [:gh_blockcode, :no_tables, :smart, :strict]
35
+ html = GreenmatCompat.new('"TEST"', *exts).to_html
36
+ assert_equal "<p>&quot;TEST&quot;</p>\n", html
37
+ end
38
+ end
@@ -0,0 +1,69 @@
1
+ require 'test_helper'
2
+
3
+ class HTML5Test < Greenmat::TestCase
4
+ def test_that_html5_works
5
+ section = <<EOS
6
+ <section>
7
+ <p>The quick brown fox jumps over the lazy dog.</p>
8
+ </section>
9
+ EOS
10
+
11
+ figure = <<EOS
12
+ <figure>
13
+ <img src="http://example.org/image.jpg" alt="">
14
+ <figcaption>
15
+ <p>Hello world!</p>
16
+ </figcaption>
17
+ </figure>
18
+ EOS
19
+
20
+ assert_renders section, section
21
+ assert_renders figure, figure
22
+ end
23
+
24
+ def test_that_html5_works_with_code_blocks
25
+ section = <<EOS
26
+ \t<section>
27
+ \t\t<p>The quick brown fox jumps over the lazy dog.</p>
28
+ \t</section>
29
+ EOS
30
+
31
+ section_expected = <<EOE
32
+ <pre><code>&lt;section&gt;
33
+ &lt;p&gt;The quick brown fox jumps over the lazy dog.&lt;/p&gt;
34
+ &lt;/section&gt;
35
+ </code></pre>
36
+ EOE
37
+
38
+ header = <<EOS
39
+ <header>
40
+ <hgroup>
41
+ <h1>Section heading</h1>
42
+ <h2>Subhead</h2>
43
+ </hgroup>
44
+ </header>
45
+ EOS
46
+
47
+ header_expected = <<EOE
48
+ <pre><code>&lt;header&gt;
49
+ &lt;hgroup&gt;
50
+ &lt;h1&gt;Section heading&lt;/h1&gt;
51
+ &lt;h2&gt;Subhead&lt;/h2&gt;
52
+ &lt;/hgroup&gt;
53
+ &lt;/header&gt;
54
+ </code></pre>
55
+ EOE
56
+
57
+ assert_renders section_expected, section
58
+ assert_renders header_expected, header
59
+ end
60
+
61
+ def test_script_tag_recognition
62
+ markdown = <<-Md
63
+ <script type="text/javascript">
64
+ alert('Foo!');
65
+ </script>
66
+ Md
67
+ assert_renders markdown, markdown
68
+ end
69
+ end
@@ -0,0 +1,241 @@
1
+ # coding: UTF-8
2
+ require 'test_helper'
3
+
4
+ class HTMLRenderTest < Greenmat::TestCase
5
+ def setup
6
+ @renderer = Greenmat::Render::HTML
7
+ end
8
+
9
+ # Hint: overrides filter_html, no_images and no_links
10
+ def test_that_escape_html_works
11
+ source = <<EOS
12
+ Through <em>NO</em> <script>DOUBLE NO</script>
13
+
14
+ <script>BAD</script>
15
+
16
+ <img src="/favicon.ico" />
17
+ EOS
18
+ expected = <<EOE
19
+ <p>Through &lt;em&gt;NO&lt;/em&gt; &lt;script&gt;DOUBLE NO&lt;/script&gt;</p>
20
+
21
+ <p>&lt;script&gt;BAD&lt;/script&gt;</p>
22
+
23
+ <p>&lt;img src=&quot;/favicon.ico&quot; /&gt;</p>
24
+ EOE
25
+
26
+ assert_equal expected, render(source, with: [:escape_html])
27
+ end
28
+
29
+ def test_that_filter_html_works
30
+ markdown = 'Through <em>NO</em> <script>DOUBLE NO</script>'
31
+ output = render(markdown, with: [:filter_html])
32
+
33
+ assert_equal "<p>Through NO DOUBLE NO</p>\n", output
34
+ end
35
+
36
+ def test_filter_html_doesnt_break_two_space_hard_break
37
+ markdown = "Lorem, \nipsum\n"
38
+ output = render(markdown, with: [:filter_html])
39
+
40
+ assert_equal "<p>Lorem,<br>\nipsum</p>\n", output
41
+ end
42
+
43
+ def test_that_no_image_flag_works
44
+ markdown = %(![dust mite](http://dust.mite/image.png) <img src="image.png" />)
45
+ output = render(markdown, with: [:no_images])
46
+
47
+ assert_no_match %r{<img}, output
48
+ end
49
+
50
+ def test_that_no_links_flag_works
51
+ markdown = %([This link](http://example.net/) <a href="links.html">links</a>)
52
+ output = render(markdown, with: [:no_links])
53
+
54
+ assert_no_match %r{<a }, output
55
+ end
56
+
57
+ def test_that_safelink_flag_works
58
+ markdown = "[IRC](irc://chat.freenode.org/#freenode)"
59
+ output = render(markdown, with: [:safe_links_only])
60
+
61
+ assert_equal "<p>[IRC](irc://chat.freenode.org/#freenode)</p>\n", output
62
+ end
63
+
64
+ def test_that_hard_wrap_works
65
+ markdown = <<EOE
66
+ Hello world,
67
+ this is just a simple test
68
+
69
+ With hard wraps
70
+ and other *things*.
71
+ EOE
72
+ output = render(markdown, with: [:hard_wrap])
73
+
74
+ assert_match %r{<br>}, output
75
+ end
76
+
77
+ def test_that_link_attributes_work
78
+ rndr = Greenmat::Render::HTML.new(:link_attributes => {:rel => 'blank'})
79
+ md = Greenmat::Markdown.new(rndr)
80
+ assert md.render('This is a [simple](http://test.com) test.').include?('rel="blank"')
81
+ end
82
+
83
+ def test_that_link_works_with_quotes
84
+ markdown = %([This'link"is](http://example.net/))
85
+ expected = %(<p><a href="http://example.net/">This&#39;link&quot;is</a></p>\n)
86
+
87
+ assert_equal expected, render(markdown)
88
+ assert_equal expected, render(markdown, with: [:escape_html])
89
+ end
90
+
91
+ def test_that_code_emphasis_work
92
+ markdown = <<-MD
93
+ This should be **`a bold codespan`**
94
+ However, this should be *`an emphasised codespan`*
95
+
96
+ * **`ABC`** or **`DEF`**
97
+ * Foo bar
98
+ MD
99
+
100
+ html = <<HTML
101
+ <p>This should be <strong><code>a bold codespan</code></strong>
102
+ However, this should be <em><code>an emphasised codespan</code></em></p>
103
+
104
+ <ul>
105
+ <li><strong><code>ABC</code></strong> or <strong><code>DEF</code></strong></li>
106
+ <li>Foo bar</li>
107
+ </ul>
108
+ HTML
109
+
110
+ assert_equal html, render(markdown)
111
+ end
112
+
113
+ def test_that_parenthesis_are_handled_into_links
114
+ markdown = %(The [bash man page](man:bash(1))!)
115
+ expected = %(<p>The <a href="man:bash(1)">bash man page</a>!</p>\n)
116
+
117
+ assert_equal expected, render(markdown)
118
+ end
119
+
120
+ def test_autolinking_works_as_expected
121
+ markdown = "Uri ftp://user:pass@example.com/. Email foo@bar.com and link http://bar.com"
122
+ output = render(markdown, with: [:autolink])
123
+
124
+ assert output.include? '<a href="ftp://user:pass@example.com/">ftp://user:pass@example.com/</a>'
125
+ assert output.include? 'mailto:foo@bar.com'
126
+ assert output.include? '<a href="http://bar.com">'
127
+ end
128
+
129
+ def test_that_footnotes_work
130
+ markdown = <<-MD
131
+ This is a footnote.[^1]
132
+
133
+ [^1]: It provides additional information.
134
+ MD
135
+
136
+ html = <<HTML
137
+ <p>This is a footnote.<sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup></p>
138
+
139
+ <div class="footnotes">
140
+ <hr>
141
+ <ol>
142
+
143
+ <li id="fn1">
144
+ <p>It provides additional information.&nbsp;<a href="#fnref1" rev="footnote">&#8617;</a></p>
145
+ </li>
146
+
147
+ </ol>
148
+ </div>
149
+ HTML
150
+
151
+ output = render(markdown, with: [:footnotes])
152
+ assert_equal html, output
153
+ end
154
+
155
+ def test_footnotes_enabled_but_missing_marker
156
+ markdown = <<MD
157
+ Some text without a marker
158
+
159
+ [^1] And a trailing definition
160
+ MD
161
+ html = <<HTML
162
+ <p>Some text without a marker</p>
163
+
164
+ <p>[^1] And a trailing definition</p>
165
+ HTML
166
+
167
+ output = render(markdown, with: [:footnotes])
168
+ assert_equal html, output
169
+ end
170
+
171
+ def test_footnotes_enabled_but_missing_definition
172
+ markdown = "Some text with a marker[^1] but no definition."
173
+ expected = "<p>Some text with a marker[^1] but no definition.</p>\n"
174
+
175
+ output = render(markdown, with: [:footnotes])
176
+ assert_equal expected, output
177
+ end
178
+
179
+ def test_autolink_short_domains
180
+ markdown = "Example of uri ftp://auto/short/domains. Email auto@l.n and link http://a/u/t/o/s/h/o/r/t"
181
+ output = render(markdown, with: [:autolink])
182
+
183
+ assert output.include? '<a href="ftp://auto/short/domains">ftp://auto/short/domains</a>'
184
+ assert output.include? 'mailto:auto@l.n'
185
+ assert output.include? '<a href="http://a/u/t/o/s/h/o/r/t">http://a/u/t/o/s/h/o/r/t</a>'
186
+ end
187
+
188
+ def test_that_prettify_works
189
+ markdown = "\tclass Foo\nend"
190
+ output = render(markdown, with: [:prettify])
191
+
192
+ assert output.include?("<pre><code class=\"prettyprint\">")
193
+
194
+ markdown = "`class`"
195
+ output = render(markdown, with: [:prettify])
196
+
197
+ assert output.include?("<code class=\"prettyprint\">")
198
+ end
199
+
200
+ def test_prettify_with_fenced_code_blocks
201
+ markdown = "~~~ruby\ncode\n~~~"
202
+ output = render(markdown, with: [:fenced_code_blocks, :prettify])
203
+
204
+ assert output.include?("<code class=\"prettyprint lang-ruby\">")
205
+ end
206
+
207
+ def test_safe_links_only_with_anchors
208
+ markdown = "An [anchor link](#anchor) on a page."
209
+ output = render(markdown, with: [:safe_links_only])
210
+
211
+ assert_match %r{<a href="#anchor">anchor link</a>}, output
212
+ end
213
+
214
+ def test_autolink_with_link_attributes
215
+ options = { autolink: true, link_attributes: {rel: "nofollow"} }
216
+ output = render("https://github.com/", with: options)
217
+
218
+ assert_match %r{rel="nofollow"}, output
219
+ end
220
+
221
+ def test_image_unsafe_src_with_safe_links_only
222
+ markdown = "![foo](javascript:while(1);)"
223
+ output = render(markdown, with: [:safe_links_only])
224
+
225
+ assert_not_match %r{img src}, output
226
+ end
227
+
228
+ def test_no_styles_option_inside_a_paragraph
229
+ markdown = "Hello <style> foo { bar: baz; } </style> !"
230
+ output = render(markdown, with: [:no_styles])
231
+
232
+ assert_no_match %r{<style>}, output
233
+ end
234
+
235
+ def test_no_styles_inside_html_block_rendering
236
+ markdown = "<style> foo { bar: baz; } </style>"
237
+ output = render(markdown, with: [:no_styles])
238
+
239
+ assert_no_match %r{<style>}, output
240
+ end
241
+ end