asciidoctor 1.5.8 → 2.0.0.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +162 -17
- data/LICENSE +1 -1
- data/README-de.adoc +12 -13
- data/README-fr.adoc +11 -12
- data/README-jp.adoc +11 -12
- data/README-zh_CN.adoc +12 -13
- data/README.adoc +6 -7
- data/asciidoctor.gemspec +19 -24
- data/bin/asciidoctor +5 -4
- data/data/reference/syntax.adoc +283 -0
- data/data/stylesheets/asciidoctor-default.css +56 -52
- data/data/stylesheets/coderay-asciidoctor.css +7 -9
- data/lib/asciidoctor.rb +171 -232
- data/lib/asciidoctor/abstract_block.rb +96 -105
- data/lib/asciidoctor/abstract_node.rb +118 -139
- data/lib/asciidoctor/attribute_list.rb +10 -14
- data/lib/asciidoctor/block.rb +20 -19
- data/lib/asciidoctor/callouts.rb +4 -2
- data/lib/asciidoctor/cli.rb +3 -2
- data/lib/asciidoctor/cli/invoker.rb +14 -21
- data/lib/asciidoctor/cli/options.rb +64 -54
- data/lib/asciidoctor/converter.rb +357 -185
- data/lib/asciidoctor/converter/composite.rb +40 -48
- data/lib/asciidoctor/converter/docbook5.rb +604 -640
- data/lib/asciidoctor/converter/html5.rb +949 -963
- data/lib/asciidoctor/converter/manpage.rb +569 -548
- data/lib/asciidoctor/converter/template.rb +231 -272
- data/lib/asciidoctor/core_ext.rb +5 -18
- data/lib/asciidoctor/core_ext/float/truncate.rb +19 -0
- data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
- data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
- data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
- data/lib/asciidoctor/document.rb +399 -377
- data/lib/asciidoctor/extensions.rb +72 -140
- data/lib/asciidoctor/helpers.rb +122 -83
- data/lib/asciidoctor/inline.rb +5 -1
- data/lib/asciidoctor/list.rb +13 -11
- data/lib/asciidoctor/logging.rb +17 -16
- data/lib/asciidoctor/parser.rb +390 -423
- data/lib/asciidoctor/path_resolver.rb +10 -5
- data/lib/asciidoctor/reader.rb +286 -263
- data/lib/asciidoctor/rouge_ext.rb +39 -0
- data/lib/asciidoctor/section.rb +9 -8
- data/lib/asciidoctor/stylesheets.rb +19 -37
- data/lib/asciidoctor/substitutors.rb +364 -509
- data/lib/asciidoctor/syntax_highlighter.rb +238 -0
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +87 -0
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +26 -0
- data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +27 -0
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +149 -0
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +129 -0
- data/lib/asciidoctor/table.rb +73 -66
- data/lib/asciidoctor/timings.rb +4 -2
- data/lib/asciidoctor/version.rb +2 -1
- data/lib/asciidoctor/writer.rb +30 -0
- data/man/asciidoctor.1 +19 -15
- data/man/asciidoctor.adoc +14 -12
- metadata +69 -216
- data/CONTRIBUTING.adoc +0 -185
- data/Gemfile +0 -60
- data/Rakefile +0 -129
- data/bin/asciidoctor-safe +0 -15
- data/features/open_block.feature +0 -92
- data/features/pass_block.feature +0 -66
- data/features/step_definitions.rb +0 -49
- data/features/text_formatting.feature +0 -57
- data/features/xref.feature +0 -1039
- data/lib/asciidoctor/converter/base.rb +0 -59
- data/lib/asciidoctor/converter/docbook45.rb +0 -93
- data/lib/asciidoctor/converter/factory.rb +0 -226
- data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
- data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
- data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
- data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
- data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
- data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
- data/test/api_test.rb +0 -1240
- data/test/attribute_list_test.rb +0 -242
- data/test/attributes_test.rb +0 -1623
- data/test/blocks_test.rb +0 -3870
- data/test/converter_test.rb +0 -470
- data/test/document_test.rb +0 -1853
- data/test/extensions_test.rb +0 -1560
- data/test/fixtures/asciidoc_index.txt +0 -521
- data/test/fixtures/basic-docinfo-footer.html +0 -6
- data/test/fixtures/basic-docinfo-footer.xml +0 -8
- data/test/fixtures/basic-docinfo.html +0 -1
- data/test/fixtures/basic-docinfo.xml +0 -4
- data/test/fixtures/basic.asciidoc +0 -5
- data/test/fixtures/chapter-a.adoc +0 -3
- data/test/fixtures/child-include.adoc +0 -5
- data/test/fixtures/circle.svg +0 -9
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
- data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
- data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
- data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
- data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
- data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
- data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
- data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
- data/test/fixtures/docinfo-footer.html +0 -1
- data/test/fixtures/docinfo-footer.xml +0 -9
- data/test/fixtures/docinfo.html +0 -1
- data/test/fixtures/docinfo.xml +0 -3
- data/test/fixtures/doctime-localtime.adoc +0 -2
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +0 -13
- data/test/fixtures/file-with-missing-include.adoc +0 -1
- data/test/fixtures/grandchild-include.adoc +0 -3
- data/test/fixtures/hello-asciidoctor.pdf +0 -69
- data/test/fixtures/include-file.asciidoc +0 -24
- data/test/fixtures/include-file.jsx +0 -8
- data/test/fixtures/include-file.ml +0 -3
- data/test/fixtures/include-file.xml +0 -5
- data/test/fixtures/lists.adoc +0 -96
- data/test/fixtures/master.adoc +0 -5
- data/test/fixtures/mismatched-end-tag.adoc +0 -7
- data/test/fixtures/other-chapters.adoc +0 -11
- data/test/fixtures/outer-include.adoc +0 -5
- data/test/fixtures/parent-include-restricted.adoc +0 -5
- data/test/fixtures/parent-include.adoc +0 -5
- data/test/fixtures/sample.asciidoc +0 -30
- data/test/fixtures/section-a.adoc +0 -4
- data/test/fixtures/stylesheets/custom.css +0 -3
- data/test/fixtures/subdir/index.adoc +0 -3
- data/test/fixtures/subdir/inner-include.adoc +0 -3
- data/test/fixtures/subdir/middle-include.adoc +0 -5
- data/test/fixtures/subs-docinfo.html +0 -2
- data/test/fixtures/subs.adoc +0 -6
- data/test/fixtures/tagged-class-enclosed.rb +0 -25
- data/test/fixtures/tagged-class.rb +0 -23
- data/test/fixtures/tip.gif +0 -0
- data/test/fixtures/unclosed-tag.adoc +0 -3
- data/test/fixtures/unexpected-end-tag.adoc +0 -4
- data/test/invoker_test.rb +0 -745
- data/test/links_test.rb +0 -855
- data/test/lists_test.rb +0 -5151
- data/test/logger_test.rb +0 -211
- data/test/manpage_test.rb +0 -660
- data/test/options_test.rb +0 -262
- data/test/paragraphs_test.rb +0 -562
- data/test/parser_test.rb +0 -742
- data/test/paths_test.rb +0 -395
- data/test/preamble_test.rb +0 -173
- data/test/reader_test.rb +0 -2161
- data/test/sections_test.rb +0 -3575
- data/test/substitutions_test.rb +0 -2066
- data/test/tables_test.rb +0 -2036
- data/test/test_helper.rb +0 -447
- data/test/text_test.rb +0 -309
@@ -1,232 +1,404 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# A module for defining converters that are used to convert {AbstractNode} objects in a parsed AsciiDoc document to an
|
4
|
+
# output (aka backend) format such as HTML or DocBook.
|
5
|
+
#
|
6
|
+
# Implementing a custom converter involves:
|
7
|
+
#
|
8
|
+
# * Including the {Converter} module in a converter class and implementing the {Converter#convert} method or extending
|
9
|
+
# the {Converter::Base Base} class and implementing the dispatch methods that map to each node.
|
10
|
+
# * Optionally registering the converter with one or more backend names statically using the +register_for+ DSL method
|
11
|
+
# contributed by the {Converter::Config Config} module.
|
12
|
+
#
|
13
|
+
# {Converter} instances are typically instantiated for each instance of a parsed AsciiDoc document.
|
14
|
+
#
|
15
|
+
# Examples
|
16
|
+
#
|
17
|
+
# class TextConverter
|
18
|
+
# include Asciidoctor::Converter
|
19
|
+
# register_for 'text'
|
20
|
+
# def initialize *args
|
21
|
+
# super
|
22
|
+
# outfilesuffix '.txt'
|
23
|
+
# end
|
24
|
+
# def convert node, transform = nil, opts = nil
|
25
|
+
# case (transform ||= node.node_name)
|
26
|
+
# when 'document', 'section'
|
27
|
+
# [node.title, node.content].join %(\n\n)
|
28
|
+
# when 'paragraph'
|
29
|
+
# (node.content.tr ?\n, ' ') << ?\n
|
30
|
+
# else
|
31
|
+
# (transform.start_with? 'inline_') ? node.text : node.content
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
# puts Asciidoctor.convert_file 'sample.adoc', backend: :text
|
36
|
+
#
|
37
|
+
# class Html5Converter < (Asciidoctor::Converter.for 'html5')
|
38
|
+
# register_for 'html5'
|
39
|
+
# def paragraph node
|
40
|
+
# %(<p>#{node.content}</p>)
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
# puts Asciidoctor.convert_file 'sample.adoc'
|
44
|
+
module Converter
|
45
|
+
autoload :CompositeConverter, %(#{__dir__}/converter/composite)
|
46
|
+
autoload :TemplateConverter, %(#{__dir__}/converter/template)
|
47
|
+
|
48
|
+
# Public: The String backend name that this converter is handling.
|
49
|
+
attr_reader :backend
|
50
|
+
|
51
|
+
# Public: Creates a new instance of this {Converter}.
|
6
52
|
#
|
7
|
-
#
|
53
|
+
# backend - The String backend name (aka format) to which this converter converts.
|
54
|
+
# opts - An options Hash (optional, default: {})
|
8
55
|
#
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
56
|
+
# Returns a new [Converter] instance.
|
57
|
+
def initialize backend, opts = {}
|
58
|
+
@backend = backend
|
59
|
+
end
|
60
|
+
|
61
|
+
# Public: Converts an {AbstractNode} using the given transform.
|
13
62
|
#
|
14
|
-
#
|
63
|
+
# This method must be implemented by a concrete converter class.
|
15
64
|
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# outfilesuffix '.txt'
|
22
|
-
# end
|
23
|
-
# def convert node, transform = nil, opts = {}
|
24
|
-
# case (transform ||= node.node_name)
|
25
|
-
# when 'document'
|
26
|
-
# node.content
|
27
|
-
# when 'section'
|
28
|
-
# [node.title, node.content].join "\n\n"
|
29
|
-
# when 'paragraph'
|
30
|
-
# node.content.tr("\n", ' ') << "\n"
|
31
|
-
# else
|
32
|
-
# if transform.start_with? 'inline_'
|
33
|
-
# node.text
|
34
|
-
# else
|
35
|
-
# %(<#{transform}>\n)
|
36
|
-
# end
|
37
|
-
# end
|
38
|
-
# end
|
39
|
-
# end
|
65
|
+
# node - The concrete instance of AbstractNode to convert.
|
66
|
+
# transform - An optional String transform that hints at which transformation should be applied to this node. If a
|
67
|
+
# transform is not given, the transform is often derived from the value of the {AbstractNode#node_name}
|
68
|
+
# property. (optional, default: nil)
|
69
|
+
# opts - An optional Hash of options hints about how to convert the node. (optional, default: nil)
|
40
70
|
#
|
41
|
-
#
|
42
|
-
|
43
|
-
#
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
metaclass.send :define_method, :converts? do |name|
|
64
|
-
backends.include? name
|
65
|
-
end
|
66
|
-
end
|
67
|
-
nil
|
68
|
-
end
|
71
|
+
# Returns the [String] result.
|
72
|
+
def convert node, transform = nil, opts = nil
|
73
|
+
raise ::NotImplementedError, %(#{self.class} (backend: #{@backend}) must implement the ##{__method__} method)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Public: Reports whether the current converter is able to convert this node (by its name). Used by the
|
77
|
+
# {CompositeConverter} to select which converter to use to handle a given node. Returns true by default.
|
78
|
+
#
|
79
|
+
# name - the String name of the node to convert.
|
80
|
+
#
|
81
|
+
# Returns a [Boolean] indicating whether this converter can handle the specified node by name.
|
82
|
+
def handles? name
|
83
|
+
true
|
84
|
+
end
|
85
|
+
|
86
|
+
module BackendTraits
|
87
|
+
def basebackend value = nil
|
88
|
+
value ? (backend_traits[:basebackend] = value) : backend_traits[:basebackend]
|
89
|
+
end
|
90
|
+
|
91
|
+
def filetype value = nil
|
92
|
+
value ? (backend_traits[:filetype] = value) : backend_traits[:filetype]
|
69
93
|
end
|
70
94
|
|
71
|
-
|
72
|
-
|
73
|
-
|
95
|
+
def htmlsyntax value = nil
|
96
|
+
value ? (backend_traits[:htmlsyntax] = value) : backend_traits[:htmlsyntax]
|
97
|
+
end
|
98
|
+
|
99
|
+
def outfilesuffix value = nil
|
100
|
+
value ? (backend_traits[:outfilesuffix] = value) : backend_traits[:outfilesuffix]
|
101
|
+
end
|
102
|
+
|
103
|
+
def supports_templates value = true
|
104
|
+
backend_traits[:supports_templates] = value
|
105
|
+
end
|
106
|
+
|
107
|
+
def supports_templates?
|
108
|
+
backend_traits[:supports_templates]
|
109
|
+
end
|
110
|
+
|
111
|
+
def init_backend_traits value = nil
|
112
|
+
@backend_traits = value || {}
|
113
|
+
end
|
114
|
+
|
115
|
+
def backend_traits
|
116
|
+
@backend_traits ||= derive_backend_traits
|
117
|
+
end
|
118
|
+
|
119
|
+
alias backend_info backend_traits
|
120
|
+
|
121
|
+
private def derive_backend_traits
|
122
|
+
BackendTraits.derive_backend_traits @backend
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.derive_backend_traits backend
|
126
|
+
return {} unless backend
|
127
|
+
if (t_outfilesuffix = DEFAULT_EXTENSIONS[(t_basebackend = backend.sub TrailingDigitsRx, '')])
|
128
|
+
t_filetype = t_outfilesuffix.slice 1, t_outfilesuffix.length
|
129
|
+
else
|
130
|
+
t_outfilesuffix = %(.#{t_filetype = t_basebackend})
|
74
131
|
end
|
132
|
+
t_filetype == 'html' ?
|
133
|
+
{ basebackend: t_basebackend, filetype: t_filetype, htmlsyntax: 'html', outfilesuffix: t_outfilesuffix } :
|
134
|
+
{ basebackend: t_basebackend, filetype: t_filetype, outfilesuffix: t_outfilesuffix }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# A module that contributes the +register_for+ method for registering a converter with the default registry.
|
139
|
+
module Config
|
140
|
+
# Public: Registers this {Converter} class with the default registry to handle the specified backend name(s).
|
141
|
+
#
|
142
|
+
# backends - One or more String backend names with which to associate this {Converter} class.
|
143
|
+
#
|
144
|
+
# Returns nothing.
|
145
|
+
private def register_for *backends
|
146
|
+
Converter.register self, *backends
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# A reusable module for registering and instantiating {Converter Converter} classes used to convert an {AbstractNode}
|
151
|
+
# to an output (aka backend) format such as HTML or DocBook.
|
152
|
+
#
|
153
|
+
# {Converter Converter} objects are instantiated by passing a String backend name and, optionally, an options Hash to
|
154
|
+
# the {Factory#create} method. The backend can be thought of as an intent to convert a document to a specified format.
|
155
|
+
#
|
156
|
+
# Applications interact with the factory either through the global, static registry mixed into the {Converter
|
157
|
+
# Converter} module or a concrete class that includes this module such as {CustomFactory}. For example:
|
158
|
+
#
|
159
|
+
# Examples
|
160
|
+
#
|
161
|
+
# converter = Asciidoctor::Converter.create 'html5', htmlsyntax: 'xml'
|
162
|
+
module Factory
|
163
|
+
# Public: Create an instance of DefaultProxyFactory or CustomFactory, depending on whether the proxy_default keyword
|
164
|
+
# arg is set (true by default), and optionally seed it with the specified converters map. If proxy_default is set,
|
165
|
+
# entries in the proxy registry are preferred over matching entries from the default registry.
|
166
|
+
#
|
167
|
+
# converters - An optional Hash of converters to use in place of ones in the default registry. The keys are
|
168
|
+
# backend names and the values are converter classes or instances.
|
169
|
+
# proxy_default - A Boolean keyword arg indicating whether to proxy the default registry (optional, default: true).
|
170
|
+
#
|
171
|
+
# Returns a Factory instance (DefaultFactoryProxy or CustomFactory) seeded with the optional converters map.
|
172
|
+
def self.new converters = nil, proxy_default: true
|
173
|
+
proxy_default ? (DefaultFactoryProxy.new converters) : (CustomFactory.new converters)
|
174
|
+
end
|
75
175
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
176
|
+
# Deprecated: Maps the old default factory instance holder to the Converter module.
|
177
|
+
def self.default *args
|
178
|
+
Converter
|
179
|
+
end
|
180
|
+
|
181
|
+
# Deprecated: Maps the create method on the old default factory instance holder to the Converter module.
|
182
|
+
def self.create backend, opts = {}
|
183
|
+
default.create backend, opts
|
184
|
+
end
|
185
|
+
|
186
|
+
# Public: Register a custom converter with this factory to handle conversion for the specified backends. If the
|
187
|
+
# backend is an asterisk (i.e., +*+), the converter will handle any backend for which a converter is not registered.
|
188
|
+
#
|
189
|
+
# converter - The Converter class to register.
|
190
|
+
# backends - One or more String backend names that this converter should be registered to handle.
|
191
|
+
#
|
192
|
+
# Returns nothing
|
193
|
+
def register converter, *backends
|
194
|
+
backends.each {|backend| backend == '*' ? (registry.default = converter) : (registry[backend] = converter) }
|
195
|
+
end
|
196
|
+
|
197
|
+
# Public: Lookup the custom converter registered with this factory to handle the specified backend.
|
198
|
+
#
|
199
|
+
# backend - The String backend name.
|
200
|
+
#
|
201
|
+
# Returns the [Converter] class registered to convert the specified backend or nil if no match is found.
|
202
|
+
def for backend
|
203
|
+
registry[backend]
|
204
|
+
end
|
205
|
+
|
206
|
+
# Public: Create a new Converter object that can be used to convert {AbstractNode}s to the format associated with
|
207
|
+
# the backend. This method accepts an optional Hash of options that are passed to the converter's constructor.
|
208
|
+
#
|
209
|
+
# If a custom Converter is found to convert the specified backend, it's instantiated (if necessary) and returned
|
210
|
+
# immediately. If a custom Converter is not found, an attempt is made to find a built-in converter. If the
|
211
|
+
# +:template_dirs+ key is found in the Hash passed as the second argument, a {CompositeConverter} is created that
|
212
|
+
# delegates to a {TemplateConverter} and, if found, the built-in converter. If the +:template_dirs+ key is not
|
213
|
+
# found, the built-in converter is returned or nil if no converter is found.
|
214
|
+
#
|
215
|
+
# backend - the String backend name.
|
216
|
+
# opts - a Hash of options to customize creation; also passed to the converter's constructor:
|
217
|
+
# :template_dirs - a String Array of directories used to instantiate a {TemplateConverter} (optional).
|
218
|
+
# :delegate_backend - a backend String of the last converter in the {CompositeConverter} chain (optional).
|
219
|
+
#
|
220
|
+
# Returns the [Converter] instance.
|
221
|
+
def create backend, opts = {}
|
222
|
+
if (converter = self.for backend)
|
223
|
+
converter = converter.new backend, opts if ::Class === converter
|
224
|
+
if (template_dirs = opts[:template_dirs]) && BackendTraits === converter && converter.supports_templates?
|
225
|
+
CompositeConverter.new backend, (TemplateConverter.new backend, template_dirs, opts), converter, backend_traits_source: converter
|
81
226
|
else
|
82
|
-
|
83
|
-
base = 'html'
|
84
|
-
ext = '.html'
|
85
|
-
type = 'html'
|
86
|
-
syntax = 'html'
|
227
|
+
converter
|
87
228
|
end
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
:htmlsyntax => syntax
|
93
|
-
}
|
94
|
-
end
|
95
|
-
|
96
|
-
def filetype value = nil
|
97
|
-
if value
|
98
|
-
backend_info[:filetype] = value
|
229
|
+
elsif (template_dirs = opts[:template_dirs])
|
230
|
+
if (delegate_backend = opts[:delegate_backend]) && (converter = self.for delegate_backend)
|
231
|
+
converter = converter.new delegate_backend, opts if ::Class === converter
|
232
|
+
CompositeConverter.new backend, (TemplateConverter.new backend, template_dirs, opts), converter, backend_traits_source: converter
|
99
233
|
else
|
100
|
-
|
234
|
+
TemplateConverter.new backend, template_dirs, opts
|
101
235
|
end
|
102
236
|
end
|
237
|
+
end
|
103
238
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
239
|
+
# Public: Get the Hash of Converter classes keyed by backend name. Intended for testing only.
|
240
|
+
def converters
|
241
|
+
registry.dup
|
242
|
+
end
|
243
|
+
|
244
|
+
private def registry
|
245
|
+
raise ::NotImplementedError, %(#{Factory} subclass #{self.class} must implement the ##{__method__} method)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
class CustomFactory
|
250
|
+
include Factory
|
251
|
+
|
252
|
+
def initialize seed_registry = nil
|
253
|
+
if seed_registry
|
254
|
+
seed_registry.default = seed_registry.delete '*'
|
255
|
+
else
|
256
|
+
seed_registry = {}
|
110
257
|
end
|
258
|
+
@registry = seed_registry
|
259
|
+
end
|
260
|
+
|
261
|
+
# Public: Unregister all Converter classes that are registered with this factory. Intended for testing only.
|
262
|
+
#
|
263
|
+
# Returns nothing.
|
264
|
+
def unregister_all
|
265
|
+
registry.clear.default = nil
|
266
|
+
end
|
267
|
+
|
268
|
+
private
|
269
|
+
|
270
|
+
attr_reader :registry
|
271
|
+
end
|
272
|
+
|
273
|
+
# Mixed into the {Converter} module to provide the global registry of converters that are registered statically.
|
274
|
+
#
|
275
|
+
# This registry includes built-in converters for {Html5Converter HTML 5}, {DocBook5Converter DocBook 5} and
|
276
|
+
# {ManPageConverter man(ual) page}, as well as any custom converters that have been discovered or explicitly
|
277
|
+
# registered. Converter registration is synchronized (where applicable) and is thus guaranteed to be thread safe.
|
278
|
+
module DefaultFactory
|
279
|
+
include Factory
|
280
|
+
|
281
|
+
private
|
282
|
+
|
283
|
+
@@registry = {}
|
111
284
|
|
112
|
-
|
113
|
-
|
114
|
-
|
285
|
+
def registry
|
286
|
+
@@registry
|
287
|
+
end
|
288
|
+
|
289
|
+
unless RUBY_ENGINE == 'opal' # the following block adds support for synchronization and lazy registration
|
290
|
+
public
|
291
|
+
|
292
|
+
def register converter, *backends
|
293
|
+
if @@mutex.owned?
|
294
|
+
backends.each {|backend| backend == '*' ? (@@catch_all = converter) : (@@registry = @@registry.merge backend => converter) }
|
115
295
|
else
|
116
|
-
|
296
|
+
@@mutex.synchronize { register converter, *backends }
|
117
297
|
end
|
118
298
|
end
|
119
299
|
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
backend_info[:htmlsyntax]
|
300
|
+
def unregister_all
|
301
|
+
@@mutex.synchronize do
|
302
|
+
@@registry = @@registry.select {|backend| PROVIDED[backend] }
|
303
|
+
@@catch_all = nil
|
125
304
|
end
|
126
305
|
end
|
127
306
|
|
128
|
-
def
|
129
|
-
|
307
|
+
def for backend
|
308
|
+
@@registry.fetch backend do
|
309
|
+
PROVIDED[backend] ? @@mutex.synchronize do
|
310
|
+
# require is thread-safe, so no reason to refetch
|
311
|
+
require PROVIDED[backend]
|
312
|
+
@@registry[backend]
|
313
|
+
end : catch_all
|
314
|
+
end
|
130
315
|
end
|
131
316
|
|
132
|
-
|
133
|
-
|
317
|
+
PROVIDED = {
|
318
|
+
'docbook5' => %(#{__dir__}/converter/docbook5),
|
319
|
+
'html5' => %(#{__dir__}/converter/html5),
|
320
|
+
'manpage' => %(#{__dir__}/converter/manpage),
|
321
|
+
}
|
322
|
+
|
323
|
+
private
|
324
|
+
|
325
|
+
def catch_all
|
326
|
+
@@catch_all
|
134
327
|
end
|
328
|
+
|
329
|
+
@@catch_all = nil
|
330
|
+
@@mutex = ::Mutex.new
|
135
331
|
end
|
332
|
+
end
|
333
|
+
|
334
|
+
class DefaultFactoryProxy < CustomFactory
|
335
|
+
include DefaultFactory # inserts module into ancestors immediately after superclass
|
136
336
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
#
|
142
|
-
# Returns nothing
|
143
|
-
def included converter
|
144
|
-
converter.extend Config
|
337
|
+
unless RUBY_ENGINE == 'opal'
|
338
|
+
def unregister_all
|
339
|
+
super
|
340
|
+
@registry.clear.default = nil
|
145
341
|
end
|
146
|
-
end
|
147
342
|
|
148
|
-
|
149
|
-
|
343
|
+
def for backend
|
344
|
+
@registry.fetch(backend) { super }
|
345
|
+
end
|
150
346
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
# opts - An options Hash (optional, default: {})
|
155
|
-
#
|
156
|
-
# Returns a new instance of [Converter]
|
157
|
-
def initialize backend, opts = {}
|
158
|
-
@backend = backend
|
159
|
-
setup_backend_info
|
347
|
+
private def catch_all
|
348
|
+
@registry.default || super
|
349
|
+
end
|
160
350
|
end
|
351
|
+
end
|
161
352
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
353
|
+
# Internal: Mixes the {Config} module into any class that includes the {Converter} module. Additionally, mixes the
|
354
|
+
# {BackendTraits} method into instances of this class.
|
355
|
+
#
|
356
|
+
# into - The Class into which the {Converter} module is being included.
|
357
|
+
#
|
358
|
+
# Returns nothing.
|
359
|
+
private_class_method def self.included into
|
360
|
+
into.include BackendTraits
|
361
|
+
into.extend Config
|
362
|
+
end
|
171
363
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
#
|
178
|
-
# dispatch to a handler method. The {TemplateConverter} uses the value of
|
179
|
-
# the transform to select a template to render.
|
364
|
+
# An abstract base class for defining converters that can be used to convert {AbstractNode} objects in a parsed
|
365
|
+
# AsciiDoc document to a backend format such as HTML or DocBook.
|
366
|
+
class Base
|
367
|
+
include Converter, Logging
|
368
|
+
|
369
|
+
# Public: Converts an {AbstractNode} by delegating to a method that matches the transform value.
|
180
370
|
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
#
|
186
|
-
#
|
187
|
-
# how to convert the node. (optional, default: {})
|
371
|
+
# This method looks for a method that matches the name of the transform to dispatch to. If the +opts+ argument is
|
372
|
+
# non-nil, this method assumes the dispatch method accepts two arguments, the node and an options Hash. The options
|
373
|
+
# Hash may be used by converters to delegate back to the top-level converter. Currently, it's used for the outline
|
374
|
+
# transform. If the +opts+ argument is nil, this method assumes the dispatch method accepts the node as its only
|
375
|
+
# argument. To distiguish from node dispatch methods, the convention is to prefix the name of helper method with
|
376
|
+
# underscore and mark them as private. Implementations may override this method to provide different behavior.
|
188
377
|
#
|
189
|
-
#
|
190
|
-
def convert node, transform = nil, opts =
|
191
|
-
|
378
|
+
# See {Converter#convert} for details about the arguments and return value.
|
379
|
+
def convert node, transform = nil, opts = nil
|
380
|
+
opts ? (send transform || node.node_name, node, opts) : (send transform || node.node_name, node)
|
381
|
+
rescue
|
382
|
+
raise unless ::NoMethodError === (ex = $!) && ex.receiver == self && ex.name.to_s == (transform || node.node_name)
|
383
|
+
logger.warn %(missing convert handler for #{ex.name} node in #{@backend} backend (#{self.class}))
|
384
|
+
nil
|
192
385
|
end
|
193
386
|
|
194
387
|
alias handles? respond_to?
|
195
388
|
|
196
|
-
#
|
197
|
-
alias convert_with_options convert
|
198
|
-
end
|
199
|
-
|
200
|
-
# A module that can be used to mix the {#write} method into a {Converter}
|
201
|
-
# implementation to allow the converter to control how the output is written
|
202
|
-
# to disk.
|
203
|
-
module Writer
|
204
|
-
# Public: Writes the output to the specified target file name or stream.
|
389
|
+
# Public: Converts the {AbstractNode} using only its converted content.
|
205
390
|
#
|
206
|
-
#
|
207
|
-
|
208
|
-
|
209
|
-
#
|
210
|
-
# Returns nothing
|
211
|
-
def write output, target
|
212
|
-
if target.respond_to? :write
|
213
|
-
target.write output.chomp
|
214
|
-
# ensure there's a trailing endline to be nice to terminals
|
215
|
-
target.write LF
|
216
|
-
else
|
217
|
-
::IO.write target, output
|
218
|
-
end
|
219
|
-
nil
|
391
|
+
# Returns the converted [String] content.
|
392
|
+
def _content_only node
|
393
|
+
node.content
|
220
394
|
end
|
221
|
-
end
|
222
395
|
|
223
|
-
|
224
|
-
|
225
|
-
#
|
226
|
-
def
|
227
|
-
end
|
396
|
+
# Public: Skips conversion of the {AbstractNode}.
|
397
|
+
#
|
398
|
+
# Returns nothing.
|
399
|
+
def _skip node; end
|
228
400
|
end
|
229
|
-
end
|
230
401
|
|
231
|
-
|
232
|
-
|
402
|
+
extend DefaultFactory # exports static methods
|
403
|
+
end
|
404
|
+
end
|