asciidoctor 1.5.8 → 2.0.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|