redcarpet 3.3.4 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of redcarpet might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.markdown +21 -11
- data/ext/redcarpet/autolink.c +7 -0
- data/ext/redcarpet/houdini_href_e.c +5 -11
- data/ext/redcarpet/html.c +18 -1
- data/ext/redcarpet/html_blocks.h +68 -70
- data/ext/redcarpet/html_smartypants.c +3 -3
- data/ext/redcarpet/markdown.c +5 -7
- data/ext/redcarpet/rc_markdown.c +7 -1
- data/ext/redcarpet/rc_render.c +9 -0
- data/lib/redcarpet.rb +1 -1
- data/lib/redcarpet/cli.rb +1 -1
- data/redcarpet.gemspec +3 -2
- data/test/custom_render_test.rb +30 -1
- data/test/html5_test.rb +51 -38
- data/test/html_render_test.rb +80 -60
- data/test/html_toc_render_test.rb +11 -4
- data/test/markdown_test.rb +216 -181
- data/test/redcarpet_bin_test.rb +2 -2
- data/test/smarty_html_test.rb +5 -5
- data/test/smarty_pants_test.rb +5 -0
- data/test/stripdown_render_test.rb +6 -6
- data/test/test_helper.rb +9 -1
- metadata +17 -3
data/ext/redcarpet/rc_markdown.c
CHANGED
@@ -86,7 +86,7 @@ rb_redcarpet_md__free(void *markdown)
|
|
86
86
|
|
87
87
|
static VALUE rb_redcarpet_md__new(int argc, VALUE *argv, VALUE klass)
|
88
88
|
{
|
89
|
-
VALUE rb_markdown, rb_rndr, hash;
|
89
|
+
VALUE rb_markdown, rb_rndr, hash, rndr_options;
|
90
90
|
unsigned int extensions = 0;
|
91
91
|
|
92
92
|
struct rb_redcarpet_rndr *rndr;
|
@@ -103,6 +103,12 @@ static VALUE rb_redcarpet_md__new(int argc, VALUE *argv, VALUE klass)
|
|
103
103
|
|
104
104
|
Data_Get_Struct(rb_rndr, struct rb_redcarpet_rndr, rndr);
|
105
105
|
|
106
|
+
/* Merge the current options in the @options hash */
|
107
|
+
if (hash != Qnil) {
|
108
|
+
rndr_options = rb_iv_get(rb_rndr, "@options");
|
109
|
+
rb_funcall(rndr_options, rb_intern("merge!"), 1, hash);
|
110
|
+
}
|
111
|
+
|
106
112
|
markdown = sd_markdown_new(extensions, 16, &rndr->callbacks, &rndr->options);
|
107
113
|
if (!markdown)
|
108
114
|
rb_raise(rb_eRuntimeError, "Failed to create new Renderer class");
|
data/ext/redcarpet/rc_render.c
CHANGED
@@ -410,6 +410,9 @@ static void rb_redcarpet__overload(VALUE self, VALUE base_class)
|
|
410
410
|
dest[i] = source[i];
|
411
411
|
}
|
412
412
|
}
|
413
|
+
|
414
|
+
if (rb_iv_get(self, "@options") == Qnil)
|
415
|
+
rb_iv_set(self, "@options", rb_hash_new());
|
413
416
|
}
|
414
417
|
|
415
418
|
static VALUE rb_redcarpet_rbase_init(VALUE self)
|
@@ -429,6 +432,9 @@ static VALUE rb_redcarpet_html_init(int argc, VALUE *argv, VALUE self)
|
|
429
432
|
if (rb_scan_args(argc, argv, "01", &hash) == 1) {
|
430
433
|
Check_Type(hash, T_HASH);
|
431
434
|
|
435
|
+
/* Give access to the passed options through `@options` */
|
436
|
+
rb_iv_set(self, "@options", hash);
|
437
|
+
|
432
438
|
/* escape_html */
|
433
439
|
if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue)
|
434
440
|
render_flags |= HTML_ESCAPE;
|
@@ -491,6 +497,9 @@ static VALUE rb_redcarpet_htmltoc_init(int argc, VALUE *argv, VALUE self)
|
|
491
497
|
if (rb_scan_args(argc, argv, "01", &hash) == 1) {
|
492
498
|
Check_Type(hash, T_HASH);
|
493
499
|
|
500
|
+
/* Give access to the passed options through `@options` */
|
501
|
+
rb_iv_set(self, "@options", hash);
|
502
|
+
|
494
503
|
/* escape_html */
|
495
504
|
if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue)
|
496
505
|
render_flags |= HTML_ESCAPE;
|
data/lib/redcarpet.rb
CHANGED
data/lib/redcarpet/cli.rb
CHANGED
data/redcarpet.gemspec
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
Gem::Specification.new do |s|
|
3
3
|
s.name = 'redcarpet'
|
4
|
-
s.version = '3.
|
4
|
+
s.version = '3.4.0'
|
5
5
|
s.summary = "Markdown that smells nice"
|
6
6
|
s.description = 'A fast, safe and extensible Markdown to (X)HTML parser'
|
7
|
-
s.date = '
|
7
|
+
s.date = '2016-12-25'
|
8
8
|
s.email = 'vicent@github.com'
|
9
9
|
s.homepage = 'http://github.com/vmg/redcarpet'
|
10
10
|
s.authors = ["Natacha Porté", "Vicent Martí"]
|
@@ -65,6 +65,7 @@ Gem::Specification.new do |s|
|
|
65
65
|
s.executables = ["redcarpet"]
|
66
66
|
s.require_paths = ["lib"]
|
67
67
|
|
68
|
+
s.add_development_dependency "rake", "~> 10.5"
|
68
69
|
s.add_development_dependency "rake-compiler", "~> 0.9.5"
|
69
70
|
s.add_development_dependency "test-unit", "~> 3.1.3"
|
70
71
|
end
|
data/test/custom_render_test.rb
CHANGED
@@ -4,7 +4,15 @@ require 'test_helper'
|
|
4
4
|
class CustomRenderTest < Redcarpet::TestCase
|
5
5
|
class SimpleRender < Redcarpet::Render::HTML
|
6
6
|
def emphasis(text)
|
7
|
-
|
7
|
+
if @options[:no_intra_emphasis]
|
8
|
+
return %(<em class="no_intra_emphasis">#{text}</em>)
|
9
|
+
end
|
10
|
+
|
11
|
+
%(<em class="cool">#{text}</em>)
|
12
|
+
end
|
13
|
+
|
14
|
+
def header(text, level)
|
15
|
+
"My little poney" if @options[:with_toc_data]
|
8
16
|
end
|
9
17
|
end
|
10
18
|
|
@@ -14,6 +22,20 @@ class CustomRenderTest < Redcarpet::TestCase
|
|
14
22
|
md.render("This is *just* a test")
|
15
23
|
end
|
16
24
|
|
25
|
+
def test_renderer_options
|
26
|
+
parser = Redcarpet::Markdown.new(SimpleRender.new(with_toc_data: true))
|
27
|
+
output = parser.render("# A title")
|
28
|
+
|
29
|
+
assert_match "My little poney", output
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_markdown_options
|
33
|
+
parser = Redcarpet::Markdown.new(SimpleRender, no_intra_emphasis: true)
|
34
|
+
output = parser.render("*foo*")
|
35
|
+
|
36
|
+
assert_match "no_intra_emphasis", output
|
37
|
+
end
|
38
|
+
|
17
39
|
class NilPreprocessRenderer < Redcarpet::Render::HTML
|
18
40
|
def preprocess(fulldoc)
|
19
41
|
nil
|
@@ -25,4 +47,11 @@ class CustomRenderTest < Redcarpet::TestCase
|
|
25
47
|
assert_equal(nil,md.render("Anything"))
|
26
48
|
end
|
27
49
|
|
50
|
+
def test_base_render_without_quote_callback
|
51
|
+
# Regression test for https://github.com/vmg/redcarpet/issues/569
|
52
|
+
render = Class.new(Redcarpet::Render::Base)
|
53
|
+
parser = Redcarpet::Markdown.new render.new, quote: true
|
54
|
+
|
55
|
+
assert_equal "", parser.render(%(a "quote"))
|
56
|
+
end
|
28
57
|
end
|
data/test/html5_test.rb
CHANGED
@@ -2,68 +2,81 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
class HTML5Test < Redcarpet::TestCase
|
4
4
|
def test_that_html5_works
|
5
|
-
section =
|
6
|
-
<section>
|
7
|
-
|
8
|
-
</section>
|
9
|
-
|
5
|
+
section = <<-HTML.chomp.strip_heredoc
|
6
|
+
<section>
|
7
|
+
<p>The quick brown fox jumps over the lazy dog.</p>
|
8
|
+
</section>
|
9
|
+
HTML
|
10
10
|
|
11
|
-
figure =
|
12
|
-
<figure>
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
</figure>
|
18
|
-
|
11
|
+
figure = <<-HTML.chomp.strip_heredoc
|
12
|
+
<figure>
|
13
|
+
<img src="http://example.org/image.jpg" alt="">
|
14
|
+
<figcaption>
|
15
|
+
<p>Hello world!</p>
|
16
|
+
</figcaption>
|
17
|
+
</figure>
|
18
|
+
HTML
|
19
19
|
|
20
20
|
assert_renders section, section
|
21
21
|
assert_renders figure, figure
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_that_html5_works_with_code_blocks
|
25
|
-
section =
|
25
|
+
section = <<-HTML
|
26
26
|
\t<section>
|
27
27
|
\t\t<p>The quick brown fox jumps over the lazy dog.</p>
|
28
28
|
\t</section>
|
29
|
-
|
29
|
+
HTML
|
30
30
|
|
31
|
-
section_expected =
|
32
|
-
<pre><code><section>
|
33
|
-
|
34
|
-
</section>
|
35
|
-
</code></pre>
|
36
|
-
|
31
|
+
section_expected = <<-HTML.chomp.strip_heredoc
|
32
|
+
<pre><code><section>
|
33
|
+
<p>The quick brown fox jumps over the lazy dog.</p>
|
34
|
+
</section>
|
35
|
+
</code></pre>
|
36
|
+
HTML
|
37
37
|
|
38
|
-
header =
|
38
|
+
header = <<-HTML
|
39
39
|
<header>
|
40
40
|
<hgroup>
|
41
41
|
<h1>Section heading</h1>
|
42
42
|
<h2>Subhead</h2>
|
43
43
|
</hgroup>
|
44
44
|
</header>
|
45
|
-
|
45
|
+
HTML
|
46
46
|
|
47
|
-
header_expected =
|
48
|
-
<pre><code><header>
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
</header>
|
54
|
-
</code></pre>
|
55
|
-
|
47
|
+
header_expected = <<-HTML.chomp.strip_heredoc
|
48
|
+
<pre><code><header>
|
49
|
+
<hgroup>
|
50
|
+
<h1>Section heading</h1>
|
51
|
+
<h2>Subhead</h2>
|
52
|
+
</hgroup>
|
53
|
+
</header>
|
54
|
+
</code></pre>
|
55
|
+
HTML
|
56
56
|
|
57
57
|
assert_renders section_expected, section
|
58
58
|
assert_renders header_expected, header
|
59
59
|
end
|
60
60
|
|
61
61
|
def test_script_tag_recognition
|
62
|
-
|
63
|
-
<script type="text/javascript">
|
64
|
-
|
65
|
-
</script>
|
66
|
-
|
67
|
-
|
62
|
+
html = <<-HTML.chomp.strip_heredoc
|
63
|
+
<script type="text/javascript">
|
64
|
+
alert('Foo!');
|
65
|
+
</script>
|
66
|
+
HTML
|
67
|
+
|
68
|
+
assert_renders html, html
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_new_html5_tags_not_escaped
|
72
|
+
details = <<-HTML.chomp.strip_heredoc
|
73
|
+
<details>
|
74
|
+
log:
|
75
|
+
|
76
|
+
</details>
|
77
|
+
HTML
|
78
|
+
|
79
|
+
assert_renders details, details
|
68
80
|
end
|
81
|
+
|
69
82
|
end
|
data/test/html_render_test.rb
CHANGED
@@ -8,20 +8,20 @@ class HTMLRenderTest < Redcarpet::TestCase
|
|
8
8
|
|
9
9
|
# Hint: overrides filter_html, no_images and no_links
|
10
10
|
def test_that_escape_html_works
|
11
|
-
source =
|
12
|
-
Through <em>NO</em> <script>DOUBLE NO</script>
|
11
|
+
source = <<-HTML.strip_heredoc
|
12
|
+
Through <em>NO</em> <script>DOUBLE NO</script>
|
13
13
|
|
14
|
-
<script>BAD</script>
|
14
|
+
<script>BAD</script>
|
15
15
|
|
16
|
-
<img src="/favicon.ico" />
|
17
|
-
|
18
|
-
expected =
|
19
|
-
<p>Through <em>NO</em> <script>DOUBLE NO</script></p>
|
16
|
+
<img src="/favicon.ico" />
|
17
|
+
HTML
|
18
|
+
expected = <<-HTML.chomp.strip_heredoc
|
19
|
+
<p>Through <em>NO</em> <script>DOUBLE NO</script></p>
|
20
20
|
|
21
|
-
<p><script>BAD</script></p>
|
21
|
+
<p><script>BAD</script></p>
|
22
22
|
|
23
|
-
<p><img src="/favicon.ico" /></p>
|
24
|
-
|
23
|
+
<p><img src="/favicon.ico" /></p>
|
24
|
+
HTML
|
25
25
|
|
26
26
|
assert_equal expected, render(source, with: [:escape_html])
|
27
27
|
end
|
@@ -30,14 +30,14 @@ EOE
|
|
30
30
|
markdown = 'Through <em>NO</em> <script>DOUBLE NO</script>'
|
31
31
|
output = render(markdown, with: [:filter_html])
|
32
32
|
|
33
|
-
assert_equal "<p>Through NO DOUBLE NO</p
|
33
|
+
assert_equal "<p>Through NO DOUBLE NO</p>", output
|
34
34
|
end
|
35
35
|
|
36
36
|
def test_filter_html_doesnt_break_two_space_hard_break
|
37
37
|
markdown = "Lorem, \nipsum\n"
|
38
38
|
output = render(markdown, with: [:filter_html])
|
39
39
|
|
40
|
-
assert_equal "<p>Lorem,<br>\nipsum</p
|
40
|
+
assert_equal "<p>Lorem,<br>\nipsum</p>", output
|
41
41
|
end
|
42
42
|
|
43
43
|
def test_that_no_image_flag_works
|
@@ -47,6 +47,12 @@ EOE
|
|
47
47
|
assert_no_match %r{<img}, output
|
48
48
|
end
|
49
49
|
|
50
|
+
def test_that_links_with_ampersands_work
|
51
|
+
markdown = %([/?a=b&c=d](/?a=b&c=d))
|
52
|
+
output = render(markdown)
|
53
|
+
assert_equal "<p><a href=\"/?a=b&c=d\">/?a=b&c=d</a></p>", output
|
54
|
+
end
|
55
|
+
|
50
56
|
def test_that_no_links_flag_works
|
51
57
|
markdown = %([This link](http://example.net/) <a href="links.html">links</a>)
|
52
58
|
output = render(markdown, with: [:no_links])
|
@@ -58,17 +64,17 @@ EOE
|
|
58
64
|
markdown = "[IRC](irc://chat.freenode.org/#freenode)"
|
59
65
|
output = render(markdown, with: [:safe_links_only])
|
60
66
|
|
61
|
-
assert_equal "<p>[IRC](irc://chat.freenode.org/#freenode)</p
|
67
|
+
assert_equal "<p>[IRC](irc://chat.freenode.org/#freenode)</p>", output
|
62
68
|
end
|
63
69
|
|
64
70
|
def test_that_hard_wrap_works
|
65
|
-
markdown =
|
66
|
-
Hello world,
|
67
|
-
this is just a simple test
|
71
|
+
markdown = <<-Markdown.strip_heredoc
|
72
|
+
Hello world,
|
73
|
+
this is just a simple test
|
68
74
|
|
69
|
-
With hard wraps
|
70
|
-
and other *things*.
|
71
|
-
|
75
|
+
With hard wraps
|
76
|
+
and other *things*.
|
77
|
+
Markdown
|
72
78
|
output = render(markdown, with: [:hard_wrap])
|
73
79
|
|
74
80
|
assert_match %r{<br>}, output
|
@@ -82,37 +88,37 @@ EOE
|
|
82
88
|
|
83
89
|
def test_that_link_works_with_quotes
|
84
90
|
markdown = %([This'link"is](http://example.net/))
|
85
|
-
expected = %(<p><a href="http://example.net/">This'link"is</a></p
|
91
|
+
expected = %(<p><a href="http://example.net/">This'link"is</a></p>)
|
86
92
|
|
87
93
|
assert_equal expected, render(markdown)
|
88
94
|
assert_equal expected, render(markdown, with: [:escape_html])
|
89
95
|
end
|
90
96
|
|
91
97
|
def test_that_code_emphasis_work
|
92
|
-
markdown = <<-
|
93
|
-
This should be **`a bold codespan`**
|
94
|
-
However, this should be *`an emphasised codespan`*
|
98
|
+
markdown = <<-Markdown.strip_heredoc
|
99
|
+
This should be **`a bold codespan`**
|
100
|
+
However, this should be *`an emphasised codespan`*
|
95
101
|
|
96
|
-
* **`ABC`** or **`DEF`**
|
97
|
-
* Foo bar
|
98
|
-
|
102
|
+
* **`ABC`** or **`DEF`**
|
103
|
+
* Foo bar
|
104
|
+
Markdown
|
99
105
|
|
100
|
-
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>
|
106
|
+
html = <<-HTML.chomp.strip_heredoc
|
107
|
+
<p>This should be <strong><code>a bold codespan</code></strong>
|
108
|
+
However, this should be <em><code>an emphasised codespan</code></em></p>
|
103
109
|
|
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
|
110
|
+
<ul>
|
111
|
+
<li><strong><code>ABC</code></strong> or <strong><code>DEF</code></strong></li>
|
112
|
+
<li>Foo bar</li>
|
113
|
+
</ul>
|
114
|
+
HTML
|
109
115
|
|
110
116
|
assert_equal html, render(markdown)
|
111
117
|
end
|
112
118
|
|
113
119
|
def test_that_parenthesis_are_handled_into_links
|
114
120
|
markdown = %(The [bash man page](man:bash(1))!)
|
115
|
-
expected = %(<p>The <a href="man:bash(1)">bash man page</a>!</p
|
121
|
+
expected = %(<p>The <a href="man:bash(1)">bash man page</a>!</p>)
|
116
122
|
|
117
123
|
assert_equal expected, render(markdown)
|
118
124
|
end
|
@@ -127,42 +133,42 @@ HTML
|
|
127
133
|
end
|
128
134
|
|
129
135
|
def test_that_footnotes_work
|
130
|
-
markdown = <<-
|
131
|
-
This is a footnote.[^1]
|
136
|
+
markdown = <<-Markdown.strip_heredoc
|
137
|
+
This is a footnote.[^1]
|
132
138
|
|
133
|
-
[^1]: It provides additional information.
|
134
|
-
|
139
|
+
[^1]: It provides additional information.
|
140
|
+
Markdown
|
135
141
|
|
136
|
-
html =
|
137
|
-
<p>This is a footnote.<sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup></p>
|
142
|
+
html = <<-HTML.chomp.strip_heredoc
|
143
|
+
<p>This is a footnote.<sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup></p>
|
138
144
|
|
139
|
-
<div class="footnotes">
|
140
|
-
<hr>
|
141
|
-
<ol>
|
145
|
+
<div class="footnotes">
|
146
|
+
<hr>
|
147
|
+
<ol>
|
142
148
|
|
143
|
-
<li id="fn1">
|
144
|
-
<p>It provides additional information. <a href="#fnref1" rev="footnote">↩</a></p>
|
145
|
-
</li>
|
149
|
+
<li id="fn1">
|
150
|
+
<p>It provides additional information. <a href="#fnref1" rev="footnote">↩</a></p>
|
151
|
+
</li>
|
146
152
|
|
147
|
-
</ol>
|
148
|
-
</div>
|
149
|
-
HTML
|
153
|
+
</ol>
|
154
|
+
</div>
|
155
|
+
HTML
|
150
156
|
|
151
157
|
output = render(markdown, with: [:footnotes])
|
152
158
|
assert_equal html, output
|
153
159
|
end
|
154
160
|
|
155
161
|
def test_footnotes_enabled_but_missing_marker
|
156
|
-
markdown =
|
157
|
-
Some text without a marker
|
162
|
+
markdown = <<-Markdown.strip_heredoc
|
163
|
+
Some text without a marker
|
158
164
|
|
159
|
-
[^1] And a trailing definition
|
160
|
-
|
161
|
-
html =
|
162
|
-
<p>Some text without a marker</p>
|
165
|
+
[^1] And a trailing definition
|
166
|
+
Markdown
|
167
|
+
html = <<-HTML.chomp.strip_heredoc
|
168
|
+
<p>Some text without a marker</p>
|
163
169
|
|
164
|
-
<p>[^1] And a trailing definition</p>
|
165
|
-
HTML
|
170
|
+
<p>[^1] And a trailing definition</p>
|
171
|
+
HTML
|
166
172
|
|
167
173
|
output = render(markdown, with: [:footnotes])
|
168
174
|
assert_equal html, output
|
@@ -170,7 +176,7 @@ HTML
|
|
170
176
|
|
171
177
|
def test_footnotes_enabled_but_missing_definition
|
172
178
|
markdown = "Some text with a marker[^1] but no definition."
|
173
|
-
expected = "<p>Some text with a marker[^1] but no definition.</p
|
179
|
+
expected = "<p>Some text with a marker[^1] but no definition.</p>"
|
174
180
|
|
175
181
|
output = render(markdown, with: [:footnotes])
|
176
182
|
assert_equal expected, output
|
@@ -241,8 +247,22 @@ HTML
|
|
241
247
|
|
242
248
|
def test_non_ascii_removal_in_header_anchors
|
243
249
|
markdown = "# Glühlampe"
|
244
|
-
html = "<h1 id=\"gl-hlampe\">Glühlampe</h1
|
250
|
+
html = "<h1 id=\"gl-hlampe\">Glühlampe</h1>"
|
245
251
|
|
246
252
|
assert_equal html, render(markdown, with: [:with_toc_data])
|
247
253
|
end
|
254
|
+
|
255
|
+
def test_utf8_only_header_anchors
|
256
|
+
markdown = "# 見出し"
|
257
|
+
html = "<h1 id=\"part-37870bfa194139f\">見出し</h1>"
|
258
|
+
|
259
|
+
assert_equal html, render(markdown, with: [:with_toc_data])
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_escape_entities_removal_from_anchor
|
263
|
+
output = render("# Foo's & Bar's", with: [:with_toc_data])
|
264
|
+
result = %(<h1 id="foos-bars">Foo's & Bar's</h1>)
|
265
|
+
|
266
|
+
assert_equal result, output
|
267
|
+
end
|
248
268
|
end
|