asciidoctor 0.1.4 → 1.5.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +209 -25
- data/{LICENSE → LICENSE.adoc} +4 -3
- data/README.adoc +392 -395
- data/Rakefile +94 -137
- data/benchmark/benchmark.rb +127 -0
- data/benchmark/sample-data/mdbasics.adoc +334 -0
- data/bin/asciidoctor +5 -8
- data/bin/asciidoctor-safe +4 -8
- data/compat/asciidoc.conf +78 -11
- data/compat/font-awesome-3-compat.css +397 -0
- data/data/stylesheets/asciidoctor-default.css +399 -0
- data/data/stylesheets/coderay-asciidoctor.css +89 -0
- data/features/open_block.feature +92 -0
- data/features/pass_block.feature +66 -0
- data/features/step_definitions.rb +42 -0
- data/features/text_formatting.feature +55 -0
- data/features/xref.feature +116 -0
- data/lib/asciidoctor.rb +1155 -605
- data/lib/asciidoctor/abstract_block.rb +157 -71
- data/lib/asciidoctor/abstract_node.rb +150 -93
- data/lib/asciidoctor/attribute_list.rb +85 -90
- data/lib/asciidoctor/block.rb +51 -24
- data/lib/asciidoctor/callouts.rb +4 -7
- data/lib/asciidoctor/cli.rb +3 -0
- data/lib/asciidoctor/cli/invoker.rb +86 -76
- data/lib/asciidoctor/cli/options.rb +111 -61
- data/lib/asciidoctor/converter.rb +232 -0
- data/lib/asciidoctor/converter/base.rb +58 -0
- data/lib/asciidoctor/converter/composite.rb +66 -0
- data/lib/asciidoctor/converter/docbook45.rb +94 -0
- data/lib/asciidoctor/converter/docbook5.rb +684 -0
- data/lib/asciidoctor/converter/factory.rb +225 -0
- data/lib/asciidoctor/converter/html5.rb +1081 -0
- data/lib/asciidoctor/converter/template.rb +296 -0
- data/lib/asciidoctor/core_ext.rb +7 -0
- data/lib/asciidoctor/core_ext/object/nil_or_empty.rb +23 -0
- data/lib/asciidoctor/core_ext/string/chr.rb +6 -0
- data/lib/asciidoctor/core_ext/symbol/length.rb +6 -0
- data/lib/asciidoctor/document.rb +590 -304
- data/lib/asciidoctor/extensions.rb +1100 -308
- data/lib/asciidoctor/helpers.rb +109 -46
- data/lib/asciidoctor/inline.rb +16 -9
- data/lib/asciidoctor/list.rb +23 -15
- data/lib/asciidoctor/opal_ext.rb +4 -0
- data/lib/asciidoctor/opal_ext/comparable.rb +38 -0
- data/lib/asciidoctor/opal_ext/dir.rb +13 -0
- data/lib/asciidoctor/opal_ext/error.rb +2 -0
- data/lib/asciidoctor/opal_ext/file.rb +125 -0
- data/lib/asciidoctor/{lexer.rb → parser.rb} +646 -455
- data/lib/asciidoctor/path_resolver.rb +141 -77
- data/lib/asciidoctor/reader.rb +257 -187
- data/lib/asciidoctor/section.rb +12 -16
- data/lib/asciidoctor/stylesheets.rb +91 -0
- data/lib/asciidoctor/substitutors.rb +1548 -0
- data/lib/asciidoctor/table.rb +73 -57
- data/lib/asciidoctor/timings.rb +39 -0
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +22 -14
- data/man/asciidoctor.adoc +18 -10
- data/test/attributes_test.rb +314 -14
- data/test/blocks_test.rb +763 -118
- data/test/converter_test.rb +352 -0
- data/test/document_test.rb +518 -199
- data/test/extensions_test.rb +273 -103
- data/test/fixtures/asciidoc_index.txt +27 -13
- data/test/fixtures/basic-docinfo.xml +1 -1
- data/test/fixtures/chapter-a.adoc +3 -0
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
- data/test/fixtures/docinfo.xml +1 -1
- data/test/fixtures/include-file.asciidoc +2 -0
- data/test/fixtures/master.adoc +5 -0
- data/test/invoker_test.rb +173 -61
- data/test/links_test.rb +97 -21
- data/test/lists_test.rb +181 -22
- data/test/options_test.rb +86 -2
- data/test/paragraphs_test.rb +47 -5
- data/test/{lexer_test.rb → parser_test.rb} +128 -57
- data/test/paths_test.rb +36 -1
- data/test/preamble_test.rb +25 -17
- data/test/reader_test.rb +404 -249
- data/test/sections_test.rb +623 -58
- data/test/substitutions_test.rb +609 -132
- data/test/tables_test.rb +198 -24
- data/test/test_helper.rb +101 -31
- data/test/text_test.rb +88 -31
- metadata +160 -64
- data/Gemfile +0 -12
- data/Guardfile +0 -18
- data/asciidoctor.gemspec +0 -143
- data/lib/asciidoctor/backends/_stylesheets.rb +0 -466
- data/lib/asciidoctor/backends/base_template.rb +0 -114
- data/lib/asciidoctor/backends/docbook45.rb +0 -774
- data/lib/asciidoctor/backends/docbook5.rb +0 -103
- data/lib/asciidoctor/backends/html5.rb +0 -1214
- data/lib/asciidoctor/renderer.rb +0 -259
- data/lib/asciidoctor/substituters.rb +0 -1083
- data/test/fixtures/asciidoc.txt +0 -105
- data/test/fixtures/ascshort.txt +0 -32
- data/test/fixtures/list_elements.asciidoc +0 -10
- data/test/renderer_test.rb +0 -162
@@ -10,7 +10,7 @@ module Asciidoctor
|
|
10
10
|
# attrlist = Asciidoctor::AttributeList.new('astyle')
|
11
11
|
#
|
12
12
|
# attrlist.parse
|
13
|
-
# => {0 => 'astyle'}
|
13
|
+
# => {0 => 'astyle'}
|
14
14
|
#
|
15
15
|
# attrlist.rekey(['style'])
|
16
16
|
# => {'style' => 'astyle'}
|
@@ -18,55 +18,58 @@ module Asciidoctor
|
|
18
18
|
# attrlist = Asciidoctor::AttributeList.new('quote, Famous Person, Famous Book (2001)')
|
19
19
|
#
|
20
20
|
# attrlist.parse(['style', 'attribution', 'citetitle'])
|
21
|
-
# => {'style' => 'quote', 'attribution' => 'Famous Person', 'citetitle' => 'Famous Book (2001)'}
|
21
|
+
# => {'style' => 'quote', 'attribution' => 'Famous Person', 'citetitle' => 'Famous Book (2001)'}
|
22
22
|
#
|
23
23
|
class AttributeList
|
24
24
|
|
25
25
|
# Public: Regular expressions for detecting the boundary of a value
|
26
|
-
|
26
|
+
BoundaryRxs = {
|
27
27
|
'"' => /.*?[^\\](?=")/,
|
28
28
|
'\'' => /.*?[^\\](?=')/,
|
29
29
|
',' => /.*?(?=[ \t]*(,|$))/
|
30
30
|
}
|
31
31
|
|
32
32
|
# Public: Regular expressions for unescaping quoted characters
|
33
|
-
|
34
|
-
'
|
35
|
-
'
|
33
|
+
EscapedQuoteRxs = {
|
34
|
+
'"' => /\\"/,
|
35
|
+
'\'' => /\\'/
|
36
36
|
}
|
37
37
|
|
38
|
+
# Public: A regular expression for an attribute name
|
39
|
+
# TODO named attributes cannot contain dash characters
|
40
|
+
NameRx = /[A-Za-z:_][A-Za-z:_\-.]*/
|
41
|
+
|
42
|
+
BlankRx = /[ \t]+/
|
43
|
+
|
38
44
|
# Public: Regular expressions for skipping blanks and delimiters
|
39
|
-
|
40
|
-
:blank =>
|
45
|
+
SkipRxs = {
|
46
|
+
:blank => BlankRx,
|
41
47
|
',' => /[ \t]*(,|$)/
|
42
48
|
}
|
43
49
|
|
44
|
-
|
45
|
-
# TODO named attributes cannot contain dash characters
|
46
|
-
NAME_PATTERN = /[A-Za-z:_][A-Za-z:_\-\.]*/
|
47
|
-
|
48
|
-
def initialize(source, block = nil, quotes = ['\'', '"'], delimiter = ',', escape_char = '\\')
|
50
|
+
def initialize source, block = nil, delimiter = ','
|
49
51
|
@scanner = ::StringScanner.new source
|
50
52
|
@block = block
|
51
|
-
@quotes = quotes
|
52
|
-
@escape_char = escape_char
|
53
53
|
@delimiter = delimiter
|
54
|
+
@delimiter_skip_pattern = SkipRxs[delimiter]
|
55
|
+
@delimiter_boundary_pattern = BoundaryRxs[delimiter]
|
54
56
|
@attributes = nil
|
55
57
|
end
|
56
58
|
|
57
|
-
def parse_into
|
58
|
-
attributes.update(parse
|
59
|
+
def parse_into attributes, posattrs = []
|
60
|
+
attributes.update(parse posattrs)
|
59
61
|
end
|
60
62
|
|
61
|
-
def parse
|
62
|
-
return
|
63
|
+
def parse posattrs = []
|
64
|
+
# return if already parsed
|
65
|
+
return @attributes if @attributes
|
63
66
|
|
64
67
|
@attributes = {}
|
65
|
-
#
|
68
|
+
# QUESTION do we want to store the attribute list as the zero-index attribute?
|
66
69
|
#attributes[0] = @scanner.string
|
67
70
|
index = 0
|
68
71
|
|
69
|
-
while parse_attribute
|
72
|
+
while parse_attribute index, posattrs
|
70
73
|
break if @scanner.eos?
|
71
74
|
skip_delimiter
|
72
75
|
index += 1
|
@@ -75,144 +78,136 @@ class AttributeList
|
|
75
78
|
@attributes
|
76
79
|
end
|
77
80
|
|
78
|
-
def rekey
|
79
|
-
AttributeList.rekey
|
81
|
+
def rekey posattrs
|
82
|
+
AttributeList.rekey @attributes, posattrs
|
80
83
|
end
|
81
84
|
|
82
|
-
def self.rekey
|
85
|
+
def self.rekey attributes, pos_attrs
|
83
86
|
pos_attrs.each_with_index do |key, index|
|
84
|
-
next
|
87
|
+
next unless key
|
85
88
|
pos = index + 1
|
86
|
-
|
89
|
+
if (val = attributes[pos])
|
90
|
+
# QUESTION should we delete the positional key?
|
87
91
|
attributes[key] = val
|
88
|
-
#QUESTION should we delete the positional key?
|
89
|
-
#attributes.delete pos
|
90
92
|
end
|
91
93
|
end
|
92
94
|
|
93
95
|
attributes
|
94
96
|
end
|
95
97
|
|
96
|
-
def parse_attribute
|
98
|
+
def parse_attribute index = 0, pos_attrs = []
|
97
99
|
single_quoted_value = false
|
98
100
|
skip_blank
|
99
|
-
|
100
|
-
|
101
|
-
|
101
|
+
# example: "quote"
|
102
|
+
if (first = @scanner.peek(1)) == '"'
|
103
|
+
name = parse_attribute_value @scanner.get_byte
|
102
104
|
value = nil
|
105
|
+
# example: 'quote'
|
106
|
+
elsif first == '\''
|
103
107
|
name = parse_attribute_value @scanner.get_byte
|
104
|
-
|
105
|
-
|
106
|
-
end
|
108
|
+
value = nil
|
109
|
+
single_quoted_value = true
|
107
110
|
else
|
108
111
|
name = scan_name
|
109
112
|
|
110
113
|
skipped = 0
|
111
114
|
c = nil
|
112
115
|
if @scanner.eos?
|
113
|
-
|
114
|
-
return false
|
115
|
-
end
|
116
|
+
return false unless name
|
116
117
|
else
|
117
118
|
skipped = skip_blank || 0
|
118
119
|
c = @scanner.get_byte
|
119
120
|
end
|
120
121
|
|
121
122
|
# example: quote
|
122
|
-
if c
|
123
|
+
if !c || c == @delimiter
|
123
124
|
value = nil
|
124
125
|
# example: Sherlock Holmes || =foo=
|
125
|
-
elsif c != '=' || name
|
126
|
-
|
127
|
-
name = '' if name.nil?
|
128
|
-
name += ' ' * skipped + c
|
129
|
-
name += remainder unless remainder.nil?
|
126
|
+
elsif c != '=' || !name
|
127
|
+
name = %(#{name}#{' ' * skipped}#{c}#{scan_to_delimiter})
|
130
128
|
value = nil
|
131
129
|
else
|
132
130
|
skip_blank
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
else
|
137
|
-
c = @scanner.get_byte
|
138
|
-
|
139
|
-
# example: foo="bar" || foo='bar' || foo="ba\"zaar" || foo='ba\'zaar' || foo='ba"zaar' (all spaces ignored)
|
140
|
-
if @quotes.include? c
|
131
|
+
if @scanner.peek(1)
|
132
|
+
# example: foo="bar" || foo="ba\"zaar"
|
133
|
+
if (c = @scanner.get_byte) == '"'
|
141
134
|
value = parse_attribute_value c
|
142
|
-
|
143
|
-
|
144
|
-
|
135
|
+
# example: foo='bar' || foo='ba\'zaar' || foo='ba"zaar'
|
136
|
+
elsif c == '\''
|
137
|
+
value = parse_attribute_value c
|
138
|
+
single_quoted_value = true
|
139
|
+
# example: foo=,
|
140
|
+
elsif c == @delimiter
|
141
|
+
value = nil
|
145
142
|
# example: foo=bar (all spaces ignored)
|
146
|
-
|
147
|
-
value = c
|
143
|
+
else
|
144
|
+
value = %(#{c}#{scan_to_delimiter})
|
145
|
+
return true if value == 'None'
|
148
146
|
end
|
149
147
|
end
|
150
148
|
end
|
151
149
|
end
|
152
150
|
|
153
|
-
if value
|
154
|
-
resolved_name = single_quoted_value && !@block.nil? ? @block.apply_normal_subs(name) : name
|
155
|
-
if !(pos_name = pos_attrs[index]).nil?
|
156
|
-
@attributes[pos_name] = resolved_name
|
157
|
-
else
|
158
|
-
#@attributes[index + 1] = resolved_name
|
159
|
-
end
|
160
|
-
# not sure if we want to always assign the positional key
|
161
|
-
@attributes[index + 1] = resolved_name
|
162
|
-
# not sure if I want this assignment or not
|
163
|
-
#@attributes[resolved_name] = nil
|
164
|
-
else
|
165
|
-
resolved_value = value
|
151
|
+
if value
|
166
152
|
# example: options="opt1,opt2,opt3"
|
167
153
|
# opts is an alias for options
|
168
|
-
|
154
|
+
case name
|
155
|
+
when 'options', 'opts'
|
169
156
|
name = 'options'
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
157
|
+
value.split(',').each {|o| @attributes[%(#{o.strip}-option)] = '' }
|
158
|
+
@attributes[name] = value
|
159
|
+
when 'title'
|
160
|
+
@attributes[name] = value
|
161
|
+
else
|
162
|
+
@attributes[name] = single_quoted_value && !value.empty? && @block ? (@block.apply_normal_subs value) : value
|
163
|
+
end
|
164
|
+
else
|
165
|
+
resolved_name = single_quoted_value && !name.empty? && @block ? (@block.apply_normal_subs name) : name
|
166
|
+
if (pos_name = pos_attrs[index])
|
167
|
+
@attributes[pos_name] = resolved_name
|
175
168
|
end
|
176
|
-
|
169
|
+
# QUESTION should we always assign the positional key?
|
170
|
+
@attributes[index + 1] = resolved_name
|
171
|
+
# QUESTION should we assign the resolved name as an attribute?
|
172
|
+
#@attributes[resolved_name] = nil
|
177
173
|
end
|
178
174
|
|
179
175
|
true
|
180
176
|
end
|
181
177
|
|
182
|
-
def parse_attribute_value
|
178
|
+
def parse_attribute_value quote
|
183
179
|
# empty quoted value
|
184
180
|
if @scanner.peek(1) == quote
|
185
|
-
@scanner.get_byte
|
181
|
+
@scanner.get_byte
|
186
182
|
return ''
|
187
183
|
end
|
188
184
|
|
189
|
-
value = scan_to_quote quote
|
190
|
-
if value.nil?
|
191
|
-
quote + scan_to_delimiter
|
192
|
-
else
|
185
|
+
if (value = scan_to_quote quote)
|
193
186
|
@scanner.get_byte
|
194
|
-
value.gsub
|
187
|
+
value.gsub EscapedQuoteRxs[quote], quote
|
188
|
+
else
|
189
|
+
%(#{quote}#{scan_to_delimiter})
|
195
190
|
end
|
196
191
|
end
|
197
192
|
|
198
193
|
def skip_blank
|
199
|
-
@scanner.skip
|
194
|
+
@scanner.skip BlankRx
|
200
195
|
end
|
201
196
|
|
202
197
|
def skip_delimiter
|
203
|
-
@scanner.skip
|
198
|
+
@scanner.skip @delimiter_skip_pattern
|
204
199
|
end
|
205
200
|
|
206
201
|
def scan_name
|
207
|
-
@scanner.scan
|
202
|
+
@scanner.scan NameRx
|
208
203
|
end
|
209
204
|
|
210
205
|
def scan_to_delimiter
|
211
|
-
@scanner.scan
|
206
|
+
@scanner.scan @delimiter_boundary_pattern
|
212
207
|
end
|
213
208
|
|
214
|
-
def scan_to_quote
|
215
|
-
@scanner.scan
|
209
|
+
def scan_to_quote quote
|
210
|
+
@scanner.scan BoundaryRxs[quote]
|
216
211
|
end
|
217
212
|
|
218
213
|
end
|
data/lib/asciidoctor/block.rb
CHANGED
@@ -8,6 +8,20 @@ module Asciidoctor
|
|
8
8
|
# => "<em>This</em> is a <test>"
|
9
9
|
class Block < AbstractBlock
|
10
10
|
|
11
|
+
DEFAULT_CONTENT_MODEL = ::Hash.new(:simple).merge({
|
12
|
+
# TODO should probably fill in all known blocks
|
13
|
+
:audio => :empty,
|
14
|
+
:image => :empty,
|
15
|
+
:listing => :verbatim,
|
16
|
+
:literal => :verbatim,
|
17
|
+
:stem => :raw,
|
18
|
+
:open => :compound,
|
19
|
+
:page_break => :empty,
|
20
|
+
:pass => :raw,
|
21
|
+
:thematic_break => :empty,
|
22
|
+
:video => :empty
|
23
|
+
})
|
24
|
+
|
11
25
|
# Public: Create alias for context to be consistent w/ AsciiDoc
|
12
26
|
alias :blockname :context
|
13
27
|
|
@@ -25,31 +39,31 @@ class Block < AbstractBlock
|
|
25
39
|
# * :source a String or Array of raw source for this Block. (default: nil)
|
26
40
|
#--
|
27
41
|
# QUESTION should we store source_data as lines for blocks that have compound content models?
|
28
|
-
def initialize
|
29
|
-
super
|
30
|
-
@content_model = opts
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
if ::Asciidoctor::FORCE_ENCODING
|
39
|
-
@lines = raw_source.lines.map {|line| "#{line.rstrip.force_encoding(::Encoding::UTF_8)}\n" }
|
42
|
+
def initialize parent, context, opts = {}
|
43
|
+
super
|
44
|
+
@content_model = opts[:content_model] || DEFAULT_CONTENT_MODEL[context]
|
45
|
+
if opts.has_key? :subs
|
46
|
+
# FIXME this is a bit funky
|
47
|
+
# we have to be defensive to avoid lock_in_subs wiping out the override
|
48
|
+
if !(subs = opts[:subs]) || (subs.is_a? ::Array)
|
49
|
+
@subs = subs || []
|
50
|
+
@default_subs = @subs.dup
|
51
|
+
@attributes.delete('subs')
|
40
52
|
else
|
41
|
-
@
|
42
|
-
end
|
43
|
-
if (last = @lines.pop)
|
44
|
-
@lines.push last.chomp
|
53
|
+
@attributes['subs'] = %(#{subs})
|
45
54
|
end
|
55
|
+
end
|
56
|
+
if !(raw_source = opts[:source])
|
57
|
+
@lines = []
|
58
|
+
elsif raw_source.is_a? ::String
|
59
|
+
@lines = Helpers.normalize_lines_from_string raw_source
|
46
60
|
else
|
47
61
|
@lines = raw_source.dup
|
48
62
|
end
|
49
63
|
end
|
50
64
|
|
51
|
-
# Public: Get
|
52
|
-
#
|
65
|
+
# Public: Get the converted result of the child blocks by converting the
|
66
|
+
# children appropriate to content model that this block supports.
|
53
67
|
#
|
54
68
|
# Examples
|
55
69
|
#
|
@@ -62,10 +76,23 @@ class Block < AbstractBlock
|
|
62
76
|
case @content_model
|
63
77
|
when :compound
|
64
78
|
super
|
65
|
-
when :simple
|
66
|
-
apply_subs
|
79
|
+
when :simple
|
80
|
+
apply_subs(@lines * EOL, @subs)
|
81
|
+
when :verbatim, :raw
|
82
|
+
#((apply_subs @lines.join(EOL), @subs).sub StripLineWiseRx, '\1')
|
83
|
+
|
84
|
+
# QUESTION could we use strip here instead of popping empty lines?
|
85
|
+
# maybe apply_subs can know how to strip whitespace?
|
86
|
+
result = apply_subs @lines, @subs
|
87
|
+
if result.size < 2
|
88
|
+
result[0]
|
89
|
+
else
|
90
|
+
result.shift while (first = result[0]) && first.rstrip.empty?
|
91
|
+
result.pop while (last = result[-1]) && last.rstrip.empty?
|
92
|
+
result * EOL
|
93
|
+
end
|
67
94
|
else
|
68
|
-
warn
|
95
|
+
warn %(Unknown content model '#{@content_model}' for block: #{to_s}) unless @content_model == :empty
|
69
96
|
nil
|
70
97
|
end
|
71
98
|
end
|
@@ -75,12 +102,12 @@ class Block < AbstractBlock
|
|
75
102
|
# Returns the a String containing the lines joined together or nil if there
|
76
103
|
# are no lines
|
77
104
|
def source
|
78
|
-
@lines
|
105
|
+
@lines * EOL
|
79
106
|
end
|
80
107
|
|
81
108
|
def to_s
|
82
|
-
content_summary = @content_model == :compound ? %(
|
83
|
-
%(
|
109
|
+
content_summary = @content_model == :compound ? %(blocks: #{@blocks.size}) : %(lines: #{@lines.size})
|
110
|
+
%(#<#{self.class}@#{object_id} {context: #{@context.inspect}, content_model: #{@content_model.inspect}, style: #{@style.inspect}, #{content_summary}}>)
|
84
111
|
end
|
85
112
|
end
|
86
113
|
end
|
data/lib/asciidoctor/callouts.rb
CHANGED
@@ -36,8 +36,8 @@ class Callouts
|
|
36
36
|
# Public: Get the next callout index in the document
|
37
37
|
#
|
38
38
|
# Reads the next callout index in the document and advances the pointer.
|
39
|
-
# This method is used during
|
40
|
-
# callout that was generated during
|
39
|
+
# This method is used during conversion to retrieve the unique id of the
|
40
|
+
# callout that was generated during parsing.
|
41
41
|
#
|
42
42
|
# Returns The unique String id of the next callout in the document
|
43
43
|
def read_next_id
|
@@ -60,10 +60,7 @@ class Callouts
|
|
60
60
|
#
|
61
61
|
# Returns A space-separated String of callout ids associated with the specified list item
|
62
62
|
def callout_ids(li_ordinal)
|
63
|
-
current_list.
|
64
|
-
collector << element[:id] if element[:ordinal] == li_ordinal
|
65
|
-
collector
|
66
|
-
} * ' '
|
63
|
+
current_list.map {|element| element[:ordinal] == li_ordinal ? %(#{element[:id]} ) : nil }.join.chop
|
67
64
|
end
|
68
65
|
|
69
66
|
# Public: The current list for which callouts are being collected
|
@@ -89,7 +86,7 @@ class Callouts
|
|
89
86
|
end
|
90
87
|
|
91
88
|
# Public: Rewind the list index pointer, intended to be used when switching
|
92
|
-
# from the parsing to
|
89
|
+
# from the parsing to conversion phase.
|
93
90
|
#
|
94
91
|
# Returns nothing
|
95
92
|
def rewind
|
@@ -12,100 +12,110 @@ module Asciidoctor
|
|
12
12
|
@err = nil
|
13
13
|
@code = 0
|
14
14
|
options = options.flatten
|
15
|
-
if
|
16
|
-
@options =
|
17
|
-
elsif
|
15
|
+
if (first_option = options[0]).is_a?(Cli::Options)
|
16
|
+
@options = first_option
|
17
|
+
elsif first_option.is_a?(::Hash)
|
18
18
|
@options = Cli::Options.new(options)
|
19
19
|
else
|
20
|
-
|
21
|
-
|
22
|
-
if @options.is_a?(Integer)
|
23
|
-
@code = @options
|
20
|
+
if (result = Cli::Options.parse! options).is_a? ::Integer
|
21
|
+
@code = result
|
24
22
|
@options = nil
|
23
|
+
else
|
24
|
+
@options = result
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
29
|
def invoke!
|
30
|
-
|
31
|
-
|
32
|
-
begin
|
33
|
-
opts = {}
|
34
|
-
profile = false
|
35
|
-
infiles = []
|
36
|
-
outfile = nil
|
37
|
-
tofile = nil
|
38
|
-
@options.map {|k, v|
|
39
|
-
case k
|
40
|
-
when :input_files
|
41
|
-
infiles = v
|
42
|
-
when :output_file
|
43
|
-
outfile = v
|
44
|
-
when :destination_dir
|
45
|
-
#opts[:to_dir] = File.expand_path(v) unless v.nil?
|
46
|
-
opts[:to_dir] = v unless v.nil?
|
47
|
-
when :attributes
|
48
|
-
opts[:attributes] = v.dup
|
49
|
-
when :verbose
|
50
|
-
profile = true if v
|
51
|
-
when :trace
|
52
|
-
# currently, nothing
|
53
|
-
else
|
54
|
-
opts[k] = v unless v.nil?
|
55
|
-
end
|
56
|
-
}
|
30
|
+
old_verbose = -1
|
31
|
+
return unless @options
|
57
32
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
33
|
+
old_verbose = $VERBOSE
|
34
|
+
case @options[:verbose]
|
35
|
+
when 0
|
36
|
+
$VERBOSE = nil
|
37
|
+
when 1
|
38
|
+
$VERBOSE = false
|
39
|
+
when 2
|
40
|
+
$VERBOSE = true
|
41
|
+
end
|
64
42
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
43
|
+
opts = {}
|
44
|
+
infiles = []
|
45
|
+
outfile = nil
|
46
|
+
tofile = nil
|
47
|
+
@options.map do |key, val|
|
48
|
+
case key
|
49
|
+
when :input_files
|
50
|
+
infiles = val
|
51
|
+
when :output_file
|
52
|
+
outfile = val
|
53
|
+
when :destination_dir
|
54
|
+
opts[:to_dir] = val if val
|
55
|
+
when :attributes
|
56
|
+
# NOTE processor will dup attributes internally
|
57
|
+
opts[:attributes] = val
|
58
|
+
when :trace
|
59
|
+
# currently, nothing
|
71
60
|
else
|
72
|
-
|
73
|
-
# automatically calculate outfile based on infile
|
74
|
-
opts[:in_place] = true unless opts.has_key? :to_dir
|
75
|
-
opts[:mkdirs] = true
|
61
|
+
opts[key] = val unless val.nil?
|
76
62
|
end
|
63
|
+
end
|
77
64
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
65
|
+
if infiles.size == 1 && infiles[0] == '-'
|
66
|
+
# allows use of block to supply stdin, particularly useful for tests
|
67
|
+
inputs = [block_given? ? yield : STDIN]
|
68
|
+
else
|
69
|
+
inputs = infiles.map {|infile| ::File.new infile, 'r'}
|
70
|
+
end
|
84
71
|
|
85
|
-
|
86
|
-
|
72
|
+
# NOTE if infile is stdin, default to outfile as stout
|
73
|
+
if outfile == '-' || (!outfile && infiles.size == 1 && infiles[0] == '-')
|
74
|
+
tofile = (@out || $stdout)
|
75
|
+
elsif outfile
|
76
|
+
tofile = outfile
|
77
|
+
opts[:mkdirs] = true
|
78
|
+
else
|
79
|
+
# automatically calculate outfile based on infile unless to_dir is set
|
80
|
+
tofile = nil
|
81
|
+
opts[:mkdirs] = true
|
82
|
+
end
|
87
83
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
84
|
+
show_timings = @options[:timings]
|
85
|
+
inputs.each do |input|
|
86
|
+
# NOTE processor will dup options and attributes internally
|
87
|
+
input_opts = tofile.nil? ? opts : opts.merge(:to_file => tofile)
|
88
|
+
if show_timings
|
89
|
+
timings = Timings.new
|
90
|
+
@documents << ::Asciidoctor.convert(input, input_opts.merge(:timings => timings))
|
91
|
+
timings.print_report((@err || $stderr), ((input.respond_to? :path) ? input.path : '-'))
|
92
|
+
else
|
93
|
+
@documents << ::Asciidoctor.convert(input, input_opts)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
rescue ::Exception => e
|
97
|
+
if ::SignalException === e
|
98
|
+
@code = e.signo
|
99
|
+
# add extra endline if Ctrl+C is used
|
100
|
+
(@err || $stderr).puts if ::Interrupt === e
|
101
|
+
else
|
102
|
+
@code = (e.respond_to? :status) ? e.status : 1
|
103
|
+
if @options[:trace]
|
104
|
+
raise e
|
105
|
+
else
|
106
|
+
err = (@err || $stderr)
|
107
|
+
err.print %(#{e.class}: ) if ::RuntimeError === e
|
108
|
+
err.puts e.message
|
109
|
+
err.puts ' Use --trace for backtrace'
|
96
110
|
end
|
97
|
-
rescue Exception => e
|
98
|
-
raise e if @options[:trace] || SystemExit === e
|
99
|
-
err = (@err || $stderr)
|
100
|
-
err.print "#{e.class}: " if e.class != RuntimeError
|
101
|
-
err.puts e.message
|
102
|
-
err.puts ' Use --trace for backtrace'
|
103
|
-
@code = 1
|
104
111
|
end
|
112
|
+
nil
|
113
|
+
ensure
|
114
|
+
$VERBOSE = old_verbose unless old_verbose == -1
|
105
115
|
end
|
106
116
|
|
107
117
|
def document
|
108
|
-
@documents
|
118
|
+
@documents[0]
|
109
119
|
end
|
110
120
|
|
111
121
|
def redirect_streams(out, err = nil)
|
@@ -114,11 +124,11 @@ module Asciidoctor
|
|
114
124
|
end
|
115
125
|
|
116
126
|
def read_output
|
117
|
-
|
127
|
+
@out ? @out.string : ''
|
118
128
|
end
|
119
129
|
|
120
130
|
def read_error
|
121
|
-
|
131
|
+
@err ? @err.string : ''
|
122
132
|
end
|
123
133
|
|
124
134
|
def reset_streams
|