asciidoctor 2.0.10 → 2.0.11
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 +4 -4
- data/CHANGELOG.adoc +89 -5
- data/LICENSE +1 -1
- data/README-de.adoc +4 -4
- data/README-fr.adoc +4 -4
- data/README-jp.adoc +4 -4
- data/README-zh_CN.adoc +6 -6
- data/README.adoc +14 -10
- data/asciidoctor.gemspec +3 -3
- data/data/locale/attributes-ar.adoc +4 -3
- data/data/locale/attributes-bg.adoc +4 -3
- data/data/locale/attributes-ca.adoc +6 -5
- data/data/locale/attributes-cs.adoc +4 -3
- data/data/locale/attributes-da.adoc +6 -5
- data/data/locale/attributes-de.adoc +4 -4
- data/data/locale/attributes-en.adoc +4 -4
- data/data/locale/attributes-es.adoc +6 -5
- data/data/locale/attributes-fa.adoc +4 -3
- data/data/locale/attributes-fi.adoc +4 -3
- data/data/locale/attributes-fr.adoc +6 -5
- data/data/locale/attributes-hu.adoc +4 -3
- data/data/locale/attributes-id.adoc +4 -3
- data/data/locale/attributes-it.adoc +4 -3
- data/data/locale/attributes-ja.adoc +4 -3
- data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
- data/data/locale/attributes-nb.adoc +4 -3
- data/data/locale/attributes-nl.adoc +4 -3
- data/data/locale/attributes-nn.adoc +4 -3
- data/data/locale/attributes-pl.adoc +8 -7
- data/data/locale/attributes-pt.adoc +6 -5
- data/data/locale/attributes-pt_BR.adoc +6 -5
- data/data/locale/attributes-ro.adoc +4 -3
- data/data/locale/attributes-ru.adoc +6 -5
- data/data/locale/attributes-sr.adoc +4 -4
- data/data/locale/attributes-sr_Latn.adoc +4 -4
- data/data/locale/attributes-sv.adoc +4 -4
- data/data/locale/attributes-tr.adoc +4 -3
- data/data/locale/attributes-uk.adoc +6 -5
- data/data/locale/attributes-zh_CN.adoc +4 -3
- data/data/locale/attributes-zh_TW.adoc +4 -3
- data/data/stylesheets/asciidoctor-default.css +22 -20
- data/lib/asciidoctor.rb +33 -7
- data/lib/asciidoctor/abstract_block.rb +9 -4
- data/lib/asciidoctor/abstract_node.rb +16 -6
- data/lib/asciidoctor/attribute_list.rb +59 -67
- data/lib/asciidoctor/cli/invoker.rb +2 -0
- data/lib/asciidoctor/cli/options.rb +3 -3
- data/lib/asciidoctor/convert.rb +167 -162
- data/lib/asciidoctor/converter.rb +13 -12
- data/lib/asciidoctor/converter/docbook5.rb +3 -7
- data/lib/asciidoctor/converter/html5.rb +59 -42
- data/lib/asciidoctor/converter/manpage.rb +12 -11
- data/lib/asciidoctor/converter/template.rb +3 -0
- data/lib/asciidoctor/document.rb +23 -38
- data/lib/asciidoctor/extensions.rb +2 -2
- data/lib/asciidoctor/helpers.rb +17 -9
- data/lib/asciidoctor/load.rb +101 -101
- data/lib/asciidoctor/parser.rb +26 -23
- data/lib/asciidoctor/path_resolver.rb +14 -12
- data/lib/asciidoctor/reader.rb +14 -7
- data/lib/asciidoctor/rx.rb +5 -4
- data/lib/asciidoctor/substitutors.rb +57 -38
- data/lib/asciidoctor/syntax_highlighter.rb +8 -5
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +1 -1
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +12 -4
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +7 -4
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +2 -3
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +15 -7
- data/lib/asciidoctor/table.rb +49 -20
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +6 -6
- data/man/asciidoctor.adoc +3 -3
- metadata +8 -8
@@ -22,19 +22,20 @@ module Asciidoctor
|
|
22
22
|
# => { 'style' => 'quote', 'attribution' => 'Famous Person', 'citetitle' => 'Famous Book (2001)' }
|
23
23
|
#
|
24
24
|
class AttributeList
|
25
|
-
BACKSLASH = '\\'
|
26
25
|
APOS = '\''
|
26
|
+
BACKSLASH = '\\'
|
27
|
+
QUOT = '"'
|
27
28
|
|
28
29
|
# Public: Regular expressions for detecting the boundary of a value
|
29
30
|
BoundaryRxs = {
|
30
|
-
|
31
|
+
QUOT => /.*?[^\\](?=")/,
|
31
32
|
APOS => /.*?[^\\](?=')/,
|
32
33
|
',' => /.*?(?=[ \t]*(,|$))/
|
33
34
|
}
|
34
35
|
|
35
36
|
# Public: Regular expressions for unescaping quoted characters
|
36
37
|
EscapedQuotes = {
|
37
|
-
|
38
|
+
QUOT => '\\"',
|
38
39
|
APOS => '\\\''
|
39
40
|
}
|
40
41
|
|
@@ -45,7 +46,9 @@ class AttributeList
|
|
45
46
|
BlankRx = /[ \t]+/
|
46
47
|
|
47
48
|
# Public: Regular expressions for skipping delimiters
|
48
|
-
SkipRxs = {
|
49
|
+
SkipRxs = {
|
50
|
+
',' => /[ \t]*(,|$)/
|
51
|
+
}
|
49
52
|
|
50
53
|
def initialize source, block = nil, delimiter = ','
|
51
54
|
@scanner = ::StringScanner.new source
|
@@ -65,8 +68,6 @@ class AttributeList
|
|
65
68
|
return @attributes if @attributes
|
66
69
|
|
67
70
|
@attributes = {}
|
68
|
-
# QUESTION do we want to store the attribute list as the zero-index attribute?
|
69
|
-
#attributes[0] = @scanner.string
|
70
71
|
index = 0
|
71
72
|
|
72
73
|
while parse_attribute index, positional_attrs
|
@@ -83,75 +84,73 @@ class AttributeList
|
|
83
84
|
end
|
84
85
|
|
85
86
|
def self.rekey attributes, positional_attrs
|
86
|
-
|
87
|
-
|
88
|
-
index += 1
|
89
|
-
if (val = attributes[index])
|
87
|
+
positional_attrs.each_with_index do |key, index|
|
88
|
+
if key && (val = attributes[index + 1])
|
90
89
|
# QUESTION should we delete the positional key?
|
91
90
|
attributes[key] = val
|
92
|
-
end
|
91
|
+
end
|
93
92
|
end
|
94
93
|
attributes
|
95
94
|
end
|
96
95
|
|
97
96
|
private
|
98
97
|
|
99
|
-
def parse_attribute index
|
100
|
-
|
98
|
+
def parse_attribute index, positional_attrs
|
99
|
+
continue = true
|
101
100
|
skip_blank
|
102
|
-
|
103
|
-
|
101
|
+
case @scanner.peek 1
|
102
|
+
# example: "quote" || "foo
|
103
|
+
when QUOT
|
104
104
|
name = parse_attribute_value @scanner.get_byte
|
105
|
-
|
106
|
-
|
107
|
-
elsif first == APOS
|
105
|
+
# example: 'quote' || 'foo
|
106
|
+
when APOS
|
108
107
|
name = parse_attribute_value @scanner.get_byte
|
109
|
-
|
110
|
-
single_quoted_value = true unless name.start_with? APOS
|
108
|
+
single_quoted = true unless name.start_with? APOS
|
111
109
|
else
|
112
|
-
name = scan_name
|
113
|
-
|
114
|
-
skipped = 0
|
115
|
-
c = nil
|
110
|
+
skipped = ((name = scan_name) && skip_blank) || 0
|
116
111
|
if @scanner.eos?
|
117
|
-
return
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
else
|
131
|
-
skip_blank
|
132
|
-
if @scanner.peek(1)
|
133
|
-
# example: foo="bar" || foo="ba\"zaar"
|
134
|
-
if (c = @scanner.get_byte) == '"'
|
112
|
+
return unless name || (@scanner.string.rstrip.end_with? @delimiter)
|
113
|
+
# example: quote (at eos)
|
114
|
+
continue = nil
|
115
|
+
# example: quote,
|
116
|
+
elsif (c = @scanner.get_byte) == @delimiter
|
117
|
+
@scanner.unscan
|
118
|
+
elsif name
|
119
|
+
# example: foo=...
|
120
|
+
if c == '='
|
121
|
+
skip_blank
|
122
|
+
case (c = @scanner.get_byte)
|
123
|
+
# example: foo="bar" || foo="ba\"zaar" || foo="bar
|
124
|
+
when QUOT
|
135
125
|
value = parse_attribute_value c
|
136
|
-
# example: foo='bar' || foo='ba\'zaar' || foo='ba"zaar'
|
137
|
-
|
126
|
+
# example: foo='bar' || foo='ba\'zaar' || foo='ba"zaar' || foo='bar
|
127
|
+
when APOS
|
138
128
|
value = parse_attribute_value c
|
139
|
-
|
129
|
+
single_quoted = true unless value.start_with? APOS
|
140
130
|
# example: foo=,
|
141
|
-
|
131
|
+
when @delimiter
|
132
|
+
value = ''
|
133
|
+
@scanner.unscan
|
134
|
+
# example: foo= (at eos)
|
135
|
+
when nil
|
142
136
|
value = ''
|
143
|
-
# example: foo=bar
|
137
|
+
# example: foo=bar || foo=None
|
144
138
|
else
|
145
139
|
value = %(#{c}#{scan_to_delimiter})
|
146
140
|
return true if value == 'None'
|
147
141
|
end
|
142
|
+
# example: foo bar
|
143
|
+
else
|
144
|
+
name = %(#{name}#{' ' * skipped}#{c}#{scan_to_delimiter})
|
148
145
|
end
|
146
|
+
# example: =foo= || !foo
|
147
|
+
else
|
148
|
+
name = %(#{c}#{scan_to_delimiter})
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
152
152
|
if value
|
153
|
-
# example: options="opt1,opt2,opt3"
|
154
|
-
# opts is an alias for options
|
153
|
+
# example: options="opt1,opt2,opt3" || opts="opts1,opt2,opt3"
|
155
154
|
case name
|
156
155
|
when 'options', 'opts'
|
157
156
|
if value.include? ','
|
@@ -161,7 +160,7 @@ class AttributeList
|
|
161
160
|
@attributes[%(#{value}-option)] = '' unless value.empty?
|
162
161
|
end
|
163
162
|
else
|
164
|
-
if
|
163
|
+
if single_quoted && @block
|
165
164
|
case name
|
166
165
|
when 'title', 'reftext'
|
167
166
|
@attributes[name] = value
|
@@ -173,33 +172,26 @@ class AttributeList
|
|
173
172
|
end
|
174
173
|
end
|
175
174
|
else
|
176
|
-
|
175
|
+
name = @block.apply_subs name if single_quoted && @block
|
177
176
|
if (positional_attr_name = positional_attrs[index])
|
178
|
-
@attributes[positional_attr_name] =
|
177
|
+
@attributes[positional_attr_name] = name
|
179
178
|
end
|
180
|
-
# QUESTION should we
|
181
|
-
@attributes[index + 1] =
|
182
|
-
# QUESTION should we assign the resolved name as an attribute?
|
183
|
-
#@attributes[resolved_name] = nil
|
179
|
+
# QUESTION should we assign the positional key even when it's claimed by a positional attribute?
|
180
|
+
@attributes[index + 1] = name
|
184
181
|
end
|
185
182
|
|
186
|
-
|
183
|
+
continue
|
187
184
|
end
|
188
185
|
|
189
186
|
def parse_attribute_value quote
|
190
187
|
# empty quoted value
|
191
|
-
if @scanner.peek
|
188
|
+
if (@scanner.peek 1) == quote
|
192
189
|
@scanner.get_byte
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
if (value = scan_to_quote quote)
|
190
|
+
''
|
191
|
+
elsif (value = scan_to_quote quote)
|
197
192
|
@scanner.get_byte
|
198
|
-
|
199
|
-
|
200
|
-
else
|
201
|
-
value
|
202
|
-
end
|
193
|
+
(value.include? BACKSLASH) ? (value.gsub EscapedQuotes[quote], quote) : value
|
194
|
+
# leading quote only
|
203
195
|
else
|
204
196
|
%(#{quote}#{scan_to_delimiter})
|
205
197
|
end
|
@@ -42,6 +42,8 @@ module Asciidoctor
|
|
42
42
|
non_posix_env = ::File::ALT_SEPARATOR == RS
|
43
43
|
err = @err || $stderr
|
44
44
|
show_timings = false
|
45
|
+
# NOTE in Ruby 2.7, RubyGems sets SOURCE_DATE_EPOCH if it's not set
|
46
|
+
::ENV.delete 'SOURCE_DATE_EPOCH' if (::ENV.key? 'IGNORE_SOURCE_DATE_EPOCH') && (::Gem.respond_to? :source_date_epoch)
|
45
47
|
|
46
48
|
@options.map do |key, val|
|
47
49
|
case key
|
@@ -76,8 +76,8 @@ module Asciidoctor
|
|
76
76
|
opts.on('-n', '--section-numbers', 'auto-number section titles in the HTML backend; disabled by default') do
|
77
77
|
self[:attributes]['sectnums'] = ''
|
78
78
|
end
|
79
|
-
opts.on('--eruby ERUBY', ['erb', 'erubis'],
|
80
|
-
'specify eRuby implementation to use when rendering custom ERB templates: [erb, erubis] (default: erb)') do |eruby|
|
79
|
+
opts.on('--eruby ERUBY', ['erb', 'erubi', 'erubis'],
|
80
|
+
'specify eRuby implementation to use when rendering custom ERB templates: [erb, erubi, erubis] (default: erb)') do |eruby|
|
81
81
|
self[:eruby] = eruby
|
82
82
|
end
|
83
83
|
opts.on('-a', '--attribute name[=value]', 'a document attribute to set in the form of name, name!, or name=value pair',
|
@@ -205,7 +205,7 @@ module Asciidoctor
|
|
205
205
|
# shave off the file to process so that options errors appear correctly
|
206
206
|
if args.size == 1 && args[0] == '-'
|
207
207
|
infiles << args.pop
|
208
|
-
|
208
|
+
else
|
209
209
|
args.each do |file|
|
210
210
|
if file.start_with? '-'
|
211
211
|
# warn, but don't panic; we may have enough to proceed, so we won't force a failure
|
data/lib/asciidoctor/convert.rb
CHANGED
@@ -1,193 +1,198 @@
|
|
1
1
|
module Asciidoctor
|
2
|
-
|
2
|
+
class << self
|
3
|
+
# Public: Parse the AsciiDoc source input into an Asciidoctor::Document and
|
4
|
+
# convert it to the specified backend format.
|
5
|
+
#
|
6
|
+
# Accepts input as an IO (or StringIO), String or String Array object. If the
|
7
|
+
# input is a File, the object is expected to be opened for reading and is not
|
8
|
+
# closed afterwards by this method. Information about the file (filename,
|
9
|
+
# directory name, etc) gets assigned to attributes on the Document object.
|
10
|
+
#
|
11
|
+
# If the :to_file option is true, and the input is a File, the output is
|
12
|
+
# written to a file adjacent to the input file, having an extension that
|
13
|
+
# corresponds to the backend format. Otherwise, if the :to_file option is
|
14
|
+
# specified, the file is written to that file. If :to_file is not an absolute
|
15
|
+
# path, it is resolved relative to :to_dir, if given, otherwise the
|
16
|
+
# Document#base_dir. If the target directory does not exist, it will not be
|
17
|
+
# created unless the :mkdirs option is set to true. If the file cannot be
|
18
|
+
# written because the target directory does not exist, or because it falls
|
19
|
+
# outside of the Document#base_dir in safe mode, an IOError is raised.
|
20
|
+
#
|
21
|
+
# If the output is going to be written to a file, the header and footer are
|
22
|
+
# included unless specified otherwise (writing to a file implies creating a
|
23
|
+
# standalone document). Otherwise, the header and footer are not included by
|
24
|
+
# default and the converted result is returned.
|
25
|
+
#
|
26
|
+
# input - the String AsciiDoc source filename
|
27
|
+
# options - a String, Array or Hash of options to control processing (default: {})
|
28
|
+
# String and Array values are converted into a Hash.
|
29
|
+
# See Asciidoctor::Document#initialize for details about options.
|
30
|
+
#
|
31
|
+
# Returns the Document object if the converted String is written to a
|
32
|
+
# file, otherwise the converted String
|
33
|
+
def convert input, options = {}
|
34
|
+
(options = options.merge).delete :parse
|
35
|
+
to_dir = options.delete :to_dir
|
36
|
+
mkdirs = options.delete :mkdirs
|
3
37
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# path, it is resolved relative to :to_dir, if given, otherwise the
|
17
|
-
# Document#base_dir. If the target directory does not exist, it will not be
|
18
|
-
# created unless the :mkdirs option is set to true. If the file cannot be
|
19
|
-
# written because the target directory does not exist, or because it falls
|
20
|
-
# outside of the Document#base_dir in safe mode, an IOError is raised.
|
21
|
-
#
|
22
|
-
# If the output is going to be written to a file, the header and footer are
|
23
|
-
# included unless specified otherwise (writing to a file implies creating a
|
24
|
-
# standalone document). Otherwise, the header and footer are not included by
|
25
|
-
# default and the converted result is returned.
|
26
|
-
#
|
27
|
-
# input - the String AsciiDoc source filename
|
28
|
-
# options - a String, Array or Hash of options to control processing (default: {})
|
29
|
-
# String and Array values are converted into a Hash.
|
30
|
-
# See Asciidoctor::Document#initialize for details about options.
|
31
|
-
#
|
32
|
-
# Returns the Document object if the converted String is written to a
|
33
|
-
# file, otherwise the converted String
|
34
|
-
def convert input, options = {}
|
35
|
-
(options = options.merge).delete :parse
|
36
|
-
to_dir = options.delete :to_dir
|
37
|
-
mkdirs = options.delete :mkdirs
|
38
|
-
|
39
|
-
case (to_file = options.delete :to_file)
|
40
|
-
when true, nil
|
41
|
-
unless (write_to_target = to_dir)
|
42
|
-
sibling_path = ::File.absolute_path input.path if ::File === input
|
38
|
+
case (to_file = options.delete :to_file)
|
39
|
+
when true, nil
|
40
|
+
unless (write_to_target = to_dir)
|
41
|
+
sibling_path = ::File.absolute_path input.path if ::File === input
|
42
|
+
end
|
43
|
+
to_file = nil
|
44
|
+
when false
|
45
|
+
to_file = nil
|
46
|
+
when '/dev/null'
|
47
|
+
return load input, options
|
48
|
+
else
|
49
|
+
options[:to_file] = write_to_target = to_file unless (stream_output = to_file.respond_to? :write)
|
43
50
|
end
|
44
|
-
to_file = nil
|
45
|
-
when false
|
46
|
-
to_file = nil
|
47
|
-
when '/dev/null'
|
48
|
-
return load input, options
|
49
|
-
else
|
50
|
-
options[:to_file] = write_to_target = to_file unless (stream_output = to_file.respond_to? :write)
|
51
|
-
end
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
52
|
+
unless options.key? :standalone
|
53
|
+
if sibling_path || write_to_target
|
54
|
+
options[:standalone] = options.fetch :header_footer, true
|
55
|
+
elsif options.key? :header_footer
|
56
|
+
options[:standalone] = options[:header_footer]
|
57
|
+
end
|
58
58
|
end
|
59
|
-
end
|
60
59
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
60
|
+
# NOTE outfile may be controlled by document attributes, so resolve outfile after loading
|
61
|
+
if sibling_path
|
62
|
+
options[:to_dir] = outdir = ::File.dirname sibling_path
|
63
|
+
elsif write_to_target
|
64
|
+
if to_dir
|
65
|
+
if to_file
|
66
|
+
options[:to_dir] = ::File.dirname ::File.expand_path to_file, to_dir
|
67
|
+
else
|
68
|
+
options[:to_dir] = ::File.expand_path to_dir
|
69
|
+
end
|
70
|
+
elsif to_file
|
71
|
+
options[:to_dir] = ::File.dirname ::File.expand_path to_file
|
70
72
|
end
|
71
|
-
elsif to_file
|
72
|
-
options[:to_dir] = ::File.dirname ::File.expand_path to_file
|
73
73
|
end
|
74
|
-
end
|
75
74
|
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
# NOTE :to_dir is always set when outputting to a file
|
76
|
+
# NOTE :to_file option only passed if assigned an explicit path
|
77
|
+
doc = load input, options
|
79
78
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
79
|
+
if sibling_path # write to file in same directory
|
80
|
+
outfile = ::File.join outdir, %(#{doc.attributes['docname']}#{doc.outfilesuffix})
|
81
|
+
raise ::IOError, %(input file and output file cannot be the same: #{outfile}) if outfile == sibling_path
|
82
|
+
elsif write_to_target # write to explicit file or directory
|
83
|
+
working_dir = (options.key? :base_dir) ? (::File.expand_path options[:base_dir]) : ::Dir.pwd
|
84
|
+
# QUESTION should the jail be the working_dir or doc.base_dir???
|
85
|
+
jail = doc.safe >= SafeMode::SAFE ? working_dir : nil
|
86
|
+
if to_dir
|
87
|
+
outdir = doc.normalize_system_path(to_dir, working_dir, jail, target_name: 'to_dir', recover: false)
|
88
|
+
if to_file
|
89
|
+
outfile = doc.normalize_system_path(to_file, outdir, nil, target_name: 'to_dir', recover: false)
|
90
|
+
# reestablish outdir as the final target directory (in the case to_file had directory segments)
|
91
|
+
outdir = ::File.dirname outfile
|
92
|
+
else
|
93
|
+
outfile = ::File.join outdir, %(#{doc.attributes['docname']}#{doc.outfilesuffix})
|
94
|
+
end
|
95
|
+
elsif to_file
|
96
|
+
outfile = doc.normalize_system_path(to_file, working_dir, jail, target_name: 'to_dir', recover: false)
|
97
|
+
# establish outdir as the final target directory (in the case to_file had directory segments)
|
92
98
|
outdir = ::File.dirname outfile
|
93
|
-
else
|
94
|
-
outfile = ::File.join outdir, %(#{doc.attributes['docname']}#{doc.outfilesuffix})
|
95
99
|
end
|
96
|
-
elsif to_file
|
97
|
-
outfile = doc.normalize_system_path(to_file, working_dir, jail, target_name: 'to_dir', recover: false)
|
98
|
-
# establish outdir as the final target directory (in the case to_file had directory segments)
|
99
|
-
outdir = ::File.dirname outfile
|
100
|
-
end
|
101
100
|
|
102
|
-
|
103
|
-
|
101
|
+
if ::File === input && outfile == (::File.absolute_path input.path)
|
102
|
+
raise ::IOError, %(input file and output file cannot be the same: #{outfile})
|
103
|
+
end
|
104
|
+
|
105
|
+
if mkdirs
|
106
|
+
Helpers.mkdir_p outdir
|
107
|
+
else
|
108
|
+
# NOTE we intentionally refer to the directory as it was passed to the API
|
109
|
+
raise ::IOError, %(target directory does not exist: #{to_dir} (hint: set :mkdirs option)) unless ::File.directory? outdir
|
110
|
+
end
|
111
|
+
else # write to stream
|
112
|
+
outfile = to_file
|
113
|
+
outdir = nil
|
104
114
|
end
|
105
115
|
|
106
|
-
if
|
107
|
-
|
116
|
+
if outfile && !stream_output
|
117
|
+
output = doc.convert 'outfile' => outfile, 'outdir' => outdir
|
108
118
|
else
|
109
|
-
|
110
|
-
raise ::IOError, %(target directory does not exist: #{to_dir} (hint: set :mkdirs option)) unless ::File.directory? outdir
|
119
|
+
output = doc.convert
|
111
120
|
end
|
112
|
-
else # write to stream
|
113
|
-
outfile = to_file
|
114
|
-
outdir = nil
|
115
|
-
end
|
116
|
-
|
117
|
-
if outfile && !stream_output
|
118
|
-
output = doc.convert 'outfile' => outfile, 'outdir' => outdir
|
119
|
-
else
|
120
|
-
output = doc.convert
|
121
|
-
end
|
122
121
|
|
123
|
-
|
124
|
-
|
122
|
+
if outfile
|
123
|
+
doc.write output, outfile
|
125
124
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
end
|
137
|
-
copy_syntax_hl_stylesheet = (syntax_hl = doc.syntax_highlighter) && (syntax_hl.write_stylesheet? doc)
|
138
|
-
if copy_asciidoctor_stylesheet || copy_user_stylesheet || copy_syntax_hl_stylesheet
|
139
|
-
stylesoutdir = doc.normalize_system_path(stylesdir, outdir, doc.safe >= SafeMode::SAFE ? outdir : nil)
|
140
|
-
if mkdirs
|
141
|
-
Helpers.mkdir_p stylesoutdir
|
142
|
-
else
|
143
|
-
raise ::IOError, %(target stylesheet directory does not exist: #{stylesoutdir} (hint: set :mkdirs option)) unless ::File.directory? stylesoutdir
|
125
|
+
# NOTE document cannot control this behavior if safe >= SafeMode::SERVER
|
126
|
+
# NOTE skip if stylesdir is a URI
|
127
|
+
if !stream_output && doc.safe < SafeMode::SECURE && (doc.attr? 'linkcss') && (doc.attr? 'copycss') &&
|
128
|
+
(doc.basebackend? 'html') && !((stylesdir = (doc.attr 'stylesdir')) && (Helpers.uriish? stylesdir))
|
129
|
+
if (stylesheet = doc.attr 'stylesheet')
|
130
|
+
if DEFAULT_STYLESHEET_KEYS.include? stylesheet
|
131
|
+
copy_asciidoctor_stylesheet = true
|
132
|
+
elsif !(Helpers.uriish? stylesheet)
|
133
|
+
copy_user_stylesheet = true
|
134
|
+
end
|
144
135
|
end
|
145
|
-
|
146
|
-
if copy_asciidoctor_stylesheet
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
if (stylesheet_src = doc.attr 'copycss').empty?
|
151
|
-
stylesheet_src = doc.normalize_system_path stylesheet
|
136
|
+
copy_syntax_hl_stylesheet = (syntax_hl = doc.syntax_highlighter) && (syntax_hl.write_stylesheet? doc)
|
137
|
+
if copy_asciidoctor_stylesheet || copy_user_stylesheet || copy_syntax_hl_stylesheet
|
138
|
+
stylesoutdir = doc.normalize_system_path(stylesdir, outdir, doc.safe >= SafeMode::SAFE ? outdir : nil)
|
139
|
+
if mkdirs
|
140
|
+
Helpers.mkdir_p stylesoutdir
|
152
141
|
else
|
153
|
-
|
154
|
-
stylesheet_src = doc.normalize_system_path stylesheet_src
|
142
|
+
raise ::IOError, %(target stylesheet directory does not exist: #{stylesoutdir} (hint: set :mkdirs option)) unless ::File.directory? stylesoutdir
|
155
143
|
end
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
144
|
+
|
145
|
+
if copy_asciidoctor_stylesheet
|
146
|
+
Stylesheets.instance.write_primary_stylesheet stylesoutdir
|
147
|
+
# FIXME should Stylesheets also handle the user stylesheet?
|
148
|
+
elsif copy_user_stylesheet
|
149
|
+
if (stylesheet_src = doc.attr 'copycss') == '' || stylesheet_src == true
|
150
|
+
stylesheet_src = doc.normalize_system_path stylesheet
|
151
|
+
else
|
152
|
+
# NOTE in this case, copycss is a source location (but cannot be a URI)
|
153
|
+
stylesheet_src = doc.normalize_system_path stylesheet_src.to_s
|
154
|
+
end
|
155
|
+
stylesheet_dest = doc.normalize_system_path stylesheet, stylesoutdir, (doc.safe >= SafeMode::SAFE ? outdir : nil)
|
156
|
+
# NOTE don't warn if src can't be read and dest already exists (see #2323)
|
157
|
+
if stylesheet_src != stylesheet_dest && (stylesheet_data = doc.read_asset stylesheet_src,
|
158
|
+
warn_on_failure: !(::File.file? stylesheet_dest), label: 'stylesheet')
|
159
|
+
if (stylesheet_outdir = ::File.dirname stylesheet_dest) != stylesoutdir && !(::File.directory? stylesheet_outdir)
|
160
|
+
if mkdirs
|
161
|
+
Helpers.mkdir_p stylesheet_outdir
|
162
|
+
else
|
163
|
+
raise ::IOError, %(target stylesheet directory does not exist: #{stylesheet_outdir} (hint: set :mkdirs option))
|
164
|
+
end
|
165
|
+
end
|
166
|
+
::File.write stylesheet_dest, stylesheet_data, mode: FILE_WRITE_MODE
|
167
|
+
end
|
161
168
|
end
|
169
|
+
syntax_hl.write_stylesheet doc, stylesoutdir if copy_syntax_hl_stylesheet
|
162
170
|
end
|
163
|
-
syntax_hl.write_stylesheet doc, stylesoutdir if copy_syntax_hl_stylesheet
|
164
171
|
end
|
172
|
+
doc
|
173
|
+
else
|
174
|
+
output
|
165
175
|
end
|
166
|
-
doc
|
167
|
-
else
|
168
|
-
output
|
169
176
|
end
|
170
|
-
end
|
171
177
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
178
|
+
# Public: Parse the contents of the AsciiDoc source file into an
|
179
|
+
# Asciidoctor::Document and convert it to the specified backend format.
|
180
|
+
#
|
181
|
+
# input - the String AsciiDoc source filename
|
182
|
+
# options - a String, Array or Hash of options to control processing (default: {})
|
183
|
+
# String and Array values are converted into a Hash.
|
184
|
+
# See Asciidoctor::Document#initialize for details about options.
|
185
|
+
#
|
186
|
+
# Returns the Document object if the converted String is written to a
|
187
|
+
# file, otherwise the converted String
|
188
|
+
def convert_file filename, options = {}
|
189
|
+
::File.open(filename, FILE_READ_MODE) {|file| convert file, options }
|
190
|
+
end
|
185
191
|
|
186
|
-
|
187
|
-
|
188
|
-
module_function :render
|
192
|
+
# Deprecated: Use {Asciidoctor.convert} instead.
|
193
|
+
alias render convert
|
189
194
|
|
190
|
-
|
191
|
-
|
192
|
-
|
195
|
+
# Deprecated: Use {Asciidoctor.convert_file} instead.
|
196
|
+
alias render_file convert_file
|
197
|
+
end
|
193
198
|
end
|