asciidoctor 0.0.7 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of asciidoctor might be problematic. Click here for more details.
- data/Gemfile +2 -0
- data/README.asciidoc +35 -26
- data/Rakefile +9 -6
- data/asciidoctor.gemspec +27 -8
- data/bin/asciidoctor +1 -1
- data/lib/asciidoctor.rb +351 -63
- data/lib/asciidoctor/abstract_block.rb +218 -0
- data/lib/asciidoctor/abstract_node.rb +249 -0
- data/lib/asciidoctor/attribute_list.rb +211 -0
- data/lib/asciidoctor/backends/base_template.rb +99 -0
- data/lib/asciidoctor/backends/docbook45.rb +510 -0
- data/lib/asciidoctor/backends/html5.rb +585 -0
- data/lib/asciidoctor/block.rb +27 -254
- data/lib/asciidoctor/callouts.rb +117 -0
- data/lib/asciidoctor/debug.rb +7 -4
- data/lib/asciidoctor/document.rb +229 -77
- data/lib/asciidoctor/inline.rb +29 -0
- data/lib/asciidoctor/lexer.rb +1330 -502
- data/lib/asciidoctor/list_item.rb +33 -34
- data/lib/asciidoctor/reader.rb +305 -142
- data/lib/asciidoctor/renderer.rb +115 -19
- data/lib/asciidoctor/section.rb +100 -189
- data/lib/asciidoctor/substituters.rb +468 -0
- data/lib/asciidoctor/table.rb +499 -0
- data/lib/asciidoctor/version.rb +1 -1
- data/test/attributes_test.rb +301 -87
- data/test/blocks_test.rb +568 -0
- data/test/document_test.rb +221 -24
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +1 -0
- data/test/fixtures/include-file.asciidoc +1 -0
- data/test/fixtures/tip.gif +0 -0
- data/test/headers_test.rb +411 -43
- data/test/lexer_test.rb +265 -45
- data/test/links_test.rb +144 -3
- data/test/lists_test.rb +2252 -74
- data/test/paragraphs_test.rb +21 -30
- data/test/preamble_test.rb +24 -0
- data/test/reader_test.rb +248 -12
- data/test/renderer_test.rb +22 -0
- data/test/substitutions_test.rb +414 -0
- data/test/tables_test.rb +484 -0
- data/test/test_helper.rb +70 -6
- data/test/text_test.rb +30 -6
- metadata +64 -10
- data/lib/asciidoctor/render_templates.rb +0 -317
- data/lib/asciidoctor/string.rb +0 -12
data/test/paragraphs_test.rb
CHANGED
@@ -1,26 +1,27 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
context "Paragraphs" do
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
context 'Normal' do
|
5
|
+
test "rendered correctly" do
|
6
|
+
assert_xpath "//p", render_string("Plain text for the win.\n\nYes, plainly."), 2
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
test "with title" do
|
10
|
+
rendered = render_string(".Titled\nParagraph.\n\nWinning")
|
11
|
+
|
12
|
+
assert_xpath "//div[@class='title']", rendered
|
13
|
+
assert_xpath "//p", rendered, 2
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
test "no duplicate block before next section" do
|
17
|
+
rendered = render_string("Title\n=====\n\nPreamble.\n\n== First Section\n\nParagraph 1\n\nParagraph 2\n\n\n== Second Section\n\nLast words")
|
18
|
+
assert_xpath '//p[text()="Paragraph 2"]', rendered, 1
|
19
|
+
end
|
18
20
|
end
|
19
21
|
|
20
22
|
context "code" do
|
21
23
|
test "single-line literal paragraphs" do
|
22
|
-
|
23
|
-
assert_xpath "//pre/tt", render_string(" LITERALS\n\n ARE LITERALLY\n\n AWESOMMMME.")
|
24
|
+
assert_xpath "//pre", render_string(" LITERALS\n\n ARE LITERALLY\n\n AWESOMMMME.")
|
24
25
|
end
|
25
26
|
|
26
27
|
test "multi-line literal paragraph" do
|
@@ -33,16 +34,16 @@ Install instructions:
|
|
33
34
|
You're good to go!
|
34
35
|
EOS
|
35
36
|
output = render_string(input)
|
36
|
-
assert_xpath "//pre
|
37
|
-
assert_match
|
37
|
+
assert_xpath "//pre", output, 1
|
38
|
+
assert_match(/^gem install asciidoctor/, output, "Indentation should be trimmed from literal block")
|
38
39
|
end
|
39
40
|
|
40
41
|
test "listing paragraph" do
|
41
|
-
assert_xpath "//
|
42
|
+
assert_xpath "//pre[@class='highlight']/code", render_string("[source]\n----\nblah blah blah\n----")
|
42
43
|
end
|
43
44
|
|
44
45
|
test "source code paragraph" do
|
45
|
-
assert_xpath "//
|
46
|
+
assert_xpath "//pre[@class='highlight']/code[@class='perl']", render_string("[source, perl]\ndie 'zomg perl sucks';")
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
@@ -54,10 +55,10 @@ You're good to go!
|
|
54
55
|
end
|
55
56
|
|
56
57
|
test "quote block with attribution" do
|
57
|
-
output = render_string("[quote, A famous person, A famous book]\n____\nFamous quote.\n____")
|
58
|
+
output = render_string("[quote, A famous person, A famous book (1999)]\n____\nFamous quote.\n____")
|
58
59
|
assert_xpath '//*[@class = "quoteblock"]', output, 1
|
59
60
|
assert_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]', output, 1
|
60
|
-
assert_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]/em[text() = "A famous book"]', output, 1
|
61
|
+
assert_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]/em[text() = "A famous book (1999)"]', output, 1
|
61
62
|
# TODO I can't seem to match the attribution (author) w/ xpath
|
62
63
|
end
|
63
64
|
|
@@ -140,14 +141,4 @@ Content goes here
|
|
140
141
|
assert_xpath "//*[@class='sidebarblock']//p", result, 1
|
141
142
|
end
|
142
143
|
end
|
143
|
-
|
144
|
-
context "comments" do
|
145
|
-
test "line comment" do
|
146
|
-
assert_no_match /comment/, render_string("first paragraph\n\n//comment\n\nsecond paragraph")
|
147
|
-
end
|
148
|
-
|
149
|
-
test "comment block" do
|
150
|
-
assert_no_match /comment/, render_string("first paragraph\n\n////\ncomment\n////\n\nsecond paragraph")
|
151
|
-
end
|
152
|
-
end
|
153
144
|
end
|
data/test/preamble_test.rb
CHANGED
@@ -85,4 +85,28 @@ Section paragraph 1.
|
|
85
85
|
assert_xpath '//h2[@id="_first_section"]/preceding::p', result, 1
|
86
86
|
end
|
87
87
|
|
88
|
+
test 'preamble in book doctype' do
|
89
|
+
input = <<-EOS
|
90
|
+
Book
|
91
|
+
====
|
92
|
+
:doctype: book
|
93
|
+
|
94
|
+
Back then...
|
95
|
+
|
96
|
+
= Chapter One
|
97
|
+
|
98
|
+
It was a dark and stormy night...
|
99
|
+
|
100
|
+
= Chapter Two
|
101
|
+
|
102
|
+
They couldn't believe their eyes when...
|
103
|
+
EOS
|
104
|
+
|
105
|
+
d = document_from_string(input)
|
106
|
+
assert_equal 'book', d.doctype
|
107
|
+
output = d.render
|
108
|
+
assert_xpath '//h1', output, 3
|
109
|
+
assert_xpath %{//*[@id="preamble"]//p[text() = "Back then#{[8230].pack('U*')}"]}, output, 1
|
110
|
+
end
|
111
|
+
|
88
112
|
end
|
data/test/reader_test.rb
CHANGED
@@ -9,7 +9,7 @@ class ReaderTest < Test::Unit::TestCase
|
|
9
9
|
|
10
10
|
context "has_lines?" do
|
11
11
|
test "returns false for empty document" do
|
12
|
-
assert !
|
12
|
+
assert !Asciidoctor::Reader.new.has_lines?
|
13
13
|
end
|
14
14
|
|
15
15
|
test "returns true with lines remaining" do
|
@@ -35,22 +35,258 @@ class ReaderTest < Test::Unit::TestCase
|
|
35
35
|
second = reader.peek_line
|
36
36
|
assert_equal "foo", second
|
37
37
|
end
|
38
|
+
|
39
|
+
test "unshift puts line onto Reader instance for the next get_line" do
|
40
|
+
reader = Asciidoctor::Reader.new(["foo"])
|
41
|
+
reader.unshift("bar")
|
42
|
+
assert_equal "bar", reader.get_line
|
43
|
+
assert_equal "foo", reader.get_line
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "Grab lines" do
|
48
|
+
test "Grab until end" do
|
49
|
+
input = <<-EOS
|
50
|
+
This is one paragraph.
|
51
|
+
|
52
|
+
This is another paragraph.
|
53
|
+
EOS
|
54
|
+
|
55
|
+
lines = input.lines.entries
|
56
|
+
reader = Asciidoctor::Reader.new(lines)
|
57
|
+
result = reader.grab_lines_until
|
58
|
+
assert_equal 3, result.size
|
59
|
+
assert_equal lines, result
|
60
|
+
assert !reader.has_lines?
|
61
|
+
assert reader.empty?
|
62
|
+
end
|
63
|
+
|
64
|
+
test "Grab until blank line" do
|
65
|
+
input = <<-EOS
|
66
|
+
This is one paragraph.
|
67
|
+
|
68
|
+
This is another paragraph.
|
69
|
+
EOS
|
70
|
+
|
71
|
+
lines = input.lines.entries
|
72
|
+
reader = Asciidoctor::Reader.new(lines)
|
73
|
+
result = reader.grab_lines_until :break_on_blank_lines => true
|
74
|
+
assert_equal 1, result.size
|
75
|
+
assert_equal lines.first, result.first
|
76
|
+
assert_equal lines.last, reader.peek_line
|
77
|
+
end
|
78
|
+
|
79
|
+
test "Grab until blank line preserving last line" do
|
80
|
+
input = <<-EOS
|
81
|
+
This is one paragraph.
|
82
|
+
|
83
|
+
This is another paragraph.
|
84
|
+
EOS
|
85
|
+
|
86
|
+
lines = input.lines.entries
|
87
|
+
reader = Asciidoctor::Reader.new(lines)
|
88
|
+
result = reader.grab_lines_until :break_on_blank_lines => true, :preserve_last_line => true
|
89
|
+
assert_equal 1, result.size
|
90
|
+
assert_equal lines.first, result.first
|
91
|
+
assert_equal "\n", reader.peek_line
|
92
|
+
end
|
93
|
+
|
94
|
+
test "Grab until condition" do
|
95
|
+
input = <<-EOS
|
96
|
+
--
|
97
|
+
This is one paragraph inside the block.
|
98
|
+
|
99
|
+
This is another paragraph inside the block.
|
100
|
+
--
|
101
|
+
|
102
|
+
This is a paragraph outside the block.
|
103
|
+
EOS
|
104
|
+
|
105
|
+
lines = input.lines.entries
|
106
|
+
reader = Asciidoctor::Reader.new(lines)
|
107
|
+
reader.get_line
|
108
|
+
result = reader.grab_lines_until {|line| line.chomp == '--' }
|
109
|
+
assert_equal 3, result.size
|
110
|
+
assert_equal lines[1, 3], result
|
111
|
+
assert_equal "\n", reader.peek_line
|
112
|
+
end
|
113
|
+
|
114
|
+
test "Grab until condition with last line" do
|
115
|
+
input = <<-EOS
|
116
|
+
--
|
117
|
+
This is one paragraph inside the block.
|
118
|
+
|
119
|
+
This is another paragraph inside the block.
|
120
|
+
--
|
121
|
+
|
122
|
+
This is a paragraph outside the block.
|
123
|
+
EOS
|
124
|
+
|
125
|
+
lines = input.lines.entries
|
126
|
+
reader = Asciidoctor::Reader.new(lines)
|
127
|
+
reader.get_line
|
128
|
+
result = reader.grab_lines_until(:grab_last_line => true) {|line| line.chomp == '--' }
|
129
|
+
assert_equal 4, result.size
|
130
|
+
assert_equal lines[1, 4], result
|
131
|
+
assert_equal "\n", reader.peek_line
|
132
|
+
end
|
133
|
+
|
134
|
+
test "Grab until condition with last line and preserving last line" do
|
135
|
+
input = <<-EOS
|
136
|
+
--
|
137
|
+
This is one paragraph inside the block.
|
138
|
+
|
139
|
+
This is another paragraph inside the block.
|
140
|
+
--
|
141
|
+
|
142
|
+
This is a paragraph outside the block.
|
143
|
+
EOS
|
144
|
+
|
145
|
+
lines = input.lines.entries
|
146
|
+
reader = Asciidoctor::Reader.new(lines)
|
147
|
+
reader.get_line
|
148
|
+
result = reader.grab_lines_until(:grab_last_line => true, :preserve_last_line => true) {|line| line.chomp == '--' }
|
149
|
+
assert_equal 4, result.size
|
150
|
+
assert_equal lines[1, 4], result
|
151
|
+
assert_equal "--\n", reader.peek_line
|
152
|
+
end
|
38
153
|
end
|
39
154
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
155
|
+
context 'Include Macro' do
|
156
|
+
test 'include macro is disabled by default' do
|
157
|
+
input = <<-EOS
|
158
|
+
include::include-file.asciidoc[]
|
159
|
+
EOS
|
160
|
+
para = block_from_string input, :attributes => { 'include-depth' => 0 }
|
161
|
+
assert_equal 1, para.buffer.size
|
162
|
+
assert_equal 'include::include-file.asciidoc[]', para.buffer.join
|
163
|
+
end
|
164
|
+
|
165
|
+
test 'include macro is enabled when safe mode is less than SECURE' do
|
166
|
+
input = <<-EOS
|
167
|
+
include::fixtures/include-file.asciidoc[]
|
168
|
+
EOS
|
169
|
+
|
170
|
+
doc = document_from_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'docdir' => File.dirname(__FILE__)}
|
171
|
+
output = doc.render
|
172
|
+
assert_match(/included content/, output)
|
173
|
+
end
|
174
|
+
|
175
|
+
test "block is called to handle an include macro" do
|
176
|
+
input = <<-EOS
|
177
|
+
first line
|
178
|
+
|
179
|
+
include::include-file.asciidoc[]
|
180
|
+
|
181
|
+
last line
|
182
|
+
EOS
|
183
|
+
doc = Asciidoctor::Document.new [], :safe => Asciidoctor::SafeMode::SAFE
|
184
|
+
Asciidoctor::Reader.new(input.lines.entries, doc) {|inc|
|
185
|
+
":file: #{inc}\n\nmiddle line".lines.entries
|
186
|
+
}
|
187
|
+
assert_equal 'include-file.asciidoc', doc.attributes['file']
|
188
|
+
end
|
189
|
+
|
190
|
+
test 'escaped include macro is left unprocessed' do
|
191
|
+
input = <<-EOS
|
192
|
+
\\include::include-file.asciidoc[]
|
193
|
+
EOS
|
194
|
+
para = block_from_string input
|
195
|
+
assert_equal 1, para.buffer.size
|
196
|
+
assert_equal 'include::include-file.asciidoc[]', para.buffer.join
|
197
|
+
end
|
198
|
+
|
199
|
+
test 'include macro not at start of line is ignored' do
|
200
|
+
input = <<-EOS
|
201
|
+
include::include-file.asciidoc[]
|
202
|
+
EOS
|
203
|
+
para = block_from_string input
|
204
|
+
assert_equal 1, para.buffer.size
|
205
|
+
# NOTE the space gets stripped because the line is treated as an inline literal
|
206
|
+
assert_equal :literal, para.context
|
207
|
+
assert_equal 'include::include-file.asciidoc[]', para.buffer.join
|
208
|
+
end
|
209
|
+
|
210
|
+
test 'include macro is disabled when include-depth attribute is 0' do
|
211
|
+
input = <<-EOS
|
212
|
+
include::include-file.asciidoc[]
|
213
|
+
EOS
|
214
|
+
para = block_from_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => { 'include-depth' => 0 }
|
215
|
+
assert_equal 1, para.buffer.size
|
216
|
+
assert_equal 'include::include-file.asciidoc[]', para.buffer.join
|
217
|
+
end
|
218
|
+
|
219
|
+
test 'include-depth cannot be set by document' do
|
220
|
+
input = <<-EOS
|
221
|
+
:include-depth: 1
|
222
|
+
|
223
|
+
include::include-file.asciidoc[]
|
224
|
+
EOS
|
225
|
+
para = block_from_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => { 'include-depth' => 0 }
|
226
|
+
assert_equal 1, para.buffer.size
|
227
|
+
assert_equal 'include::include-file.asciidoc[]', para.buffer.join
|
228
|
+
end
|
45
229
|
end
|
46
230
|
|
47
|
-
|
48
|
-
|
231
|
+
context 'build secure asset path' do
|
232
|
+
test 'allows us to specify a path relative to the current dir' do
|
233
|
+
doc = Asciidoctor::Document.new
|
234
|
+
reader = Asciidoctor::Reader.new(["foo"], doc)
|
235
|
+
legit_path = Dir.pwd + "/foo"
|
236
|
+
assert_equal legit_path, doc.normalize_asset_path(legit_path)
|
237
|
+
end
|
238
|
+
|
239
|
+
test "keeps naughty absolute paths from getting outside" do
|
240
|
+
naughty_path = "/etc/passwd"
|
241
|
+
doc = Asciidoctor::Document.new
|
242
|
+
reader = Asciidoctor::Reader.new(["foo"], doc)
|
243
|
+
secure_path = doc.normalize_asset_path(naughty_path)
|
244
|
+
assert naughty_path != secure_path
|
245
|
+
assert_match(/^#{doc.base_dir}/, secure_path)
|
246
|
+
end
|
247
|
+
|
248
|
+
test "keeps naughty relative paths from getting outside" do
|
249
|
+
naughty_path = "safe/ok/../../../../../etc/passwd"
|
250
|
+
doc = Asciidoctor::Document.new
|
251
|
+
reader = Asciidoctor::Reader.new(["foo"], doc)
|
252
|
+
secure_path = doc.normalize_asset_path(naughty_path)
|
253
|
+
assert naughty_path != secure_path
|
254
|
+
assert_match(/^#{doc.base_dir}/, secure_path)
|
255
|
+
end
|
49
256
|
end
|
50
257
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
258
|
+
# TODO these tests could be expanded
|
259
|
+
context 'Conditional blocks' do
|
260
|
+
test 'ifdef with defined attribute includes block' do
|
261
|
+
input = <<-EOS
|
262
|
+
:holygrail:
|
263
|
+
|
264
|
+
ifdef::holygrail[]
|
265
|
+
There is a holy grail!
|
266
|
+
endif::holygrail[]
|
267
|
+
EOS
|
268
|
+
|
269
|
+
reader = Asciidoctor::Reader.new(input.lines.entries, Asciidoctor::Document.new)
|
270
|
+
assert_match(/There is a holy grail!/, reader.lines.join)
|
271
|
+
end
|
272
|
+
|
273
|
+
test 'ifndef with undefined attribute includes block' do
|
274
|
+
input = <<-EOS
|
275
|
+
ifndef::holygrail[]
|
276
|
+
Our quest continues to find the holy grail!
|
277
|
+
endif::holygrail[]
|
278
|
+
EOS
|
279
|
+
|
280
|
+
reader = Asciidoctor::Reader.new(input.lines.entries, Asciidoctor::Document.new)
|
281
|
+
assert_match(/Our quest continues to find the holy grail!/, reader.lines.join)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context 'Text processing' do
|
286
|
+
test 'sanitize attribute name' do
|
287
|
+
assert_equal 'foobar', @reader.sanitize_attribute_name("Foo Bar")
|
288
|
+
assert_equal 'foo', @reader.sanitize_attribute_name("foo")
|
289
|
+
assert_equal 'foo3-bar', @reader.sanitize_attribute_name("Foo 3^ # - Bar[")
|
290
|
+
end
|
55
291
|
end
|
56
292
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
context 'Renderer' do
|
4
|
+
|
5
|
+
test 'should extract view mapping from built-in template with one segment and backend' do
|
6
|
+
view_name, view_backend = Asciidoctor::Renderer.extract_view_mapping('Asciidoctor::HTML5::DocumentTemplate')
|
7
|
+
assert_equal 'document', view_name
|
8
|
+
assert_equal 'html5', view_backend
|
9
|
+
end
|
10
|
+
|
11
|
+
test 'should extract view mapping from built-in template with two segments and backend' do
|
12
|
+
view_name, view_backend = Asciidoctor::Renderer.extract_view_mapping('Asciidoctor::DocBook45::BlockSidebarTemplate')
|
13
|
+
assert_equal 'block_sidebar', view_name
|
14
|
+
assert_equal 'docbook45', view_backend
|
15
|
+
end
|
16
|
+
|
17
|
+
test 'should extract view mapping from built-in template without backend' do
|
18
|
+
view_name, view_backend = Asciidoctor::Renderer.extract_view_mapping('Asciidoctor::DocumentTemplate')
|
19
|
+
assert_equal 'document', view_name
|
20
|
+
assert view_backend.nil?
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,414 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# TODO
|
4
|
+
# - test negatives
|
5
|
+
# - test role on every quote type
|
6
|
+
context 'Substitutions' do
|
7
|
+
context 'Dispatcher' do
|
8
|
+
test 'apply normal substitutions' do
|
9
|
+
para = block_from_string("[blue]'http://asciidoc.org[AsciiDoc]' & [red]*Ruby*\n§ Making +++<u>documentation</u>+++ together +\nsince (C) {inception_year}.")
|
10
|
+
para.document.attributes['inception_year'] = '2012'
|
11
|
+
result = para.apply_normal_subs(para.buffer)
|
12
|
+
assert_equal %{<em><span class="blue"><a href="http://asciidoc.org">AsciiDoc</a></span></em> & <strong><span class="red">Ruby</span></strong>\n§ Making <u>documentation</u> together<br>\nsince © 2012.}, result
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'Quotes' do
|
17
|
+
test 'single-line double-quoted string' do
|
18
|
+
para = block_from_string(%q{``a few quoted words''})
|
19
|
+
assert_equal '“a few quoted words”', para.sub_quotes(para.buffer.join)
|
20
|
+
end
|
21
|
+
|
22
|
+
test 'escaped single-line double-quoted string' do
|
23
|
+
para = block_from_string(%q{\``a few quoted words''})
|
24
|
+
assert_equal %q(‘`a few quoted words’'), para.sub_quotes(para.buffer.join)
|
25
|
+
end
|
26
|
+
|
27
|
+
test 'multi-line double-quoted string' do
|
28
|
+
para = block_from_string(%Q{``a few\nquoted words''})
|
29
|
+
assert_equal "“a few\nquoted words”", para.sub_quotes(para.buffer.join)
|
30
|
+
end
|
31
|
+
|
32
|
+
test 'double-quoted string with inline single quote' do
|
33
|
+
para = block_from_string(%q{``Here's Johnny!''})
|
34
|
+
assert_equal %q{“Here's Johnny!”}, para.sub_quotes(para.buffer.join)
|
35
|
+
end
|
36
|
+
|
37
|
+
test 'double-quoted string with inline backquote' do
|
38
|
+
para = block_from_string(%q{``Here`s Johnny!''})
|
39
|
+
assert_equal %q{“Here`s Johnny!”}, para.sub_quotes(para.buffer.join)
|
40
|
+
end
|
41
|
+
|
42
|
+
test 'single-line single-quoted string' do
|
43
|
+
para = block_from_string(%q{`a few quoted words'})
|
44
|
+
assert_equal '‘a few quoted words’', para.sub_quotes(para.buffer.join)
|
45
|
+
end
|
46
|
+
|
47
|
+
test 'escaped single-line single-quoted string' do
|
48
|
+
para = block_from_string(%q{\`a few quoted words'})
|
49
|
+
assert_equal %(`a few quoted words'), para.sub_quotes(para.buffer.join)
|
50
|
+
end
|
51
|
+
|
52
|
+
test 'multi-line single-quoted string' do
|
53
|
+
para = block_from_string(%Q{`a few\nquoted words'})
|
54
|
+
assert_equal "‘a few\nquoted words’", para.sub_quotes(para.buffer.join)
|
55
|
+
end
|
56
|
+
|
57
|
+
test 'single-quoted string with inline single quote' do
|
58
|
+
para = block_from_string(%q{`That isn't what I did.'})
|
59
|
+
assert_equal %q{‘That isn't what I did.’}, para.sub_quotes(para.buffer.join)
|
60
|
+
end
|
61
|
+
|
62
|
+
test 'single-quoted string with inline backquote' do
|
63
|
+
para = block_from_string(%q{`Here`s Johnny!'})
|
64
|
+
assert_equal %q{‘Here`s Johnny!’}, para.sub_quotes(para.buffer.join)
|
65
|
+
end
|
66
|
+
|
67
|
+
test 'single-line constrained unquoted string' do
|
68
|
+
para = block_from_string(%q{#a few words#})
|
69
|
+
assert_equal 'a few words', para.sub_quotes(para.buffer.join)
|
70
|
+
end
|
71
|
+
|
72
|
+
test 'escaped single-line constrained unquoted string' do
|
73
|
+
para = block_from_string(%q{\#a few words#})
|
74
|
+
assert_equal '#a few words#', para.sub_quotes(para.buffer.join)
|
75
|
+
end
|
76
|
+
|
77
|
+
test 'multi-line constrained unquoted string' do
|
78
|
+
para = block_from_string(%Q{#a few\nwords#})
|
79
|
+
assert_equal "a few\nwords", para.sub_quotes(para.buffer.join)
|
80
|
+
end
|
81
|
+
|
82
|
+
test 'single-line unconstrained unquoted string' do
|
83
|
+
para = block_from_string(%q{##--anything goes ##})
|
84
|
+
assert_equal '--anything goes ', para.sub_quotes(para.buffer.join)
|
85
|
+
end
|
86
|
+
|
87
|
+
test 'escaped single-line unconstrained unquoted string' do
|
88
|
+
para = block_from_string(%q{\##--anything goes ##})
|
89
|
+
assert_equal '#--anything goes #', para.sub_quotes(para.buffer.join)
|
90
|
+
end
|
91
|
+
|
92
|
+
test 'multi-line unconstrained unquoted string' do
|
93
|
+
para = block_from_string(%Q{##--anything\ngoes ##})
|
94
|
+
assert_equal "--anything\ngoes ", para.sub_quotes(para.buffer.join)
|
95
|
+
end
|
96
|
+
|
97
|
+
test 'single-line constrained strong string' do
|
98
|
+
para = block_from_string(%q{*a few strong words*})
|
99
|
+
assert_equal '<strong>a few strong words</strong>', para.sub_quotes(para.buffer.join)
|
100
|
+
end
|
101
|
+
|
102
|
+
test 'escaped single-line constrained strong string' do
|
103
|
+
para = block_from_string(%q{\*a few strong words*})
|
104
|
+
assert_equal '*a few strong words*', para.sub_quotes(para.buffer.join)
|
105
|
+
end
|
106
|
+
|
107
|
+
test 'multi-line constrained strong string' do
|
108
|
+
para = block_from_string(%Q{*a few\nstrong words*})
|
109
|
+
assert_equal "<strong>a few\nstrong words</strong>", para.sub_quotes(para.buffer.join)
|
110
|
+
end
|
111
|
+
|
112
|
+
test 'constrained strong string containing an asterisk' do
|
113
|
+
para = block_from_string(%q{*bl*ck*-eye})
|
114
|
+
assert_equal '<strong>bl*ck</strong>-eye', para.sub_quotes(para.buffer.join)
|
115
|
+
end
|
116
|
+
|
117
|
+
test 'single-line constrained quote variation emphasized string' do
|
118
|
+
para = block_from_string(%q{'a few emphasized words'})
|
119
|
+
assert_equal '<em>a few emphasized words</em>', para.sub_quotes(para.buffer.join)
|
120
|
+
end
|
121
|
+
|
122
|
+
test 'escaped single-line constrained quote variation emphasized string' do
|
123
|
+
para = block_from_string(%q{\'a few emphasized words'})
|
124
|
+
assert_equal %q('a few emphasized words'), para.sub_quotes(para.buffer.join)
|
125
|
+
end
|
126
|
+
|
127
|
+
test 'multi-line constrained emphasized quote variation string' do
|
128
|
+
para = block_from_string(%Q{'a few\nemphasized words'})
|
129
|
+
assert_equal "<em>a few\nemphasized words</em>", para.sub_quotes(para.buffer.join)
|
130
|
+
end
|
131
|
+
|
132
|
+
test 'single-quoted string containing an emphasized phrase' do
|
133
|
+
para = block_from_string(%q{`I told him, 'Just go for it!''})
|
134
|
+
assert_equal '‘I told him, <em>Just go for it!</em>’', para.sub_quotes(para.buffer.join)
|
135
|
+
end
|
136
|
+
|
137
|
+
test 'escaped single-quotes inside emphasized words are restored' do
|
138
|
+
para = block_from_string(%q{'Here\'s Johnny!'})
|
139
|
+
# NOTE the \' is replaced with ' by the :replacements substitution, later in the substitution pipeline
|
140
|
+
assert_equal %q{<em>Here\'s Johnny!</em>}, para.sub_quotes(para.buffer.join)
|
141
|
+
end
|
142
|
+
|
143
|
+
test 'single-line constrained emphasized underline variation string' do
|
144
|
+
para = block_from_string(%q{_a few emphasized words_})
|
145
|
+
assert_equal '<em>a few emphasized words</em>', para.sub_quotes(para.buffer.join)
|
146
|
+
end
|
147
|
+
|
148
|
+
test 'escaped single-line constrained emphasized underline variation string' do
|
149
|
+
para = block_from_string(%q{\_a few emphasized words_})
|
150
|
+
assert_equal '_a few emphasized words_', para.sub_quotes(para.buffer.join)
|
151
|
+
end
|
152
|
+
|
153
|
+
test 'multi-line constrained emphasized underline variation string' do
|
154
|
+
para = block_from_string(%Q{_a few\nemphasized words_})
|
155
|
+
assert_equal "<em>a few\nemphasized words</em>", para.sub_quotes(para.buffer.join)
|
156
|
+
end
|
157
|
+
|
158
|
+
test 'single-line constrained monospaced string' do
|
159
|
+
para = block_from_string(%q{`a few <\{monospaced\}> words`})
|
160
|
+
# NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
|
161
|
+
assert_equal '<tt>a few <{monospaced}> words</tt>', para.apply_normal_subs(para.buffer)
|
162
|
+
end
|
163
|
+
|
164
|
+
test 'escaped single-line constrained monospaced string' do
|
165
|
+
para = block_from_string(%q{\`a few <monospaced> words`})
|
166
|
+
# NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
|
167
|
+
assert_equal '`a few <monospaced> words`', para.apply_normal_subs(para.buffer)
|
168
|
+
end
|
169
|
+
|
170
|
+
test 'multi-line constrained monospaced string' do
|
171
|
+
para = block_from_string(%Q{`a few\n<\{monospaced\}> words`})
|
172
|
+
# NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
|
173
|
+
assert_equal "<tt>a few\n<{monospaced}> words</tt>", para.apply_normal_subs(para.buffer)
|
174
|
+
end
|
175
|
+
|
176
|
+
test 'single-line unconstrained strong chars' do
|
177
|
+
para = block_from_string(%q{**Git**Hub})
|
178
|
+
assert_equal '<strong>Git</strong>Hub', para.sub_quotes(para.buffer.join)
|
179
|
+
end
|
180
|
+
|
181
|
+
test 'escaped single-line unconstrained strong chars' do
|
182
|
+
para = block_from_string(%q{\**Git**Hub})
|
183
|
+
assert_equal '<strong>*Git</strong>*Hub', para.sub_quotes(para.buffer.join)
|
184
|
+
end
|
185
|
+
|
186
|
+
test 'multi-line unconstrained strong chars' do
|
187
|
+
para = block_from_string(%Q{**G\ni\nt\n**Hub})
|
188
|
+
assert_equal "<strong>G\ni\nt\n</strong>Hub", para.sub_quotes(para.buffer.join)
|
189
|
+
end
|
190
|
+
|
191
|
+
test 'unconstrained strong chars with inline asterisk' do
|
192
|
+
para = block_from_string(%q{**bl*ck**-eye})
|
193
|
+
assert_equal '<strong>bl*ck</strong>-eye', para.sub_quotes(para.buffer.join)
|
194
|
+
end
|
195
|
+
|
196
|
+
test 'unconstrained strong chars with role' do
|
197
|
+
para = block_from_string(%q{Git[blue]**Hub**})
|
198
|
+
assert_equal %q{Git<strong><span class="blue">Hub</span></strong>}, para.sub_quotes(para.buffer.join)
|
199
|
+
end
|
200
|
+
|
201
|
+
# TODO this is not the same result as AsciiDoc, though I don't understand why AsciiDoc gets what it gets
|
202
|
+
test 'escaped unconstrained strong chars with role' do
|
203
|
+
para = block_from_string(%q{Git\[blue]**Hub**})
|
204
|
+
assert_equal %q{Git[blue]<strong>*Hub</strong>*}, para.sub_quotes(para.buffer.join)
|
205
|
+
end
|
206
|
+
|
207
|
+
test 'single-line unconstrained emphasized chars' do
|
208
|
+
para = block_from_string(%q{__Git__Hub})
|
209
|
+
assert_equal '<em>Git</em>Hub', para.sub_quotes(para.buffer.join)
|
210
|
+
end
|
211
|
+
|
212
|
+
test 'escaped single-line unconstrained emphasized chars' do
|
213
|
+
para = block_from_string(%q{\__Git__Hub})
|
214
|
+
assert_equal '__Git__Hub', para.sub_quotes(para.buffer.join)
|
215
|
+
end
|
216
|
+
|
217
|
+
test 'multi-line unconstrained emphasized chars' do
|
218
|
+
para = block_from_string(%Q{__G\ni\nt\n__Hub})
|
219
|
+
assert_equal "<em>G\ni\nt\n</em>Hub", para.sub_quotes(para.buffer.join)
|
220
|
+
end
|
221
|
+
|
222
|
+
test 'unconstrained emphasis chars with role' do
|
223
|
+
para = block_from_string(%q{[gray]__Git__Hub})
|
224
|
+
assert_equal %q{<em><span class="gray">Git</span></em>Hub}, para.sub_quotes(para.buffer.join)
|
225
|
+
end
|
226
|
+
|
227
|
+
test 'escaped unconstrained emphasis chars with role' do
|
228
|
+
para = block_from_string(%q{\[gray]__Git__Hub})
|
229
|
+
assert_equal %q{[gray]__Git__Hub}, para.sub_quotes(para.buffer.join)
|
230
|
+
end
|
231
|
+
|
232
|
+
test 'single-line unconstrained monospaced chars' do
|
233
|
+
para = block_from_string(%q{Git++Hub++})
|
234
|
+
assert_equal 'Git<tt>Hub</tt>', para.sub_quotes(para.buffer.join)
|
235
|
+
end
|
236
|
+
|
237
|
+
test 'escaped single-line unconstrained monospaced chars' do
|
238
|
+
para = block_from_string(%q{Git\++Hub++})
|
239
|
+
assert_equal 'Git+<tt>Hub</tt>+', para.sub_quotes(para.buffer.join)
|
240
|
+
end
|
241
|
+
|
242
|
+
test 'multi-line unconstrained monospaced chars' do
|
243
|
+
para = block_from_string(%Q{Git++\nH\nu\nb++})
|
244
|
+
assert_equal "Git<tt>\nH\nu\nb</tt>", para.sub_quotes(para.buffer.join)
|
245
|
+
end
|
246
|
+
|
247
|
+
test 'single-line superscript chars' do
|
248
|
+
para = block_from_string(%q{x^2^ = x * x, e = mc^2^, there's a 1^st^ time for everything})
|
249
|
+
assert_equal 'x<sup>2</sup> = x * x, e = mc<sup>2</sup>, there\'s a 1<sup>st</sup> time for everything', para.sub_quotes(para.buffer.join)
|
250
|
+
end
|
251
|
+
|
252
|
+
test 'escaped single-line superscript chars' do
|
253
|
+
para = block_from_string(%q{x\^2^ = x * x})
|
254
|
+
assert_equal 'x^2^ = x * x', para.sub_quotes(para.buffer.join)
|
255
|
+
end
|
256
|
+
|
257
|
+
test 'multi-line superscript chars' do
|
258
|
+
para = block_from_string(%Q{x^(n\n+\n1)^})
|
259
|
+
assert_equal "x<sup>(n\n+\n1)</sup>", para.sub_quotes(para.buffer.join)
|
260
|
+
end
|
261
|
+
|
262
|
+
test 'single-line subscript chars' do
|
263
|
+
para = block_from_string(%q{H~2~O})
|
264
|
+
assert_equal 'H<sub>2</sub>O', para.sub_quotes(para.buffer.join)
|
265
|
+
end
|
266
|
+
|
267
|
+
test 'escaped single-line subscript chars' do
|
268
|
+
para = block_from_string(%q{H\~2~O})
|
269
|
+
assert_equal 'H~2~O', para.sub_quotes(para.buffer.join)
|
270
|
+
end
|
271
|
+
|
272
|
+
test 'multi-line subscript chars' do
|
273
|
+
para = block_from_string(%Q{project~ view\non\nGitHub~})
|
274
|
+
assert_equal "project<sub> view\non\nGitHub</sub>", para.sub_quotes(para.buffer.join)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context 'Macros' do
|
279
|
+
test 'a single-line link macro should be interpreted as a link' do
|
280
|
+
para = block_from_string('link:/home.html[]')
|
281
|
+
assert_equal %q{<a href="/home.html">/home.html</a>}, para.sub_macros(para.buffer.join)
|
282
|
+
end
|
283
|
+
|
284
|
+
test 'a single-line link macro with text should be interpreted as a link' do
|
285
|
+
para = block_from_string('link:/home.html[Home]')
|
286
|
+
assert_equal %q{<a href="/home.html">Home</a>}, para.sub_macros(para.buffer.join)
|
287
|
+
end
|
288
|
+
|
289
|
+
test 'a single-line raw url should be interpreted as a link' do
|
290
|
+
para = block_from_string('http://google.com')
|
291
|
+
assert_equal %q{<a href="http://google.com">http://google.com</a>}, para.sub_macros(para.buffer.join)
|
292
|
+
end
|
293
|
+
|
294
|
+
test 'a single-line raw url with text should be interpreted as a link' do
|
295
|
+
para = block_from_string('http://google.com[Google]')
|
296
|
+
assert_equal %q{<a href="http://google.com">Google</a>}, para.sub_macros(para.buffer.join)
|
297
|
+
end
|
298
|
+
|
299
|
+
test 'a multi-line raw url with text should be interpreted as a link' do
|
300
|
+
para = block_from_string("http://google.com[Google\nHomepage]")
|
301
|
+
assert_equal %{<a href="http://google.com">Google\nHomepage</a>}, para.sub_macros(para.buffer.join)
|
302
|
+
end
|
303
|
+
|
304
|
+
test 'a multi-line raw url with attribute as text should be interpreted as a link with resolved attribute' do
|
305
|
+
para = block_from_string("http://google.com[{google_homepage}]")
|
306
|
+
para.document.attributes['google_homepage'] = 'Google Homepage'
|
307
|
+
assert_equal %q{<a href="http://google.com">Google Homepage</a>}, para.sub_macros(para.buffer.join)
|
308
|
+
end
|
309
|
+
|
310
|
+
test 'a single-line escaped raw url should not be interpreted as a link' do
|
311
|
+
para = block_from_string('\http://google.com')
|
312
|
+
assert_equal %q{http://google.com}, para.sub_macros(para.buffer.join)
|
313
|
+
end
|
314
|
+
|
315
|
+
test 'a single-line image macro should be interpreted as an image' do
|
316
|
+
para = block_from_string('image:tiger.png[]')
|
317
|
+
assert_equal %{<span class="image">\n <img src="tiger.png" alt="tiger">\n</span>}, para.sub_macros(para.buffer.join)
|
318
|
+
end
|
319
|
+
|
320
|
+
test 'a single-line image macro with text should be interpreted as an image with alt text' do
|
321
|
+
para = block_from_string('image:tiger.png[Tiger]')
|
322
|
+
assert_equal %{<span class="image">\n <img src="tiger.png" alt="Tiger">\n</span>}, para.sub_macros(para.buffer.join)
|
323
|
+
end
|
324
|
+
|
325
|
+
test 'a single-line image macro with text and dimensions should be interpreted as an image with alt text and dimensions' do
|
326
|
+
para = block_from_string('image:tiger.png[Tiger, 200, 100]')
|
327
|
+
assert_equal %{<span class="image">\n <img src="tiger.png" alt="Tiger" width="200" height="100">\n</span>}, para.sub_macros(para.buffer.join)
|
328
|
+
end
|
329
|
+
|
330
|
+
test 'a single-line image macro with text and link should be interpreted as a linked image with alt text' do
|
331
|
+
para = block_from_string('image:tiger.png[Tiger, link="http://en.wikipedia.org/wiki/Tiger"]')
|
332
|
+
assert_equal %{<span class="image">\n <a class="image" href="http://en.wikipedia.org/wiki/Tiger"><img src="tiger.png" alt="Tiger"></a>\n</span>}, para.sub_macros(para.buffer.join)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
context 'Passthroughs' do
|
337
|
+
test 'collect inline triple plus passthroughs' do
|
338
|
+
para = block_from_string('+++<code>inline code</code>+++')
|
339
|
+
result = para.extract_passthroughs(para.buffer.join)
|
340
|
+
assert_equal "\x0" + '0' + "\x0", result
|
341
|
+
assert_equal 1, para.passthroughs.size
|
342
|
+
assert_equal '<code>inline code</code>', para.passthroughs.first[:text]
|
343
|
+
assert para.passthroughs.first[:subs].empty?
|
344
|
+
end
|
345
|
+
|
346
|
+
test 'collect multi-line inline triple plus passthroughs' do
|
347
|
+
para = block_from_string("+++<code>inline\ncode</code>+++")
|
348
|
+
result = para.extract_passthroughs(para.buffer.join)
|
349
|
+
assert_equal "\x0" + '0' + "\x0", result
|
350
|
+
assert_equal 1, para.passthroughs.size
|
351
|
+
assert_equal "<code>inline\ncode</code>", para.passthroughs.first[:text]
|
352
|
+
assert para.passthroughs.first[:subs].empty?
|
353
|
+
end
|
354
|
+
|
355
|
+
test 'collect inline double dollar passthroughs' do
|
356
|
+
para = block_from_string('$$<code>{code}</code>$$')
|
357
|
+
result = para.extract_passthroughs(para.buffer.join)
|
358
|
+
assert_equal "\x0" + '0' + "\x0", result
|
359
|
+
assert_equal 1, para.passthroughs.size
|
360
|
+
assert_equal '<code>{code}</code>', para.passthroughs.first[:text]
|
361
|
+
assert_equal [:specialcharacters], para.passthroughs.first[:subs]
|
362
|
+
end
|
363
|
+
|
364
|
+
test 'collect multi-line inline double dollar passthroughs' do
|
365
|
+
para = block_from_string("$$<code>\n{code}\n</code>$$")
|
366
|
+
result = para.extract_passthroughs(para.buffer.join)
|
367
|
+
assert_equal "\x0" + '0' + "\x0", result
|
368
|
+
assert_equal 1, para.passthroughs.size
|
369
|
+
assert_equal "<code>\n{code}\n</code>", para.passthroughs.first[:text]
|
370
|
+
assert_equal [:specialcharacters], para.passthroughs.first[:subs]
|
371
|
+
end
|
372
|
+
|
373
|
+
test 'collect passthroughs from inline pass macro' do
|
374
|
+
para = block_from_string(%Q{pass:specialcharacters,quotes[<code>['code'\\]</code>]})
|
375
|
+
result = para.extract_passthroughs(para.buffer.join)
|
376
|
+
assert_equal "\x0" + '0' + "\x0", result
|
377
|
+
assert_equal 1, para.passthroughs.size
|
378
|
+
assert_equal %q{<code>['code']</code>}, para.passthroughs.first[:text]
|
379
|
+
assert_equal [:specialcharacters, :quotes], para.passthroughs.first[:subs]
|
380
|
+
end
|
381
|
+
|
382
|
+
test 'collect multi-line passthroughs from inline pass macro' do
|
383
|
+
para = block_from_string(%Q{pass:specialcharacters,quotes[<code>['more\ncode'\\]</code>]})
|
384
|
+
result = para.extract_passthroughs(para.buffer.join)
|
385
|
+
assert_equal "\x0" + '0' + "\x0", result
|
386
|
+
assert_equal 1, para.passthroughs.size
|
387
|
+
assert_equal %Q{<code>['more\ncode']</code>}, para.passthroughs.first[:text]
|
388
|
+
assert_equal [:specialcharacters, :quotes], para.passthroughs.first[:subs]
|
389
|
+
end
|
390
|
+
|
391
|
+
test 'restore inline passthroughs without subs' do
|
392
|
+
para = block_from_string("\x0" + '0' + "\x0")
|
393
|
+
para.passthroughs << {:text => '<code>inline code</code>', :subs => []}
|
394
|
+
result = para.restore_passthroughs(para.buffer.join)
|
395
|
+
assert_equal '<code>inline code</code>', result
|
396
|
+
end
|
397
|
+
|
398
|
+
# TODO add two entries to ensure index lookup is working correctly (0 indx could be ambiguous)
|
399
|
+
test 'restore inline passthroughs with subs' do
|
400
|
+
para = block_from_string("\x0" + '0' + "\x0")
|
401
|
+
para.passthroughs << {:text => '<code>{code}</code>', :subs => [:specialcharacters]}
|
402
|
+
result = para.restore_passthroughs(para.buffer.join)
|
403
|
+
assert_equal '<code>{code}</code>', result
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
context 'Post replacements' do
|
408
|
+
test 'line break' do
|
409
|
+
para = block_from_string("First line +\nSecond line")
|
410
|
+
result = para.apply_subs(para.buffer, :post_replacements)
|
411
|
+
assert_equal "First line<br>\n", result.first
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|