asciidoctor 1.5.5 → 1.5.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of asciidoctor might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +216 -1
- data/CONTRIBUTING.adoc +2 -2
- data/Gemfile +20 -1
- data/LICENSE.adoc +1 -1
- data/README-fr.adoc +4 -3
- data/README-jp.adoc +11 -10
- data/README-zh_CN.adoc +4 -3
- data/README.adoc +17 -202
- data/Rakefile +41 -25
- data/asciidoctor.gemspec +9 -10
- data/data/locale/attributes.adoc +216 -34
- data/data/stylesheets/asciidoctor-default.css +23 -16
- data/features/step_definitions.rb +15 -19
- data/features/xref.feature +584 -20
- data/lib/asciidoctor.rb +292 -278
- data/lib/asciidoctor/abstract_block.rb +155 -94
- data/lib/asciidoctor/abstract_node.rb +108 -94
- data/lib/asciidoctor/attribute_list.rb +30 -22
- data/lib/asciidoctor/block.rb +7 -7
- data/lib/asciidoctor/cli/invoker.rb +47 -34
- data/lib/asciidoctor/cli/options.rb +22 -11
- data/lib/asciidoctor/converter.rb +3 -3
- data/lib/asciidoctor/converter/base.rb +2 -2
- data/lib/asciidoctor/converter/composite.rb +1 -1
- data/lib/asciidoctor/converter/docbook45.rb +2 -2
- data/lib/asciidoctor/converter/docbook5.rb +132 -87
- data/lib/asciidoctor/converter/factory.rb +0 -1
- data/lib/asciidoctor/converter/html5.rb +116 -98
- data/lib/asciidoctor/converter/manpage.rb +51 -52
- data/lib/asciidoctor/converter/template.rb +47 -36
- data/lib/asciidoctor/core_ext.rb +8 -2
- data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +4 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +5 -0
- data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +1 -1
- data/lib/asciidoctor/core_ext/1.8.7/string/{limit.rb → limit_bytesize.rb} +7 -6
- data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +1 -1
- data/lib/asciidoctor/core_ext/nil_or_empty.rb +5 -5
- data/lib/asciidoctor/core_ext/regexp/is_match.rb +3 -0
- data/lib/asciidoctor/core_ext/string/{limit.rb → limit_bytesize.rb} +2 -2
- data/lib/asciidoctor/document.rb +216 -213
- data/lib/asciidoctor/extensions.rb +318 -185
- data/lib/asciidoctor/helpers.rb +35 -35
- data/lib/asciidoctor/inline.rb +32 -1
- data/lib/asciidoctor/list.rb +22 -6
- data/lib/asciidoctor/parser.rb +1008 -1038
- data/lib/asciidoctor/path_resolver.rb +46 -50
- data/lib/asciidoctor/reader.rb +275 -251
- data/lib/asciidoctor/section.rb +86 -58
- data/lib/asciidoctor/stylesheets.rb +6 -6
- data/lib/asciidoctor/substitutors.rb +567 -649
- data/lib/asciidoctor/table.rb +163 -108
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +18 -16
- data/man/asciidoctor.adoc +15 -13
- data/test/attributes_test.rb +138 -22
- data/test/blocks_test.rb +377 -97
- data/test/converter_test.rb +13 -0
- data/test/document_test.rb +244 -34
- data/test/extensions_test.rb +409 -42
- data/test/fixtures/asciidoc_index.txt +521 -0
- data/test/fixtures/basic-docinfo-footer.html +6 -0
- data/test/fixtures/basic-docinfo-footer.xml +8 -0
- data/test/fixtures/basic-docinfo.html +1 -0
- data/test/fixtures/basic-docinfo.xml +4 -0
- data/test/fixtures/basic.asciidoc +5 -0
- data/test/fixtures/chapter-a.adoc +3 -0
- data/test/fixtures/child-include.adoc +5 -0
- data/test/fixtures/circle.svg +9 -0
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
- data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +6 -0
- data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +1 -0
- data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +3 -0
- data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +5 -0
- data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +6 -0
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +3 -0
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +5 -0
- data/test/fixtures/custom-docinfodir/basic-docinfo.html +1 -0
- data/test/fixtures/custom-docinfodir/docinfo.html +1 -0
- data/test/fixtures/docinfo-footer.html +1 -0
- data/test/fixtures/docinfo-footer.xml +9 -0
- data/test/fixtures/docinfo.html +1 -0
- data/test/fixtures/docinfo.xml +3 -0
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +13 -0
- data/test/fixtures/grandchild-include.adoc +3 -0
- data/test/fixtures/hello-asciidoctor.pdf +69 -0
- data/test/fixtures/include-file.asciidoc +24 -0
- data/test/fixtures/include-file.ml +3 -0
- data/test/fixtures/include-file.xml +5 -0
- data/test/fixtures/master.adoc +5 -0
- data/test/fixtures/mismatched-end-tag.adoc +7 -0
- data/test/fixtures/parent-include-restricted.adoc +5 -0
- data/test/fixtures/parent-include.adoc +5 -0
- data/test/fixtures/sample.asciidoc +26 -0
- data/test/fixtures/stylesheets/custom.css +3 -0
- data/test/fixtures/subs-docinfo.html +2 -0
- data/test/fixtures/subs.adoc +7 -0
- data/test/fixtures/tagged-class-enclosed.rb +26 -0
- data/test/fixtures/tagged-class.rb +23 -0
- data/test/fixtures/tip.gif +0 -0
- data/test/invoker_test.rb +82 -4
- data/test/links_test.rb +312 -37
- data/test/lists_test.rb +204 -25
- data/test/manpage_test.rb +191 -4
- data/test/options_test.rb +18 -1
- data/test/paragraphs_test.rb +32 -7
- data/test/parser_test.rb +150 -30
- data/test/paths_test.rb +47 -13
- data/test/preamble_test.rb +1 -1
- data/test/reader_test.rb +366 -126
- data/test/sections_test.rb +203 -56
- data/test/substitutions_test.rb +339 -131
- data/test/tables_test.rb +315 -15
- data/test/test_helper.rb +400 -0
- data/test/text_test.rb +5 -5
- metadata +110 -22
@@ -11,7 +11,7 @@ module Asciidoctor
|
|
11
11
|
# 2. The Parser parses the block-level content into an abstract syntax tree.
|
12
12
|
# Custom blocks and block macros are processed by associated {BlockProcessor}s
|
13
13
|
# and {BlockMacroProcessor}s, respectively.
|
14
|
-
# 3. {
|
14
|
+
# 3. {TreeProcessor}s are run on the abstract syntax tree.
|
15
15
|
# 4. Conversion of the document begins, at which point inline markup is processed
|
16
16
|
# and converted. Custom inline macros are processed by associated {InlineMacroProcessor}s.
|
17
17
|
# 5. {Postprocessor}s modify or replace the converted document.
|
@@ -73,8 +73,8 @@ module Extensions
|
|
73
73
|
extend const_get :DSL if constants.grep :DSL
|
74
74
|
end
|
75
75
|
end
|
76
|
-
alias
|
77
|
-
alias
|
76
|
+
alias extend_dsl use_dsl
|
77
|
+
alias include_dsl use_dsl
|
78
78
|
end
|
79
79
|
|
80
80
|
# Public: Get the configuration Hash for this processor instance.
|
@@ -89,7 +89,58 @@ module Extensions
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def process *args
|
92
|
-
raise ::NotImplementedError
|
92
|
+
raise ::NotImplementedError, %(Asciidoctor::Extensions::Processor subclass must implement ##{__method__} method)
|
93
|
+
end
|
94
|
+
|
95
|
+
# QUESTION should attributes be an option instead of a parameter?
|
96
|
+
|
97
|
+
# Public: Creates a new Section node.
|
98
|
+
#
|
99
|
+
# Creates a Section node in the same manner as the parser.
|
100
|
+
#
|
101
|
+
# parent - The parent Section (or Document) of this new Section.
|
102
|
+
# title - The String title of the new Section.
|
103
|
+
# attrs - A Hash of attributes to control how the section is built.
|
104
|
+
# Use the style attribute to set the name of a special section (ex. appendix).
|
105
|
+
# Use the id attribute to assign an explicit ID or set the value to false to
|
106
|
+
# disable automatic ID generation (when sectids document attribute is set).
|
107
|
+
# opts - An optional Hash of options (default: {}):
|
108
|
+
# :level - [Integer] The level to assign to this section; defaults to
|
109
|
+
# one greater than the parent level (optional).
|
110
|
+
# :numbered - [Boolean] A flag to force numbering, which falls back to the
|
111
|
+
# state of the sectnums document attribute (optional).
|
112
|
+
#
|
113
|
+
# Returns a [Section] node with all properties properly initialized.
|
114
|
+
def create_section parent, title, attrs, opts = {}
|
115
|
+
doc = parent.document
|
116
|
+
doctype, level = doc.doctype, (opts[:level] || parent.level + 1)
|
117
|
+
if (style = attrs.delete 'style')
|
118
|
+
if style == 'abstract' && doctype == 'book'
|
119
|
+
sectname, level = 'chapter', 1
|
120
|
+
else
|
121
|
+
sectname, special = style, true
|
122
|
+
level = 1 if level == 0
|
123
|
+
end
|
124
|
+
elsif doctype == 'book'
|
125
|
+
sectname = level == 0 ? 'part' : (level == 1 ? 'chapter' : 'section')
|
126
|
+
elsif doctype == 'manpage' && (title.casecmp 'synopsis') == 0
|
127
|
+
sectname, special = 'synopsis', true
|
128
|
+
else
|
129
|
+
sectname = 'section'
|
130
|
+
end
|
131
|
+
sect = Section.new parent, level, false
|
132
|
+
sect.title, sect.sectname = title, sectname
|
133
|
+
if special
|
134
|
+
sect.special = true
|
135
|
+
sect.numbered = true if opts.fetch :numbered, (style == 'appendix')
|
136
|
+
elsif opts.fetch :numbered, (level > 0 && (doc.attributes.key? 'sectnums'))
|
137
|
+
sect.numbered = sect.special ? (parent.context == :section && parent.numbered) : true
|
138
|
+
end
|
139
|
+
unless (id = attrs.delete 'id') == false
|
140
|
+
sect.id = attrs['id'] = id || ((doc.attributes.key? 'sectids') ? (Section.generate_id sect.title, doc) : nil)
|
141
|
+
end
|
142
|
+
sect.update_attributes attrs
|
143
|
+
sect
|
93
144
|
end
|
94
145
|
|
95
146
|
def create_block parent, context, source, attrs, opts = {}
|
@@ -129,7 +180,8 @@ module Extensions
|
|
129
180
|
[:create_anchor, :create_inline, :anchor]
|
130
181
|
].each do |method_name, delegate_method_name, context|
|
131
182
|
define_method method_name do |*args|
|
132
|
-
|
183
|
+
args.unshift args.shift, context
|
184
|
+
send delegate_method_name, *args
|
133
185
|
end
|
134
186
|
end
|
135
187
|
end
|
@@ -143,63 +195,151 @@ module Extensions
|
|
143
195
|
end
|
144
196
|
|
145
197
|
def process *args, &block
|
146
|
-
# need to check for both block/proc and lambda
|
147
|
-
# TODO need test for this!
|
148
|
-
#if block_given? || (args.size == 1 && ::Proc === (block = args[0]))
|
149
198
|
if block_given?
|
199
|
+
raise ::ArgumentError, %(wrong number of arguments (given #{args.size}, expected 0)) unless args.empty?
|
150
200
|
@process_block = block
|
151
|
-
|
201
|
+
# TODO enable if we want to support passing proc or lambda as argument instead of block
|
202
|
+
#elsif ::Proc === args[0]
|
203
|
+
# block = args.shift
|
204
|
+
# raise ::ArgumentError, %(wrong number of arguments (given #{args.size}, expected 0)) unless args.empty?
|
205
|
+
# @process_block = block
|
206
|
+
elsif defined? @process_block
|
152
207
|
# NOTE Proc automatically expands a single array argument
|
153
208
|
# ...but lambda doesn't (and we want to accept lambdas too)
|
154
209
|
# TODO need a test for this!
|
155
210
|
@process_block.call(*args)
|
156
211
|
else
|
212
|
+
# TODO add exception message here
|
157
213
|
raise ::NotImplementedError
|
158
214
|
end
|
159
215
|
end
|
160
|
-
#alias :process_with :process
|
161
216
|
|
162
217
|
def process_block_given?
|
163
218
|
defined? @process_block
|
164
219
|
end
|
165
220
|
end
|
166
221
|
|
222
|
+
module SyntaxDsl
|
223
|
+
include ProcessorDsl
|
224
|
+
|
225
|
+
def named value
|
226
|
+
# NOTE due to how processors get initialized, we must defer this assignment in some scenarios
|
227
|
+
if Processor === self
|
228
|
+
@name = value
|
229
|
+
else
|
230
|
+
option :name, value
|
231
|
+
end
|
232
|
+
end
|
233
|
+
# NOTE match_name may get deprecated
|
234
|
+
alias match_name named
|
235
|
+
|
236
|
+
def content_model value
|
237
|
+
option :content_model, value
|
238
|
+
end
|
239
|
+
alias parse_content_as content_model
|
240
|
+
alias parses_content_as content_model
|
241
|
+
#alias parse_as content_model
|
242
|
+
#alias parsed_as content_model
|
243
|
+
|
244
|
+
def positional_attrs *value
|
245
|
+
option :pos_attrs, value.flatten
|
246
|
+
end
|
247
|
+
alias name_attributes positional_attrs
|
248
|
+
alias name_positional_attributes positional_attrs
|
249
|
+
|
250
|
+
def default_attrs value
|
251
|
+
option :default_attrs, value
|
252
|
+
end
|
253
|
+
|
254
|
+
def resolves_attributes *args
|
255
|
+
# NOTE assume true as default value; rewrap single-argument string or symbol
|
256
|
+
if (args = args.fetch 0, true).respond_to? :to_sym
|
257
|
+
args = [args]
|
258
|
+
end unless args.size > 1
|
259
|
+
case args
|
260
|
+
when true
|
261
|
+
option :pos_attrs, []
|
262
|
+
option :default_attrs, {}
|
263
|
+
when ::Array
|
264
|
+
names, defaults = [], {}
|
265
|
+
args.each do |arg|
|
266
|
+
if (arg = arg.to_s).include? '='
|
267
|
+
name, value = arg.split '=', 2
|
268
|
+
if name.include? ':'
|
269
|
+
idx, name = name.split ':', 2
|
270
|
+
idx = idx == '@' ? names.size : idx.to_i
|
271
|
+
names[idx] = name
|
272
|
+
end
|
273
|
+
defaults[name] = value
|
274
|
+
elsif arg.include? ':'
|
275
|
+
idx, name = arg.split ':', 2
|
276
|
+
idx = idx == '@' ? names.size : idx.to_i
|
277
|
+
names[idx] = name
|
278
|
+
else
|
279
|
+
names << arg
|
280
|
+
end
|
281
|
+
end
|
282
|
+
option :pos_attrs, names.compact
|
283
|
+
option :default_attrs, defaults
|
284
|
+
when ::Hash
|
285
|
+
names, defaults = [], {}
|
286
|
+
args.each do |key, val|
|
287
|
+
if (name = key.to_s).include? ':'
|
288
|
+
idx, name = name.split ':', 2
|
289
|
+
idx = idx == '@' ? names.size : idx.to_i
|
290
|
+
names[idx] = name
|
291
|
+
end
|
292
|
+
defaults[name] = val if val
|
293
|
+
end
|
294
|
+
option :pos_attrs, names.compact
|
295
|
+
option :default_attrs, defaults
|
296
|
+
else
|
297
|
+
raise ::ArgumentError, %(unsupported attributes specification for macro: #{args.inspect})
|
298
|
+
end
|
299
|
+
end
|
300
|
+
# NOTE we may decide to drop this alias
|
301
|
+
alias resolve_attributes resolves_attributes
|
302
|
+
end
|
303
|
+
|
167
304
|
# Public: Preprocessors are run after the source text is split into lines and
|
168
305
|
# normalized, but before parsing begins.
|
169
306
|
#
|
170
307
|
# Prior to invoking the preprocessor, Asciidoctor splits the source text into
|
171
308
|
# lines and normalizes them. The normalize process strips trailing whitespace
|
172
|
-
#
|
309
|
+
# and the end of line character sequence from each line.
|
173
310
|
#
|
174
|
-
# Asciidoctor passes
|
175
|
-
#
|
176
|
-
#
|
177
|
-
#
|
311
|
+
# Asciidoctor passes the document and the document's Reader to the
|
312
|
+
# {Processor#process} method of the Preprocessor instance. The Preprocessor
|
313
|
+
# can modify the Reader as necessary and either return the same Reader (or
|
314
|
+
# falsy, which is equivalent) or a reference to a substitute Reader.
|
178
315
|
#
|
179
316
|
# Preprocessor implementations must extend the Preprocessor class.
|
180
317
|
class Preprocessor < Processor
|
181
318
|
def process document, reader
|
182
|
-
raise ::NotImplementedError
|
319
|
+
raise ::NotImplementedError, %(Asciidoctor::Extensions::Preprocessor subclass must implement ##{__method__} method)
|
183
320
|
end
|
184
321
|
end
|
185
322
|
Preprocessor::DSL = ProcessorDsl
|
186
323
|
|
187
|
-
# Public:
|
324
|
+
# Public: TreeProcessors are run on the Document after the source has been
|
188
325
|
# parsed into an abstract syntax tree (AST), as represented by the Document
|
189
326
|
# object and its child Node objects (e.g., Section, Block, List, ListItem).
|
190
327
|
#
|
191
328
|
# Asciidoctor invokes the {Processor#process} method on an instance of each
|
192
|
-
# registered
|
329
|
+
# registered TreeProcessor.
|
193
330
|
#
|
194
|
-
#
|
331
|
+
# TreeProcessor implementations must extend TreeProcessor.
|
195
332
|
#--
|
196
|
-
# QUESTION should the
|
197
|
-
class
|
333
|
+
# QUESTION should the tree processor get invoked after parse header too?
|
334
|
+
class TreeProcessor < Processor
|
198
335
|
def process document
|
199
|
-
raise ::NotImplementedError
|
336
|
+
raise ::NotImplementedError, %(Asciidoctor::Extensions::TreeProcessor subclass must implement ##{__method__} method)
|
200
337
|
end
|
201
338
|
end
|
202
|
-
|
339
|
+
TreeProcessor::DSL = ProcessorDsl
|
340
|
+
|
341
|
+
# Alias deprecated class name for backwards compatibility
|
342
|
+
Treeprocessor = TreeProcessor
|
203
343
|
|
204
344
|
# Public: Postprocessors are run after the document is converted, but before
|
205
345
|
# it is written to the output stream.
|
@@ -218,7 +358,7 @@ module Extensions
|
|
218
358
|
# Postprocessor implementations must Postprocessor.
|
219
359
|
class Postprocessor < Processor
|
220
360
|
def process document, output
|
221
|
-
raise ::NotImplementedError
|
361
|
+
raise ::NotImplementedError, %(Asciidoctor::Extensions::Postprocessor subclass must implement ##{__method__} method)
|
222
362
|
end
|
223
363
|
end
|
224
364
|
Postprocessor::DSL = ProcessorDsl
|
@@ -233,17 +373,37 @@ module Extensions
|
|
233
373
|
#
|
234
374
|
# IncludeProcessor implementations must extend IncludeProcessor.
|
235
375
|
#--
|
236
|
-
# TODO add file extension or regexp
|
376
|
+
# TODO add file extension or regexp as shortcut for handles? method
|
237
377
|
class IncludeProcessor < Processor
|
238
378
|
def process document, reader, target, attributes
|
239
|
-
raise ::NotImplementedError
|
379
|
+
raise ::NotImplementedError, %(Asciidoctor::Extensions::IncludeProcessor subclass must implement ##{__method__} method)
|
240
380
|
end
|
241
381
|
|
242
382
|
def handles? target
|
243
383
|
true
|
244
384
|
end
|
245
385
|
end
|
246
|
-
|
386
|
+
|
387
|
+
module IncludeProcessorDsl
|
388
|
+
include ProcessorDsl
|
389
|
+
|
390
|
+
def handles? *args, &block
|
391
|
+
if block_given?
|
392
|
+
raise ::ArgumentError, %(wrong number of arguments (given #{args.size}, expected 0)) unless args.empty?
|
393
|
+
@handles_block = block
|
394
|
+
# TODO enable if we want to support passing proc or lambda as argument instead of block
|
395
|
+
#elsif ::Proc === args[0]
|
396
|
+
# block = args.shift
|
397
|
+
# raise ::ArgumentError, %(wrong number of arguments (given #{args.size}, expected 0)) unless args.empty?
|
398
|
+
# @handles_block = block
|
399
|
+
elsif defined? @handles_block
|
400
|
+
@handles_block.call args[0]
|
401
|
+
else
|
402
|
+
true
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
IncludeProcessor::DSL = IncludeProcessorDsl
|
247
407
|
|
248
408
|
# Public: DocinfoProcessors are used to add additional content to
|
249
409
|
# the header and/or footer of the generated document.
|
@@ -262,7 +422,7 @@ module Extensions
|
|
262
422
|
end
|
263
423
|
|
264
424
|
def process document
|
265
|
-
raise ::NotImplementedError
|
425
|
+
raise ::NotImplementedError, %(Asciidoctor::Extensions::DocinfoProcessor subclass must implement ##{__method__} method)
|
266
426
|
end
|
267
427
|
end
|
268
428
|
|
@@ -281,7 +441,7 @@ module Extensions
|
|
281
441
|
# When Asciidoctor encounters a delimited block or paragraph with an
|
282
442
|
# unrecognized name while parsing the document, it looks for a BlockProcessor
|
283
443
|
# registered to handle this name and, if found, invokes its {Processor#process}
|
284
|
-
# method to build a
|
444
|
+
# method to build a corresponding node in the document tree.
|
285
445
|
#
|
286
446
|
# AsciiDoc example:
|
287
447
|
#
|
@@ -293,7 +453,8 @@ module Extensions
|
|
293
453
|
# * :named - The name of the block (required: true)
|
294
454
|
# * :contexts - The blocks contexts on which this style can be used (default: [:paragraph, :open]
|
295
455
|
# * :content_model - The structure of the content supported in this block (default: :compound)
|
296
|
-
# * :
|
456
|
+
# * :pos_attrs - A list of attribute names used to map positional attributes (default: nil)
|
457
|
+
# * :default_attrs - A hash of attribute names and values used to seed the attributes hash (default: nil)
|
297
458
|
# * ...
|
298
459
|
#
|
299
460
|
# BlockProcessor implementations must extend BlockProcessor.
|
@@ -317,46 +478,19 @@ module Extensions
|
|
317
478
|
end
|
318
479
|
|
319
480
|
def process parent, reader, attributes
|
320
|
-
raise ::NotImplementedError
|
481
|
+
raise ::NotImplementedError, %(Asciidoctor::Extensions::BlockProcessor subclass must implement ##{__method__} method)
|
321
482
|
end
|
322
483
|
end
|
323
484
|
|
324
485
|
module BlockProcessorDsl
|
325
|
-
include
|
326
|
-
|
327
|
-
# FIXME this isn't the prettiest thing
|
328
|
-
def named value
|
329
|
-
if Processor === self
|
330
|
-
@name = value
|
331
|
-
else
|
332
|
-
option :name, value
|
333
|
-
end
|
334
|
-
end
|
335
|
-
alias :match_name :named
|
336
|
-
alias :bind_to :named
|
486
|
+
include SyntaxDsl
|
337
487
|
|
338
488
|
def contexts *value
|
339
489
|
option :contexts, value.flatten
|
340
490
|
end
|
341
|
-
alias
|
342
|
-
alias
|
343
|
-
|
344
|
-
def content_model value
|
345
|
-
option :content_model, value
|
346
|
-
end
|
347
|
-
alias :parse_content_as :content_model
|
348
|
-
|
349
|
-
def positional_attributes *value
|
350
|
-
option :pos_attrs, value.flatten
|
351
|
-
end
|
352
|
-
alias :pos_attrs :positional_attributes
|
353
|
-
alias :name_attributes :positional_attributes
|
354
|
-
alias :name_positional_attributes :positional_attributes
|
355
|
-
|
356
|
-
def default_attrs value
|
357
|
-
option :default_attrs, value
|
358
|
-
end
|
359
|
-
alias :seed_attributes_with :default_attrs
|
491
|
+
alias on_contexts contexts
|
492
|
+
alias on_context contexts
|
493
|
+
alias bound_to contexts
|
360
494
|
end
|
361
495
|
BlockProcessor::DSL = BlockProcessorDsl
|
362
496
|
|
@@ -370,40 +504,23 @@ module Extensions
|
|
370
504
|
end
|
371
505
|
|
372
506
|
def process parent, target, attributes
|
373
|
-
raise ::NotImplementedError
|
507
|
+
raise ::NotImplementedError, %(Asciidoctor::Extensions::MacroProcessor subclass must implement ##{__method__} method)
|
374
508
|
end
|
375
509
|
end
|
376
510
|
|
377
511
|
module MacroProcessorDsl
|
378
|
-
include
|
379
|
-
# QUESTION perhaps include a SyntaxDsl?
|
512
|
+
include SyntaxDsl
|
380
513
|
|
381
|
-
def
|
382
|
-
if
|
383
|
-
|
384
|
-
|
385
|
-
option :name, value
|
514
|
+
def resolves_attributes *args
|
515
|
+
if args.size == 1 && !args[0]
|
516
|
+
option :content_model, :text
|
517
|
+
return
|
386
518
|
end
|
519
|
+
super
|
520
|
+
option :content_model, :attributes
|
387
521
|
end
|
388
|
-
|
389
|
-
alias
|
390
|
-
|
391
|
-
def content_model value
|
392
|
-
option :content_model, value
|
393
|
-
end
|
394
|
-
alias :parse_content_as :content_model
|
395
|
-
|
396
|
-
def positional_attributes *value
|
397
|
-
option :pos_attrs, value.flatten
|
398
|
-
end
|
399
|
-
alias :pos_attrs :positional_attributes
|
400
|
-
alias :name_attributes :positional_attributes
|
401
|
-
alias :name_positional_attributes :positional_attributes
|
402
|
-
|
403
|
-
def default_attrs value
|
404
|
-
option :default_attrs, value
|
405
|
-
end
|
406
|
-
alias :seed_attributes_with :default_attrs
|
522
|
+
# NOTE we may decide to drop this alias
|
523
|
+
alias resolve_attributes resolves_attributes
|
407
524
|
end
|
408
525
|
|
409
526
|
# Public: BlockMacroProcessors are used to handle block macros that have a
|
@@ -420,35 +537,36 @@ module Extensions
|
|
420
537
|
# InlineMacroProcessor implementations must extend InlineMacroProcessor.
|
421
538
|
#--
|
422
539
|
# TODO break this out into different pattern types
|
423
|
-
# for example,
|
540
|
+
# for example, FullInlineMacro, ShortInlineMacro (no target) and other patterns
|
424
541
|
# FIXME for inline passthrough, we need to have some way to specify the text as a passthrough
|
425
542
|
class InlineMacroProcessor < MacroProcessor
|
543
|
+
@@rx_cache = {}
|
544
|
+
|
426
545
|
# Lookup the regexp option, resolving it first if necessary.
|
427
546
|
# Once this method is called, the regexp is considered frozen.
|
428
547
|
def regexp
|
429
|
-
@config[:regexp] ||=
|
548
|
+
@config[:regexp] ||= resolve_regexp @name.to_s, @config[:format]
|
430
549
|
end
|
431
550
|
|
432
551
|
def resolve_regexp name, format
|
433
|
-
|
434
|
-
|
435
|
-
%r(\\?#{name}:\[((?:\\\]|[^\]])*?)\])
|
436
|
-
else
|
437
|
-
%r(\\?#{name}:(\S+?)\[((?:\\\]|[^\]])*?)\])
|
438
|
-
end
|
552
|
+
raise ::ArgumentError, %(invalid name for inline macro: #{name}) unless MacroNameRx.match? name
|
553
|
+
@@rx_cache[[name, format]] ||= /\\?#{name}:#{format == :short ? '(){0}' : '(\S+?)'}\[(|.*?[^\\])\]/
|
439
554
|
end
|
440
555
|
end
|
441
556
|
|
442
557
|
module InlineMacroProcessorDsl
|
443
558
|
include MacroProcessorDsl
|
444
559
|
|
445
|
-
def
|
560
|
+
def with_format value
|
446
561
|
option :format, value
|
447
562
|
end
|
563
|
+
alias using_format with_format
|
448
564
|
|
449
|
-
def
|
565
|
+
def matches value
|
450
566
|
option :regexp, value
|
451
567
|
end
|
568
|
+
alias match matches
|
569
|
+
alias matching matches
|
452
570
|
end
|
453
571
|
InlineMacroProcessor::DSL = InlineMacroProcessorDsl
|
454
572
|
|
@@ -463,9 +581,9 @@ module Extensions
|
|
463
581
|
#--
|
464
582
|
# QUESTION call this ExtensionInfo?
|
465
583
|
class Extension
|
466
|
-
|
467
|
-
|
468
|
-
|
584
|
+
attr_reader :kind
|
585
|
+
attr_reader :config
|
586
|
+
attr_reader :instance
|
469
587
|
|
470
588
|
def initialize kind, instance, config
|
471
589
|
@kind = kind
|
@@ -478,7 +596,7 @@ module Extensions
|
|
478
596
|
# reference to the {Processor#process} method. By storing this reference, its
|
479
597
|
# possible to accomodate both concrete extension implementations and Procs.
|
480
598
|
class ProcessorExtension < Extension
|
481
|
-
|
599
|
+
attr_reader :process_method
|
482
600
|
|
483
601
|
def initialize kind, instance, process_method = nil
|
484
602
|
super kind, instance, instance.config
|
@@ -518,7 +636,7 @@ module Extensions
|
|
518
636
|
|
519
637
|
def initialize groups = {}
|
520
638
|
@groups = groups
|
521
|
-
@preprocessor_extensions = @
|
639
|
+
@preprocessor_extensions = @tree_processor_extensions = @postprocessor_extensions = @include_processor_extensions = @docinfo_processor_extensions = nil
|
522
640
|
@block_extensions = @block_macro_extensions = @inline_macro_extensions = nil
|
523
641
|
@document = nil
|
524
642
|
end
|
@@ -575,7 +693,7 @@ module Extensions
|
|
575
693
|
#
|
576
694
|
# # as a method block
|
577
695
|
# preprocessor do
|
578
|
-
# process |
|
696
|
+
# process |doc, reader|
|
579
697
|
# ...
|
580
698
|
# end
|
581
699
|
# end
|
@@ -601,58 +719,63 @@ module Extensions
|
|
601
719
|
@preprocessor_extensions
|
602
720
|
end
|
603
721
|
|
604
|
-
# Public: Registers a {
|
722
|
+
# Public: Registers a {TreeProcessor} with the extension registry to process
|
605
723
|
# the AsciiDoc source after parsing is complete.
|
606
724
|
#
|
607
|
-
# The
|
725
|
+
# The TreeProcessor may be one of four types:
|
608
726
|
#
|
609
|
-
# * A
|
610
|
-
# * An instance of a
|
611
|
-
# * The String name of a
|
612
|
-
# * A method block (i.e., Proc) that conforms to the
|
727
|
+
# * A TreeProcessor subclass
|
728
|
+
# * An instance of a TreeProcessor subclass
|
729
|
+
# * The String name of a TreeProcessor subclass
|
730
|
+
# * A method block (i.e., Proc) that conforms to the TreeProcessor contract
|
613
731
|
#
|
614
|
-
# Unless the
|
732
|
+
# Unless the TreeProcessor is passed as the method block, it must be the
|
615
733
|
# first argument to this method.
|
616
734
|
#
|
617
735
|
# Examples
|
618
736
|
#
|
619
|
-
# # as a
|
620
|
-
#
|
737
|
+
# # as a TreeProcessor subclass
|
738
|
+
# tree_processor ShellTreeProcessor
|
621
739
|
#
|
622
|
-
# # as an instance of a
|
623
|
-
#
|
740
|
+
# # as an instance of a TreeProcessor subclass
|
741
|
+
# tree_processor ShellTreeProcessor.new
|
624
742
|
#
|
625
|
-
# # as a name of a
|
626
|
-
#
|
743
|
+
# # as a name of a TreeProcessor subclass
|
744
|
+
# tree_processor 'ShellTreeProcessor'
|
627
745
|
#
|
628
746
|
# # as a method block
|
629
|
-
#
|
747
|
+
# tree_processor do
|
630
748
|
# process |document|
|
631
749
|
# ...
|
632
750
|
# end
|
633
751
|
# end
|
634
752
|
#
|
635
753
|
# Returns the [Extension] stored in the registry that proxies the
|
636
|
-
# instance of this
|
637
|
-
def
|
638
|
-
add_document_processor :
|
754
|
+
# instance of this TreeProcessor.
|
755
|
+
def tree_processor *args, &block
|
756
|
+
add_document_processor :tree_processor, args, &block
|
639
757
|
end
|
640
758
|
|
641
|
-
# Public: Checks whether any {
|
759
|
+
# Public: Checks whether any {TreeProcessor} extensions have been registered.
|
642
760
|
#
|
643
|
-
# Returns a [Boolean] indicating whether any
|
644
|
-
def
|
645
|
-
!!@
|
761
|
+
# Returns a [Boolean] indicating whether any TreeProcessor extensions are registered.
|
762
|
+
def tree_processors?
|
763
|
+
!!@tree_processor_extensions
|
646
764
|
end
|
647
765
|
|
648
766
|
# Public: Retrieves the {Extension} proxy objects for all
|
649
|
-
#
|
767
|
+
# TreeProcessor instances in this registry.
|
650
768
|
#
|
651
769
|
# Returns an [Array] of Extension proxy objects.
|
652
|
-
def
|
653
|
-
@
|
770
|
+
def tree_processors
|
771
|
+
@tree_processor_extensions
|
654
772
|
end
|
655
773
|
|
774
|
+
# Alias deprecated methods for backwards compatibility
|
775
|
+
alias treeprocessor tree_processor
|
776
|
+
alias treeprocessors? tree_processors?
|
777
|
+
alias treeprocessors tree_processors
|
778
|
+
|
656
779
|
# Public: Registers a {Postprocessor} with the extension registry to process
|
657
780
|
# the output after conversion is complete.
|
658
781
|
#
|
@@ -1109,7 +1232,7 @@ module Extensions
|
|
1109
1232
|
|
1110
1233
|
def add_document_processor kind, args, &block
|
1111
1234
|
kind_name = kind.to_s.tr '_', ' '
|
1112
|
-
kind_class_symbol = kind_name.split
|
1235
|
+
kind_class_symbol = kind_name.split.map {|it| it.capitalize }.join.to_sym
|
1113
1236
|
kind_class = Extensions.const_get kind_class_symbol
|
1114
1237
|
kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol) : nil
|
1115
1238
|
kind_store = instance_variable_get(%(@#{kind}_extensions).to_sym) || instance_variable_set(%(@#{kind}_extensions).to_sym, [])
|
@@ -1127,17 +1250,17 @@ module Extensions
|
|
1127
1250
|
processor.instance_exec(&block)
|
1128
1251
|
processor.freeze
|
1129
1252
|
unless processor.process_block_given?
|
1130
|
-
raise ::ArgumentError
|
1253
|
+
raise ::ArgumentError, %(No block specified to process #{kind_name} extension at #{block.source_location})
|
1131
1254
|
end
|
1132
1255
|
ProcessorExtension.new kind, processor
|
1133
1256
|
else
|
1134
1257
|
processor, config = resolve_args args, 2
|
1135
|
-
# style 2: specified as
|
1136
|
-
if
|
1137
|
-
unless
|
1138
|
-
raise ::ArgumentError
|
1258
|
+
# style 2: specified as Class or String class name
|
1259
|
+
if (processor_class = Extensions.resolve_class processor)
|
1260
|
+
unless processor_class < kind_class || (kind_java_class && processor_class < kind_java_class)
|
1261
|
+
raise ::ArgumentError, %(Invalid type for #{kind_name} extension: #{processor})
|
1139
1262
|
end
|
1140
|
-
processor_instance =
|
1263
|
+
processor_instance = processor_class.new config
|
1141
1264
|
processor_instance.freeze
|
1142
1265
|
ProcessorExtension.new kind, processor_instance
|
1143
1266
|
# style 3: specified as instance
|
@@ -1146,7 +1269,7 @@ module Extensions
|
|
1146
1269
|
processor.freeze
|
1147
1270
|
ProcessorExtension.new kind, processor
|
1148
1271
|
else
|
1149
|
-
raise ::ArgumentError
|
1272
|
+
raise ::ArgumentError, %(Invalid arguments specified for registering #{kind_name} extension: #{args})
|
1150
1273
|
end
|
1151
1274
|
end
|
1152
1275
|
|
@@ -1159,8 +1282,7 @@ module Extensions
|
|
1159
1282
|
|
1160
1283
|
def add_syntax_processor kind, args, &block
|
1161
1284
|
kind_name = kind.to_s.tr '_', ' '
|
1162
|
-
|
1163
|
-
kind_class_symbol = %(#{kind_class_basename}Processor).to_sym
|
1285
|
+
kind_class_symbol = (kind_name.split.map {|it| it.capitalize }.push 'Processor').join.to_sym
|
1164
1286
|
kind_class = Extensions.const_get kind_class_symbol
|
1165
1287
|
kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol) : nil
|
1166
1288
|
kind_store = instance_variable_get(%(@#{kind}_extensions).to_sym) || instance_variable_set(%(@#{kind}_extensions).to_sym, {})
|
@@ -1180,37 +1302,37 @@ module Extensions
|
|
1180
1302
|
processor.instance_exec(&block)
|
1181
1303
|
end
|
1182
1304
|
unless (name = as_symbol processor.name)
|
1183
|
-
raise ::ArgumentError
|
1305
|
+
raise ::ArgumentError, %(No name specified for #{kind_name} extension at #{block.source_location})
|
1184
1306
|
end
|
1185
1307
|
unless processor.process_block_given?
|
1186
|
-
raise ::NoMethodError
|
1308
|
+
raise ::NoMethodError, %(No block specified to process #{kind_name} extension at #{block.source_location})
|
1187
1309
|
end
|
1188
1310
|
processor.freeze
|
1189
1311
|
kind_store[name] = ProcessorExtension.new kind, processor
|
1190
1312
|
else
|
1191
1313
|
processor, name, config = resolve_args args, 3
|
1192
|
-
# style 2: specified as
|
1193
|
-
if
|
1194
|
-
unless
|
1195
|
-
raise ::ArgumentError
|
1314
|
+
# style 2: specified as Class or String class name
|
1315
|
+
if (processor_class = Extensions.resolve_class processor)
|
1316
|
+
unless processor_class < kind_class || (kind_java_class && processor_class < kind_java_class)
|
1317
|
+
raise ::ArgumentError, %(Class specified for #{kind_name} extension does not inherit from #{kind_class}: #{processor})
|
1196
1318
|
end
|
1197
|
-
processor_instance =
|
1319
|
+
processor_instance = processor_class.new as_symbol(name), config
|
1198
1320
|
unless (name = as_symbol processor_instance.name)
|
1199
|
-
raise ::ArgumentError
|
1321
|
+
raise ::ArgumentError, %(No name specified for #{kind_name} extension: #{processor})
|
1200
1322
|
end
|
1201
|
-
|
1323
|
+
processor_instance.freeze
|
1202
1324
|
kind_store[name] = ProcessorExtension.new kind, processor_instance
|
1203
1325
|
# style 3: specified as instance
|
1204
1326
|
elsif kind_class === processor || (kind_java_class && kind_java_class === processor)
|
1205
1327
|
processor.update_config config
|
1206
1328
|
# TODO need a test for this override!
|
1207
1329
|
unless (name = name ? (processor.name = as_symbol name) : (as_symbol processor.name))
|
1208
|
-
raise ::ArgumentError
|
1330
|
+
raise ::ArgumentError, %(No name specified for #{kind_name} extension: #{processor})
|
1209
1331
|
end
|
1210
1332
|
processor.freeze
|
1211
1333
|
kind_store[name] = ProcessorExtension.new kind, processor
|
1212
1334
|
else
|
1213
|
-
raise ::ArgumentError
|
1335
|
+
raise ::ArgumentError, %(Invalid arguments specified for registering #{kind_name} extension: #{args})
|
1214
1336
|
end
|
1215
1337
|
end
|
1216
1338
|
end
|
@@ -1218,9 +1340,8 @@ module Extensions
|
|
1218
1340
|
def resolve_args args, expect
|
1219
1341
|
opts = ::Hash === args[-1] ? args.pop : {}
|
1220
1342
|
return opts if expect == 1
|
1221
|
-
|
1222
|
-
|
1223
|
-
args.fill nil, num_args, missing
|
1343
|
+
if (missing = expect - 1 - args.size) > 0
|
1344
|
+
args += (::Array.new missing)
|
1224
1345
|
elsif missing < 0
|
1225
1346
|
args.pop(-missing)
|
1226
1347
|
end
|
@@ -1247,14 +1368,15 @@ module Extensions
|
|
1247
1368
|
@groups ||= {}
|
1248
1369
|
end
|
1249
1370
|
|
1250
|
-
def
|
1371
|
+
def create name = nil, &block
|
1251
1372
|
if block_given?
|
1252
|
-
name
|
1253
|
-
Registry.new({ name => block })
|
1373
|
+
Registry.new({ (name || generate_name) => block })
|
1254
1374
|
else
|
1255
1375
|
Registry.new
|
1256
1376
|
end
|
1257
1377
|
end
|
1378
|
+
# Deprecated: Use create instead of build_registry
|
1379
|
+
alias build_registry create
|
1258
1380
|
|
1259
1381
|
# Public: Registers an extension Group that subsequently registers a
|
1260
1382
|
# collection of extensions.
|
@@ -1291,56 +1413,67 @@ module Extensions
|
|
1291
1413
|
#
|
1292
1414
|
# Returns the [Proc, Class or Object] instance, matching the type passed to this method.
|
1293
1415
|
def register *args, &block
|
1294
|
-
argc = args.
|
1295
|
-
|
1296
|
-
block
|
1297
|
-
elsif
|
1298
|
-
|
1416
|
+
argc = args.size
|
1417
|
+
if block_given?
|
1418
|
+
resolved_group = block
|
1419
|
+
elsif (group = args.pop)
|
1420
|
+
# QUESTION should we instantiate the group class here or defer until activation??
|
1421
|
+
resolved_group = (resolve_class group) || group
|
1299
1422
|
else
|
1300
|
-
|
1301
|
-
# activation??
|
1302
|
-
case group
|
1303
|
-
when ::Class
|
1304
|
-
group
|
1305
|
-
when ::String
|
1306
|
-
class_for_name group
|
1307
|
-
when ::Symbol
|
1308
|
-
class_for_name group.to_s
|
1309
|
-
else
|
1310
|
-
group
|
1311
|
-
end
|
1423
|
+
raise ::ArgumentError, %(Extension group to register not specified)
|
1312
1424
|
end
|
1313
1425
|
name = args.pop || generate_name
|
1314
1426
|
unless args.empty?
|
1315
|
-
raise ::ArgumentError
|
1427
|
+
raise ::ArgumentError, %(Wrong number of arguments (#{argc} for 1..2))
|
1316
1428
|
end
|
1317
1429
|
groups[name] = resolved_group
|
1318
1430
|
end
|
1319
1431
|
|
1432
|
+
# Public: Unregister all statically-registered extension groups.
|
1433
|
+
#
|
1434
|
+
# Returns nothing
|
1320
1435
|
def unregister_all
|
1321
1436
|
@groups = {}
|
1437
|
+
nil
|
1322
1438
|
end
|
1323
1439
|
|
1324
|
-
#
|
1440
|
+
# Public: Unregister statically-registered extension groups by name.
|
1441
|
+
#
|
1442
|
+
# names - one or more Symbol or String group names to unregister
|
1443
|
+
#
|
1444
|
+
# Returns nothing
|
1445
|
+
def unregister *names
|
1446
|
+
names.each {|group| @groups.delete group.to_sym }
|
1447
|
+
nil
|
1448
|
+
end
|
1449
|
+
|
1450
|
+
# Internal: Resolve the specified object as a Class
|
1451
|
+
#
|
1452
|
+
# object - The object to resolve as a Class
|
1453
|
+
#
|
1454
|
+
# Returns a Class if the specified object is a Class (but not a Module) or
|
1455
|
+
# a String that resolves to a Class; otherwise, nil
|
1325
1456
|
def resolve_class object
|
1326
|
-
|
1457
|
+
case object
|
1458
|
+
when ::Class
|
1459
|
+
object
|
1460
|
+
when ::String
|
1461
|
+
class_for_name object
|
1462
|
+
end
|
1327
1463
|
end
|
1328
1464
|
|
1329
1465
|
# Public: Resolves the Class object for the qualified name.
|
1330
1466
|
#
|
1331
1467
|
# Returns Class
|
1332
1468
|
def class_for_name qualified_name
|
1333
|
-
|
1334
|
-
qualified_name.split
|
1335
|
-
|
1336
|
-
|
1337
|
-
elsif resolved_class.const_defined? name
|
1338
|
-
resolved_class = resolved_class.const_get name
|
1339
|
-
else
|
1340
|
-
raise %(Could not resolve class for name: #{qualified_name})
|
1469
|
+
resolved = ::Object
|
1470
|
+
(qualified_name.split '::').each do |name|
|
1471
|
+
unless name.empty? || ((resolved.const_defined? name) && ::Module === (resolved = resolved.const_get name))
|
1472
|
+
raise ::NameError, %(Could not resolve class for name: #{qualified_name})
|
1341
1473
|
end
|
1342
1474
|
end
|
1343
|
-
|
1475
|
+
raise ::NameError, %(Could not resolve class for name: #{qualified_name}) unless ::Class === resolved
|
1476
|
+
resolved
|
1344
1477
|
end
|
1345
1478
|
end
|
1346
1479
|
|