asciidoctor 0.0.9 → 0.1.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.
- data/README.asciidoc +163 -41
- data/Rakefile +3 -1
- data/asciidoctor.gemspec +13 -5
- data/bin/asciidoctor +6 -3
- data/bin/asciidoctor-safe +13 -0
- data/lib/asciidoctor.rb +237 -26
- data/lib/asciidoctor/abstract_node.rb +27 -17
- data/lib/asciidoctor/attribute_list.rb +6 -0
- data/lib/asciidoctor/backends/base_template.rb +3 -4
- data/lib/asciidoctor/backends/docbook45.rb +114 -55
- data/lib/asciidoctor/backends/html5.rb +173 -104
- data/lib/asciidoctor/cli/invoker.rb +105 -0
- data/lib/asciidoctor/cli/options.rb +146 -0
- data/lib/asciidoctor/document.rb +135 -35
- data/lib/asciidoctor/lexer.rb +86 -33
- data/lib/asciidoctor/list_item.rb +2 -2
- data/lib/asciidoctor/reader.rb +6 -7
- data/lib/asciidoctor/section.rb +17 -5
- data/lib/asciidoctor/substituters.rb +216 -97
- data/lib/asciidoctor/table.rb +9 -2
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +212 -0
- data/man/asciidoctor.ad +156 -0
- data/test/attributes_test.rb +108 -5
- data/test/blocks_test.rb +102 -15
- data/test/document_test.rb +214 -3
- data/test/fixtures/encoding.asciidoc +4 -0
- data/test/fixtures/sample.asciidoc +26 -0
- data/test/invoker_test.rb +254 -0
- data/test/lexer_test.rb +53 -0
- data/test/links_test.rb +30 -0
- data/test/lists_test.rb +648 -9
- data/test/options_test.rb +68 -0
- data/test/paragraphs_test.rb +65 -1
- data/test/reader_test.rb +18 -4
- data/test/{headers_test.rb → sections_test.rb} +237 -0
- data/test/substitutions_test.rb +247 -5
- data/test/tables_test.rb +22 -4
- data/test/test_helper.rb +47 -3
- data/test/text_test.rb +20 -4
- metadata +34 -6
- data/noof.rb +0 -16
@@ -0,0 +1,105 @@
|
|
1
|
+
module Asciidoctor
|
2
|
+
module Cli
|
3
|
+
# Public Invocation class for starting Asciidoctor via CLI
|
4
|
+
class Invoker
|
5
|
+
attr_reader :options
|
6
|
+
attr_reader :document
|
7
|
+
attr_reader :code
|
8
|
+
attr_reader :timings
|
9
|
+
|
10
|
+
def initialize(*options)
|
11
|
+
@document = nil
|
12
|
+
@out = nil
|
13
|
+
@err = nil
|
14
|
+
@code = 0
|
15
|
+
@timings = {}
|
16
|
+
options = options.flatten
|
17
|
+
if !options.empty? && options.first.is_a?(Asciidoctor::Cli::Options)
|
18
|
+
@options = options.first
|
19
|
+
elsif options.first.is_a? Hash
|
20
|
+
@options = Asciidoctor::Cli::Options.new(options)
|
21
|
+
else
|
22
|
+
@options = Asciidoctor::Cli::Options.parse!(options)
|
23
|
+
# hmmm
|
24
|
+
if @options.is_a?(Integer)
|
25
|
+
@code = @options
|
26
|
+
@options = nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def invoke!
|
32
|
+
return if @options.nil?
|
33
|
+
|
34
|
+
begin
|
35
|
+
@timings = {}
|
36
|
+
infile = @options[:input_file]
|
37
|
+
outfile = @options[:output_file]
|
38
|
+
if infile == '-'
|
39
|
+
# allow use of block to supply stdin, particularly useful for tests
|
40
|
+
input = block_given? ? yield : STDIN
|
41
|
+
else
|
42
|
+
input = File.new(infile)
|
43
|
+
end
|
44
|
+
start = Time.now
|
45
|
+
@document = Asciidoctor.load(input, @options)
|
46
|
+
timings[:parse] = Time.now - start
|
47
|
+
start = Time.now
|
48
|
+
output = @document.render
|
49
|
+
timings[:render] = Time.now - start
|
50
|
+
if @options[:verbose]
|
51
|
+
puts "Time to read and parse source: #{timings[:parse]}"
|
52
|
+
puts "Time to render document: #{timings[:render]}"
|
53
|
+
puts "Total time to read, parse and render: #{timings.reduce(0) {|sum, (_, v)| sum += v}}"
|
54
|
+
end
|
55
|
+
if outfile == '/dev/null'
|
56
|
+
# output nothing
|
57
|
+
elsif outfile == '-' || (infile == '-' && (outfile.nil? || outfile.empty?))
|
58
|
+
(@out || $stdout).puts output
|
59
|
+
else
|
60
|
+
if outfile.nil? || outfile.empty?
|
61
|
+
if @options[:destination_dir]
|
62
|
+
destination_dir = File.expand_path(@options[:destination_dir])
|
63
|
+
else
|
64
|
+
destination_dir = @document.base_dir
|
65
|
+
end
|
66
|
+
outfile = File.join(destination_dir, "#{@document.attributes['docname']}#{@document.attributes['outfilesuffix']}")
|
67
|
+
else
|
68
|
+
outfile = @document.normalize_asset_path outfile
|
69
|
+
end
|
70
|
+
|
71
|
+
# this assignment is primarily for testing or other post analysis
|
72
|
+
@document.attributes['outfile'] = outfile
|
73
|
+
@document.attributes['outdir'] = File.dirname(outfile)
|
74
|
+
File.open(outfile, 'w') {|file| file.write output }
|
75
|
+
end
|
76
|
+
rescue Exception => e
|
77
|
+
raise e if @options[:trace] || SystemExit === e
|
78
|
+
err = (@err || $stderr)
|
79
|
+
err.print "#{e.class}: " if e.class != RuntimeError
|
80
|
+
err.puts e.message
|
81
|
+
err.puts ' Use --trace for backtrace'
|
82
|
+
@code = 1
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def redirect_streams(out, err = nil)
|
87
|
+
@out = out
|
88
|
+
@err = err
|
89
|
+
end
|
90
|
+
|
91
|
+
def read_output
|
92
|
+
!@out.nil? ? @out.string : ''
|
93
|
+
end
|
94
|
+
|
95
|
+
def read_error
|
96
|
+
!@err.nil? ? @err.string : ''
|
97
|
+
end
|
98
|
+
|
99
|
+
def reset_streams
|
100
|
+
@out = nil
|
101
|
+
@err = nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Asciidoctor
|
4
|
+
module Cli
|
5
|
+
|
6
|
+
# Public: List of options that can be specified on the command line
|
7
|
+
class Options < Hash
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
self[:attributes] = options[:attributes] || {}
|
11
|
+
self[:input_file] = options[:input_file] || nil
|
12
|
+
self[:output_file] = options[:output_file] || nil
|
13
|
+
self[:safe] = options[:safe] || Asciidoctor::SafeMode::UNSAFE
|
14
|
+
self[:header_footer] = options[:header_footer] || true
|
15
|
+
self[:template_dir] = options[:template_dir] || nil
|
16
|
+
if options[:doctype]
|
17
|
+
self[:attributes]['doctype'] = options[:doctype]
|
18
|
+
end
|
19
|
+
if options[:backend]
|
20
|
+
self[:attributes]['backend'] = options[:backend]
|
21
|
+
end
|
22
|
+
self[:eruby] = options[:eruby] || nil
|
23
|
+
self[:compact] = options[:compact] || false
|
24
|
+
self[:verbose] = options[:verbose] || false
|
25
|
+
self[:base_dir] = options[:base_dir] || nil
|
26
|
+
self[:destination_dir] = options[:destination_dir] || nil
|
27
|
+
self[:trace] = false
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.parse!(args)
|
31
|
+
Options.new.parse! args
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse!(args)
|
35
|
+
opts_parser = OptionParser.new do |opts|
|
36
|
+
opts.banner = <<-EOS
|
37
|
+
Usage: asciidoctor [OPTION]... [FILE]
|
38
|
+
Translate the AsciiDoc source FILE into the backend output format (e.g., HTML 5, DocBook 4.5, etc.)
|
39
|
+
By default, the output is written to a file with the basename of the source file and the appropriate extension.
|
40
|
+
Example: asciidoctor -b html5 source.asciidoc
|
41
|
+
|
42
|
+
EOS
|
43
|
+
|
44
|
+
opts.on('-v', '--verbose', 'enable verbose mode (default: false)') do |verbose|
|
45
|
+
self[:verbose] = true
|
46
|
+
end
|
47
|
+
opts.on('-b', '--backend BACKEND', ['html5', 'docbook45'], 'set output format (i.e., backend): [html5, docbook45] (default: html5)') do |backend|
|
48
|
+
self[:attributes]['backend'] = backend
|
49
|
+
end
|
50
|
+
opts.on('-d', '--doctype DOCTYPE', ['article', 'book'],
|
51
|
+
'document type to use when rendering output: [article, book] (default: article)') do |doc_type|
|
52
|
+
self[:attributes]['doctype'] = doc_type
|
53
|
+
end
|
54
|
+
opts.on('-o', '--out-file FILE', 'output file (default: based on input file path); use - to output to STDOUT') do |output_file|
|
55
|
+
self[:output_file] = output_file
|
56
|
+
end
|
57
|
+
opts.on('--safe',
|
58
|
+
'set safe mode to safe (default: secure)',
|
59
|
+
'enables include macros, but restricts access to ancestor paths of source file',
|
60
|
+
'provided for compatibility with the asciidoc command') do
|
61
|
+
self[:safe] = Asciidoctor::SafeMode::SAFE
|
62
|
+
end
|
63
|
+
opts.on('-S', '--safe-mode SAFE_MODE', ['unsafe', 'safe', 'secure'],
|
64
|
+
'set safe mode level explicitly: [unsafe, safe, secure] (default: secure)',
|
65
|
+
'disables potentially dangerous macros in source files, such as include::[]') do |safe_mode|
|
66
|
+
self[:safe] = Asciidoctor::SafeMode.const_get(safe_mode.upcase)
|
67
|
+
end
|
68
|
+
opts.on('-s', '--no-header-footer', 'suppress output of header and footer (default: false)') do
|
69
|
+
self[:header_footer] = false
|
70
|
+
end
|
71
|
+
opts.on('-n', '--section-numbers', 'auto-number section titles in the HTML backend; disabled by default') do
|
72
|
+
self[:attributes]['numbered'] = ''
|
73
|
+
end
|
74
|
+
opts.on('-e', '--eruby ERUBY', ['erb', 'erubis'],
|
75
|
+
'specify eRuby implementation to render built-in templates: [erb, erubis] (default: erb)') do |eruby|
|
76
|
+
self[:eruby] = eruby
|
77
|
+
end
|
78
|
+
opts.on('-C', '--compact', 'compact the output by removing blank lines (default: false)') do
|
79
|
+
self[:compact] = true
|
80
|
+
end
|
81
|
+
opts.on('-a', '--attribute key1=value,key2=value2,...', Array,
|
82
|
+
'a list of attributes, in the form key or key=value pair, to set on the document',
|
83
|
+
'these attributes take precedence over attributes defined in the source file') do |attribs|
|
84
|
+
attribs.each do |attrib|
|
85
|
+
tokens = attrib.split('=')
|
86
|
+
self[:attributes][tokens[0]] = tokens[1] || ''
|
87
|
+
end
|
88
|
+
end
|
89
|
+
opts.on('-T', '--template-dir DIR', 'directory containing custom render templates the override the built-in set') do |template_dir|
|
90
|
+
self[:template_dir] = template_dir
|
91
|
+
end
|
92
|
+
opts.on('-B', '--base-dir DIR', 'base directory containing the document and resources (default: directory of source file)') do |base_dir|
|
93
|
+
self[:base_dir] = base_dir
|
94
|
+
end
|
95
|
+
opts.on('-D', '--destination-dir DIR', 'destination output directory (default: directory of source file)') do |dest_dir|
|
96
|
+
self[:destination_dir] = dest_dir
|
97
|
+
end
|
98
|
+
opts.on('--trace', 'include backtrace information on errors (default: false)') do |trace|
|
99
|
+
self[:trace] = true
|
100
|
+
end
|
101
|
+
|
102
|
+
opts.on_tail('-h', '--help', 'show this message') do
|
103
|
+
$stdout.puts opts
|
104
|
+
return 0
|
105
|
+
end
|
106
|
+
|
107
|
+
opts.on_tail('-V', '--version', 'display the version') do
|
108
|
+
$stdout.puts "Asciidoctor #{Asciidoctor::VERSION} [http://asciidoctor.org]"
|
109
|
+
return 0
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
begin
|
115
|
+
# shave off the file to process so that options errors appear correctly
|
116
|
+
if args.last && (args.last == '-' || !args.last.start_with?('-'))
|
117
|
+
self[:input_file] = args.pop
|
118
|
+
end
|
119
|
+
opts_parser.parse!(args)
|
120
|
+
if args.size > 0
|
121
|
+
# warn, but don't panic; we may have enough to proceed, so we won't force a failure
|
122
|
+
$stderr.puts "asciidoctor: WARNING: extra arguments detected (unparsed arguments: #{args.map{|a| "'#{a}'"} * ', '})"
|
123
|
+
end
|
124
|
+
|
125
|
+
if self[:input_file].nil? || self[:input_file].empty?
|
126
|
+
$stderr.puts opts_parser
|
127
|
+
return 1
|
128
|
+
elsif self[:input_file] != '-' && !File.exist?(self[:input_file])
|
129
|
+
$stderr.puts "asciidoctor: FAILED: input file #{self[:input_file]} missing"
|
130
|
+
return 1
|
131
|
+
end
|
132
|
+
rescue OptionParser::MissingArgument
|
133
|
+
$stderr.puts "asciidoctor: option #{$!.message}"
|
134
|
+
$stdout.puts opts_parser
|
135
|
+
return 1
|
136
|
+
rescue OptionParser::InvalidOption, OptionParser::InvalidArgument
|
137
|
+
$stderr.puts "asciidoctor: #{$!.message}"
|
138
|
+
$stdout.puts opts_parser
|
139
|
+
return 1
|
140
|
+
end
|
141
|
+
self
|
142
|
+
end # parse()
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/asciidoctor/document.rb
CHANGED
@@ -19,6 +19,8 @@ class Asciidoctor::Document < Asciidoctor::AbstractBlock
|
|
19
19
|
|
20
20
|
include Asciidoctor
|
21
21
|
|
22
|
+
Footnote = Struct.new(:index, :id, :text)
|
23
|
+
|
22
24
|
# Public A read-only integer value indicating the level of security that
|
23
25
|
# should be enforced while processing this document. The value must be
|
24
26
|
# set in the Document constructor using the :safe option.
|
@@ -30,14 +32,23 @@ class Asciidoctor::Document < Asciidoctor::AbstractBlock
|
|
30
32
|
# it prevents access to files which reside outside of the parent directory
|
31
33
|
# of the source file and disables any macro other than the include macro.
|
32
34
|
#
|
33
|
-
# A value of 10 (
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
35
|
+
# A value of 10 (SERVER) disallows the document from setting attributes that
|
36
|
+
# would affect the rendering of the document, in addition to all the security
|
37
|
+
# features of SafeMode::SAFE. For instance, this value disallows changing the
|
38
|
+
# backend or the source-highlighter using an attribute defined in the source
|
39
|
+
# document. This is the most fundamental level of security for server-side
|
40
|
+
# deployments (hence the name).
|
41
|
+
#
|
42
|
+
# A value of 20 (SECURE) disallows the document from attempting to read files
|
43
|
+
# from the file system and including the contents of them into the document,
|
44
|
+
# in addition to all the security features of SafeMode::SECURE. In
|
45
|
+
# particular, it disallows use of the include::[] macro and the embedding of
|
46
|
+
# binary content (data uri), stylesheets and JavaScripts referenced by the
|
47
|
+
# document. (Asciidoctor and trusted extensions may still be allowed to embed
|
48
|
+
# trusted content into the document).
|
49
|
+
#
|
50
|
+
# Since Asciidoctor is aiming for wide adoption, 20 (SECURE) is the default
|
51
|
+
# value and is recommended for server-side deployments.
|
41
52
|
#
|
42
53
|
# A value of 100 (PARANOID) is planned to disallow the use of passthrough
|
43
54
|
# macros and prevents the document from setting any known attributes in
|
@@ -48,13 +59,17 @@ class Asciidoctor::Document < Asciidoctor::AbstractBlock
|
|
48
59
|
# Public: Get the Hash of document references
|
49
60
|
attr_reader :references
|
50
61
|
|
62
|
+
# Public: Get the Hash of document counters
|
63
|
+
attr_reader :counters
|
64
|
+
|
51
65
|
# Public: Get the Hash of callouts
|
52
66
|
attr_reader :callouts
|
53
67
|
|
54
68
|
# Public: The section level 0 block
|
55
69
|
attr_reader :header
|
56
70
|
|
57
|
-
# Public: Base directory for rendering this document
|
71
|
+
# Public: Base directory for rendering this document. Defaults to directory of the source file.
|
72
|
+
# If the source is a string, defaults to the current directory.
|
58
73
|
attr_reader :base_dir
|
59
74
|
|
60
75
|
# Public: A reference to the parent document of this nested document.
|
@@ -82,6 +97,8 @@ class Asciidoctor::Document < Asciidoctor::AbstractBlock
|
|
82
97
|
@parent_document = options.delete(:parent)
|
83
98
|
# should we dup here?
|
84
99
|
options[:attributes] = @parent_document.attributes
|
100
|
+
options[:safe] ||= @parent_document.safe
|
101
|
+
options[:base_dir] ||= @parent_document.base_dir
|
85
102
|
@renderer = @parent_document.renderer
|
86
103
|
else
|
87
104
|
@parent_document = nil
|
@@ -90,17 +107,20 @@ class Asciidoctor::Document < Asciidoctor::AbstractBlock
|
|
90
107
|
@header = nil
|
91
108
|
@references = {
|
92
109
|
:ids => {},
|
110
|
+
:footnotes => [],
|
93
111
|
:links => [],
|
94
|
-
:images => []
|
112
|
+
:images => [],
|
113
|
+
:indexterms => []
|
95
114
|
}
|
115
|
+
@counters = {}
|
96
116
|
@callouts = Callouts.new
|
97
117
|
@options = options
|
98
118
|
@safe = @options.fetch(:safe, SafeMode::SECURE).to_i
|
99
|
-
@options[:header_footer] = @options.fetch(:header_footer,
|
119
|
+
@options[:header_footer] = @options.fetch(:header_footer, false)
|
100
120
|
|
101
|
-
@attributes['asciidoctor'] =
|
121
|
+
@attributes['asciidoctor'] = ''
|
102
122
|
@attributes['asciidoctor-version'] = VERSION
|
103
|
-
@attributes['sectids'] =
|
123
|
+
@attributes['sectids'] = ''
|
104
124
|
@attributes['encoding'] = 'UTF-8'
|
105
125
|
|
106
126
|
attribute_overrides = options[:attributes] || {}
|
@@ -109,35 +129,58 @@ class Asciidoctor::Document < Asciidoctor::AbstractBlock
|
|
109
129
|
# 10 is the AsciiDoc default, though currently Asciidoctor only supports 1 level
|
110
130
|
attribute_overrides['include-depth'] ||= 10
|
111
131
|
|
112
|
-
#
|
113
|
-
#
|
114
|
-
|
115
|
-
|
132
|
+
# if the base_dir option is specified, it overrides docdir as the root for relative paths
|
133
|
+
# otherwise, the base_dir is the directory of the source file (docdir) or the current
|
134
|
+
# directory of the input is a string
|
135
|
+
if options[:base_dir].nil?
|
136
|
+
if attribute_overrides['docdir']
|
137
|
+
@base_dir = attribute_overrides['docdir'] = File.expand_path(attribute_overrides['docdir'])
|
138
|
+
else
|
139
|
+
# perhaps issue a warning here?
|
140
|
+
@base_dir = attribute_overrides['docdir'] = Dir.pwd
|
141
|
+
end
|
116
142
|
else
|
117
|
-
attribute_overrides['docdir']
|
118
|
-
@base_dir = attribute_overrides['docdir']
|
143
|
+
@base_dir = attribute_overrides['docdir'] = File.expand_path(options[:base_dir])
|
119
144
|
end
|
120
145
|
|
121
|
-
|
122
|
-
|
123
|
-
if @safe >= SafeMode::SECURE
|
146
|
+
if @safe >= SafeMode::SERVER
|
147
|
+
# restrict document from setting source-highlighter and backend
|
124
148
|
attribute_overrides['source-highlighter'] ||= nil
|
149
|
+
attribute_overrides['backend'] ||= DEFAULT_BACKEND
|
150
|
+
# restrict document from seeing the docdir and trim docfile to relative path
|
151
|
+
if attribute_overrides.has_key?('docfile') && @parent_document.nil?
|
152
|
+
attribute_overrides['docfile'] = attribute_overrides['docfile'][(attribute_overrides['docdir'].length + 1)..-1]
|
153
|
+
end
|
154
|
+
attribute_overrides['docdir'] = ''
|
155
|
+
# restrict document from enabling icons
|
156
|
+
if @safe >= SafeMode::SECURE
|
157
|
+
attribute_overrides['icons'] ||= nil
|
158
|
+
end
|
125
159
|
end
|
126
160
|
|
127
|
-
attribute_overrides.
|
161
|
+
attribute_overrides.delete_if {|key, val|
|
162
|
+
verdict = false
|
128
163
|
# a nil or negative key undefines the attribute
|
129
|
-
if
|
164
|
+
if val.nil? || key[-1..-1] == '!'
|
130
165
|
@attributes.delete(key.chomp '!')
|
131
166
|
# otherwise it's an attribute assignment
|
132
167
|
else
|
168
|
+
# a value ending in @ indicates this attribute does not override
|
169
|
+
# an attribute with the same key in the document souce
|
170
|
+
if val.is_a?(String) && val.end_with?('@')
|
171
|
+
val.chop!
|
172
|
+
verdict = true
|
173
|
+
end
|
133
174
|
@attributes[key] = val
|
134
175
|
end
|
176
|
+
verdict
|
135
177
|
}
|
136
178
|
|
137
179
|
@attributes['backend'] ||= DEFAULT_BACKEND
|
180
|
+
@attributes['doctype'] ||= DEFAULT_DOCTYPE
|
138
181
|
update_backend_attributes
|
139
182
|
|
140
|
-
if
|
183
|
+
if !@parent_document.nil?
|
141
184
|
# don't need to do the extra processing within our own document
|
142
185
|
@reader = Reader.new(data)
|
143
186
|
else
|
@@ -145,16 +188,16 @@ class Asciidoctor::Document < Asciidoctor::AbstractBlock
|
|
145
188
|
end
|
146
189
|
|
147
190
|
# dynamic intrinstic attribute values
|
148
|
-
@attributes['doctype'] ||= DEFAULT_DOCTYPE
|
149
|
-
|
150
191
|
now = Time.new
|
151
192
|
@attributes['localdate'] ||= now.strftime('%Y-%m-%d')
|
152
|
-
@attributes['localtime'] ||= now.strftime('%H:%
|
153
|
-
@attributes['localdatetime'] ||= [@attributes['localdate'], @attributes['localtime']]
|
193
|
+
@attributes['localtime'] ||= now.strftime('%H:%M:%S %Z')
|
194
|
+
@attributes['localdatetime'] ||= [@attributes['localdate'], @attributes['localtime']] * ' '
|
154
195
|
|
155
|
-
# docdate and
|
196
|
+
# docdate, doctime and docdatetime should default to
|
197
|
+
# localdate, localtime and localdatetime if not otherwise set
|
156
198
|
@attributes['docdate'] ||= @attributes['localdate']
|
157
199
|
@attributes['doctime'] ||= @attributes['localtime']
|
200
|
+
@attributes['docdatetime'] ||= @attributes['localdatetime']
|
158
201
|
|
159
202
|
@attributes['iconsdir'] ||= File.join(@attributes.fetch('imagesdir', 'images'), 'icons')
|
160
203
|
|
@@ -175,15 +218,61 @@ class Asciidoctor::Document < Asciidoctor::AbstractBlock
|
|
175
218
|
}
|
176
219
|
end
|
177
220
|
|
221
|
+
# Public: Get the named counter and take the next number in the sequence.
|
222
|
+
#
|
223
|
+
# name - the String name of the counter
|
224
|
+
# seed - the initial value as a String or Integer
|
225
|
+
#
|
226
|
+
# returns the next number in the sequence for the specified counter
|
227
|
+
def counter(name, seed = nil)
|
228
|
+
if !@counters.has_key? name
|
229
|
+
if seed.nil?
|
230
|
+
seed = nextval(@attributes.has_key?(name) ? @attributes[name] : 0)
|
231
|
+
elsif seed.to_i.to_s == seed
|
232
|
+
seed = seed.to_i
|
233
|
+
end
|
234
|
+
@counters[name] = seed
|
235
|
+
else
|
236
|
+
@counters[name] = nextval(@counters[name])
|
237
|
+
end
|
238
|
+
|
239
|
+
(@attributes[name] = @counters[name])
|
240
|
+
end
|
241
|
+
|
242
|
+
# Internal: Get the next value in the sequence.
|
243
|
+
#
|
244
|
+
# Handles both integer and character sequences.
|
245
|
+
#
|
246
|
+
# current - the value to increment as a String or Integer
|
247
|
+
#
|
248
|
+
# returns the next value in the sequence according to the current value's type
|
249
|
+
def nextval(current)
|
250
|
+
if current.is_a?(Integer)
|
251
|
+
current + 1
|
252
|
+
else
|
253
|
+
intval = current.to_i
|
254
|
+
if intval.to_s != current.to_s
|
255
|
+
(current[0].ord + 1).chr
|
256
|
+
else
|
257
|
+
intval + 1
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
178
262
|
def register(type, value)
|
179
|
-
|
263
|
+
case type
|
264
|
+
when :ids
|
180
265
|
if value.is_a?(Array)
|
181
266
|
@references[:ids][value[0]] = (value[1] || '[' + value[0] + ']')
|
182
267
|
else
|
183
268
|
@references[:ids][value] = '[' + value + ']'
|
184
269
|
end
|
185
|
-
|
270
|
+
when :footnotes, :indexterms
|
186
271
|
@references[type] << value
|
272
|
+
else
|
273
|
+
if @options[:catalog_assets]
|
274
|
+
@references[type] << value
|
275
|
+
end
|
187
276
|
end
|
188
277
|
end
|
189
278
|
|
@@ -242,6 +331,9 @@ class Asciidoctor::Document < Asciidoctor::AbstractBlock
|
|
242
331
|
# Public: Update the backend attributes to reflect a change in the selected backend
|
243
332
|
def update_backend_attributes()
|
244
333
|
backend = @attributes['backend']
|
334
|
+
if BACKEND_ALIASES.has_key? backend
|
335
|
+
backend = @attributes['backend'] = BACKEND_ALIASES[backend]
|
336
|
+
end
|
245
337
|
basebackend = backend.sub(/[[:digit:]]+$/, '')
|
246
338
|
page_width = DEFAULT_PAGE_WIDTHS[basebackend]
|
247
339
|
if page_width
|
@@ -249,9 +341,17 @@ class Asciidoctor::Document < Asciidoctor::AbstractBlock
|
|
249
341
|
else
|
250
342
|
@attributes.delete('pagewidth')
|
251
343
|
end
|
252
|
-
@attributes[
|
344
|
+
@attributes["backend-#{backend}"] = ''
|
253
345
|
@attributes['basebackend'] = basebackend
|
254
|
-
@attributes[
|
346
|
+
@attributes["basebackend-#{basebackend}"] = ''
|
347
|
+
# REVIEW cases for the next two assignments
|
348
|
+
@attributes["#{backend}-#{@attributes['doctype']}"] = ''
|
349
|
+
@attributes["#{basebackend}-#{@attributes['doctype']}"] = ''
|
350
|
+
ext = DEFAULT_EXTENSIONS[basebackend] || '.html'
|
351
|
+
@attributes['outfilesuffix'] = ext
|
352
|
+
file_type = ext[1..-1]
|
353
|
+
@attributes['filetype'] = file_type
|
354
|
+
@attributes["filetype-#{file_type}"] = ''
|
255
355
|
end
|
256
356
|
|
257
357
|
def splain
|
@@ -301,7 +401,7 @@ class Asciidoctor::Document < Asciidoctor::AbstractBlock
|
|
301
401
|
# using the appropriate built-in template.
|
302
402
|
def render(opts = {})
|
303
403
|
r = renderer(opts)
|
304
|
-
@options.merge(opts)[:header_footer] ? r.render('document', self) : r.render('embedded', self)
|
404
|
+
@options.merge(opts)[:header_footer] ? r.render('document', self).strip : r.render('embedded', self)
|
305
405
|
end
|
306
406
|
|
307
407
|
def content
|