redcarpet 3.3.4 → 3.5.1
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.
- checksums.yaml +5 -5
- data/Gemfile +2 -2
- data/README.markdown +45 -34
- data/ext/redcarpet/autolink.c +7 -1
- data/ext/redcarpet/buffer.h +0 -1
- data/ext/redcarpet/houdini_href_e.c +5 -11
- data/ext/redcarpet/houdini_html_e.c +0 -1
- data/ext/redcarpet/html.c +34 -7
- data/ext/redcarpet/html.h +1 -2
- data/ext/redcarpet/html_blocks.h +68 -70
- data/ext/redcarpet/html_smartypants.c +20 -5
- data/ext/redcarpet/markdown.c +5 -7
- data/ext/redcarpet/rc_markdown.c +17 -2
- data/ext/redcarpet/rc_render.c +28 -5
- data/lib/redcarpet/cli.rb +1 -1
- data/lib/redcarpet/compat.rb +0 -2
- data/lib/redcarpet/render_strip.rb +1 -1
- data/lib/redcarpet.rb +1 -1
- data/redcarpet.gemspec +5 -4
- data/test/custom_render_test.rb +40 -1
- data/test/html5_test.rb +51 -38
- data/test/html_render_test.rb +86 -60
- data/test/html_toc_render_test.rb +41 -4
- data/test/markdown_test.rb +226 -181
- data/test/redcarpet_bin_test.rb +2 -2
- data/test/smarty_html_test.rb +11 -5
- data/test/smarty_pants_test.rb +5 -0
- data/test/stripdown_render_test.rb +14 -6
- data/test/test_helper.rb +9 -1
- metadata +24 -11
data/ext/redcarpet/markdown.c
CHANGED
@@ -92,7 +92,6 @@ typedef size_t
|
|
92
92
|
|
93
93
|
static size_t char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
94
94
|
static size_t char_underline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
95
|
-
static size_t char_highlight(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
96
95
|
static size_t char_quote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
97
96
|
static size_t char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
98
97
|
static size_t char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
@@ -613,7 +612,7 @@ parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
|
|
613
612
|
if (data[i] == c && !_isspace(data[i - 1])) {
|
614
613
|
|
615
614
|
if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) {
|
616
|
-
if (i +
|
615
|
+
if (i + 1 < size && _isalnum(data[i + 1]))
|
617
616
|
continue;
|
618
617
|
}
|
619
618
|
|
@@ -845,7 +844,6 @@ char_quote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offse
|
|
845
844
|
return end;
|
846
845
|
}
|
847
846
|
|
848
|
-
|
849
847
|
/* char_escape • '\\' backslash escape */
|
850
848
|
static size_t
|
851
849
|
char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
|
@@ -2339,7 +2337,7 @@ parse_table_header(
|
|
2339
2337
|
if (i < under_end && data[i] != '|' && data[i] != '+')
|
2340
2338
|
break;
|
2341
2339
|
|
2342
|
-
if (dashes <
|
2340
|
+
if (dashes < 1)
|
2343
2341
|
break;
|
2344
2342
|
|
2345
2343
|
i++;
|
@@ -2757,10 +2755,13 @@ sd_markdown_new(
|
|
2757
2755
|
if (md->cb.emphasis || md->cb.double_emphasis || md->cb.triple_emphasis) {
|
2758
2756
|
md->active_char['*'] = MD_CHAR_EMPHASIS;
|
2759
2757
|
md->active_char['_'] = MD_CHAR_EMPHASIS;
|
2758
|
+
|
2760
2759
|
if (extensions & MKDEXT_STRIKETHROUGH)
|
2761
2760
|
md->active_char['~'] = MD_CHAR_EMPHASIS;
|
2762
2761
|
if (extensions & MKDEXT_HIGHLIGHT)
|
2763
2762
|
md->active_char['='] = MD_CHAR_EMPHASIS;
|
2763
|
+
if (extensions & MKDEXT_QUOTE)
|
2764
|
+
md->active_char['"'] = MD_CHAR_QUOTE;
|
2764
2765
|
}
|
2765
2766
|
|
2766
2767
|
if (md->cb.codespan)
|
@@ -2785,9 +2786,6 @@ sd_markdown_new(
|
|
2785
2786
|
if (extensions & MKDEXT_SUPERSCRIPT)
|
2786
2787
|
md->active_char['^'] = MD_CHAR_SUPERSCRIPT;
|
2787
2788
|
|
2788
|
-
if (extensions & MKDEXT_QUOTE)
|
2789
|
-
md->active_char['"'] = MD_CHAR_QUOTE;
|
2790
|
-
|
2791
2789
|
/* Extension data */
|
2792
2790
|
md->ext_flags = extensions;
|
2793
2791
|
md->opaque = opaque;
|
data/ext/redcarpet/rc_markdown.c
CHANGED
@@ -24,6 +24,7 @@
|
|
24
24
|
|
25
25
|
VALUE rb_mRedcarpet;
|
26
26
|
VALUE rb_cMarkdown;
|
27
|
+
VALUE rb_cRenderHTML_TOC;
|
27
28
|
|
28
29
|
extern VALUE rb_cRenderBase;
|
29
30
|
|
@@ -86,7 +87,7 @@ rb_redcarpet_md__free(void *markdown)
|
|
86
87
|
|
87
88
|
static VALUE rb_redcarpet_md__new(int argc, VALUE *argv, VALUE klass)
|
88
89
|
{
|
89
|
-
VALUE rb_markdown, rb_rndr, hash;
|
90
|
+
VALUE rb_markdown, rb_rndr, hash, rndr_options;
|
90
91
|
unsigned int extensions = 0;
|
91
92
|
|
92
93
|
struct rb_redcarpet_rndr *rndr;
|
@@ -101,8 +102,23 @@ static VALUE rb_redcarpet_md__new(int argc, VALUE *argv, VALUE klass)
|
|
101
102
|
if (!rb_obj_is_kind_of(rb_rndr, rb_cRenderBase))
|
102
103
|
rb_raise(rb_eTypeError, "Invalid Renderer instance given");
|
103
104
|
|
105
|
+
/**
|
106
|
+
* Automatically enable the `fenced_code_blocks` option if
|
107
|
+
* given a kind of `HTML_TOC` object since many languages
|
108
|
+
* like Ruby use the sharp to comment code so these comments
|
109
|
+
* would be processed as titles.
|
110
|
+
*/
|
111
|
+
if (rb_obj_is_kind_of(rb_rndr, rb_cRenderHTML_TOC))
|
112
|
+
extensions |= MKDEXT_FENCED_CODE;
|
113
|
+
|
104
114
|
Data_Get_Struct(rb_rndr, struct rb_redcarpet_rndr, rndr);
|
105
115
|
|
116
|
+
/* Merge the current options in the @options hash */
|
117
|
+
if (hash != Qnil) {
|
118
|
+
rndr_options = rb_funcall(rb_iv_get(rb_rndr, "@options"), rb_intern("merge"), 1, hash);
|
119
|
+
rb_iv_set(rb_rndr, "@options", rndr_options);
|
120
|
+
}
|
121
|
+
|
106
122
|
markdown = sd_markdown_new(extensions, 16, &rndr->callbacks, &rndr->options);
|
107
123
|
if (!markdown)
|
108
124
|
rb_raise(rb_eRuntimeError, "Failed to create new Renderer class");
|
@@ -165,4 +181,3 @@ void Init_redcarpet()
|
|
165
181
|
|
166
182
|
Init_redcarpet_rndr();
|
167
183
|
}
|
168
|
-
|
data/ext/redcarpet/rc_render.c
CHANGED
@@ -40,10 +40,10 @@
|
|
40
40
|
}
|
41
41
|
|
42
42
|
extern VALUE rb_mRedcarpet;
|
43
|
+
extern VALUE rb_cRenderHTML_TOC;
|
43
44
|
VALUE rb_mRender;
|
44
45
|
VALUE rb_cRenderBase;
|
45
46
|
VALUE rb_cRenderHTML;
|
46
|
-
VALUE rb_cRenderHTML_TOC;
|
47
47
|
VALUE rb_mSmartyPants;
|
48
48
|
|
49
49
|
#define buf2str(t) ((t) ? rb_enc_str_new((const char*)(t)->data, (t)->size, opt->active_enc) : Qnil)
|
@@ -390,6 +390,7 @@ static VALUE rb_redcarpet_rbase_alloc(VALUE klass)
|
|
390
390
|
static void rb_redcarpet__overload(VALUE self, VALUE base_class)
|
391
391
|
{
|
392
392
|
struct rb_redcarpet_rndr *rndr;
|
393
|
+
VALUE options_ivar;
|
393
394
|
|
394
395
|
Data_Get_Struct(self, struct rb_redcarpet_rndr, rndr);
|
395
396
|
rndr->options.self = self;
|
@@ -410,6 +411,10 @@ static void rb_redcarpet__overload(VALUE self, VALUE base_class)
|
|
410
411
|
dest[i] = source[i];
|
411
412
|
}
|
412
413
|
}
|
414
|
+
|
415
|
+
options_ivar = rb_attr_get(self, rb_intern("@options"));
|
416
|
+
if (options_ivar == Qundef || options_ivar == Qnil)
|
417
|
+
rb_iv_set(self, "@options", rb_hash_new());
|
413
418
|
}
|
414
419
|
|
415
420
|
static VALUE rb_redcarpet_rbase_init(VALUE self)
|
@@ -429,6 +434,9 @@ static VALUE rb_redcarpet_html_init(int argc, VALUE *argv, VALUE self)
|
|
429
434
|
if (rb_scan_args(argc, argv, "01", &hash) == 1) {
|
430
435
|
Check_Type(hash, T_HASH);
|
431
436
|
|
437
|
+
/* Give access to the passed options through `@options` */
|
438
|
+
rb_iv_set(self, "@options", hash);
|
439
|
+
|
432
440
|
/* escape_html */
|
433
441
|
if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue)
|
434
442
|
render_flags |= HTML_ESCAPE;
|
@@ -491,6 +499,9 @@ static VALUE rb_redcarpet_htmltoc_init(int argc, VALUE *argv, VALUE self)
|
|
491
499
|
if (rb_scan_args(argc, argv, "01", &hash) == 1) {
|
492
500
|
Check_Type(hash, T_HASH);
|
493
501
|
|
502
|
+
/* Give access to the passed options through `@options` */
|
503
|
+
rb_iv_set(self, "@options", hash);
|
504
|
+
|
494
505
|
/* escape_html */
|
495
506
|
if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue)
|
496
507
|
render_flags |= HTML_ESCAPE;
|
@@ -502,10 +513,22 @@ static VALUE rb_redcarpet_htmltoc_init(int argc, VALUE *argv, VALUE self)
|
|
502
513
|
sdhtml_toc_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, render_flags);
|
503
514
|
rb_redcarpet__overload(self, rb_cRenderHTML_TOC);
|
504
515
|
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
516
|
+
/* Check whether we are dealing with a Range object by
|
517
|
+
checking whether the object responds to min and max */
|
518
|
+
if (rb_respond_to(nesting_level, rb_intern("min")) &&
|
519
|
+
rb_respond_to(nesting_level, rb_intern("max"))) {
|
520
|
+
int min = NUM2INT(rb_funcall(nesting_level, rb_intern("min"), 0));
|
521
|
+
int max = NUM2INT(rb_funcall(nesting_level, rb_intern("max"), 0));
|
522
|
+
|
523
|
+
rndr->options.html.toc_data.nesting_bounds[0] = min;
|
524
|
+
rndr->options.html.toc_data.nesting_bounds[1] = max;
|
525
|
+
} else if (FIXNUM_P(nesting_level)) {
|
526
|
+
rndr->options.html.toc_data.nesting_bounds[0] = 1;
|
527
|
+
rndr->options.html.toc_data.nesting_bounds[1] = NUM2INT(nesting_level);
|
528
|
+
} else {
|
529
|
+
rndr->options.html.toc_data.nesting_bounds[0] = 1;
|
530
|
+
rndr->options.html.toc_data.nesting_bounds[1] = 6;
|
531
|
+
}
|
509
532
|
|
510
533
|
return Qnil;
|
511
534
|
}
|
data/lib/redcarpet/cli.rb
CHANGED
data/lib/redcarpet/compat.rb
CHANGED
@@ -13,7 +13,7 @@ module Redcarpet
|
|
13
13
|
:autolink, :codespan, :double_emphasis,
|
14
14
|
:emphasis, :underline, :raw_html,
|
15
15
|
:triple_emphasis, :strikethrough,
|
16
|
-
:superscript, :highlight,
|
16
|
+
:superscript, :highlight, :quote,
|
17
17
|
|
18
18
|
# footnotes
|
19
19
|
:footnotes, :footnote_def, :footnote_ref,
|
data/lib/redcarpet.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.5.1'
|
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 = '2020-12-15'
|
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
|
69
|
-
s.add_development_dependency "
|
68
|
+
s.add_development_dependency "rake", "~> 12.2.1"
|
69
|
+
s.add_development_dependency "rake-compiler", "~> 1.0.3"
|
70
|
+
s.add_development_dependency "test-unit", "~> 3.2.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,30 @@ 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
|
+
|
39
|
+
def test_original_options_hash_is_not_mutated
|
40
|
+
options = { with_toc_data: true }
|
41
|
+
render = SimpleRender.new(options)
|
42
|
+
parser = Redcarpet::Markdown.new(render, tables: true)
|
43
|
+
|
44
|
+
computed_options = render.instance_variable_get(:"@options")
|
45
|
+
|
46
|
+
refute_equal computed_options.object_id, options.object_id
|
47
|
+
end
|
48
|
+
|
17
49
|
class NilPreprocessRenderer < Redcarpet::Render::HTML
|
18
50
|
def preprocess(fulldoc)
|
19
51
|
nil
|
@@ -25,4 +57,11 @@ class CustomRenderTest < Redcarpet::TestCase
|
|
25
57
|
assert_equal(nil,md.render("Anything"))
|
26
58
|
end
|
27
59
|
|
60
|
+
def test_base_render_without_quote_callback
|
61
|
+
# Regression test for https://github.com/vmg/redcarpet/issues/569
|
62
|
+
render = Class.new(Redcarpet::Render::Base)
|
63
|
+
parser = Redcarpet::Markdown.new render.new, quote: true
|
64
|
+
|
65
|
+
assert_equal "", parser.render(%(a "quote"))
|
66
|
+
end
|
28
67
|
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"
|
142
|
+
html = <<-HTML.chomp.strip_heredoc
|
143
|
+
<p>This is a footnote.<sup id="fnref1"><a href="#fn1">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"
|
145
|
-
</li>
|
149
|
+
<li id="fn1">
|
150
|
+
<p>It provides additional information. <a href="#fnref1">↩</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,28 @@ 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
|
+
if 1.size == 4 # 32-bit architecture
|
258
|
+
html = "<h1 id=\"part-a194139f\">見出し</h1>"
|
259
|
+
elsif 1.size == 8 # 64-bit architecture
|
260
|
+
html = "<h1 id=\"part-37870bfa194139f\">見出し</h1>"
|
261
|
+
else
|
262
|
+
raise "unknown integer size"
|
263
|
+
end
|
264
|
+
|
265
|
+
assert_equal html, render(markdown, with: [:with_toc_data])
|
266
|
+
end
|
267
|
+
|
268
|
+
def test_escape_entities_removal_from_anchor
|
269
|
+
output = render("# Foo's & Bar's", with: [:with_toc_data])
|
270
|
+
result = %(<h1 id="foos-bars">Foo's & Bar's</h1>)
|
271
|
+
|
272
|
+
assert_equal result, output
|
273
|
+
end
|
248
274
|
end
|