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.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +162 -17
  3. data/LICENSE +1 -1
  4. data/README-de.adoc +12 -13
  5. data/README-fr.adoc +11 -12
  6. data/README-jp.adoc +11 -12
  7. data/README-zh_CN.adoc +12 -13
  8. data/README.adoc +6 -7
  9. data/asciidoctor.gemspec +19 -24
  10. data/bin/asciidoctor +5 -4
  11. data/data/reference/syntax.adoc +283 -0
  12. data/data/stylesheets/asciidoctor-default.css +56 -52
  13. data/data/stylesheets/coderay-asciidoctor.css +7 -9
  14. data/lib/asciidoctor.rb +171 -232
  15. data/lib/asciidoctor/abstract_block.rb +96 -105
  16. data/lib/asciidoctor/abstract_node.rb +118 -139
  17. data/lib/asciidoctor/attribute_list.rb +10 -14
  18. data/lib/asciidoctor/block.rb +20 -19
  19. data/lib/asciidoctor/callouts.rb +4 -2
  20. data/lib/asciidoctor/cli.rb +3 -2
  21. data/lib/asciidoctor/cli/invoker.rb +14 -21
  22. data/lib/asciidoctor/cli/options.rb +64 -54
  23. data/lib/asciidoctor/converter.rb +357 -185
  24. data/lib/asciidoctor/converter/composite.rb +40 -48
  25. data/lib/asciidoctor/converter/docbook5.rb +604 -640
  26. data/lib/asciidoctor/converter/html5.rb +949 -963
  27. data/lib/asciidoctor/converter/manpage.rb +569 -548
  28. data/lib/asciidoctor/converter/template.rb +231 -272
  29. data/lib/asciidoctor/core_ext.rb +5 -18
  30. data/lib/asciidoctor/core_ext/float/truncate.rb +19 -0
  31. data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
  32. data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
  33. data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
  34. data/lib/asciidoctor/document.rb +399 -377
  35. data/lib/asciidoctor/extensions.rb +72 -140
  36. data/lib/asciidoctor/helpers.rb +122 -83
  37. data/lib/asciidoctor/inline.rb +5 -1
  38. data/lib/asciidoctor/list.rb +13 -11
  39. data/lib/asciidoctor/logging.rb +17 -16
  40. data/lib/asciidoctor/parser.rb +390 -423
  41. data/lib/asciidoctor/path_resolver.rb +10 -5
  42. data/lib/asciidoctor/reader.rb +286 -263
  43. data/lib/asciidoctor/rouge_ext.rb +39 -0
  44. data/lib/asciidoctor/section.rb +9 -8
  45. data/lib/asciidoctor/stylesheets.rb +19 -37
  46. data/lib/asciidoctor/substitutors.rb +364 -509
  47. data/lib/asciidoctor/syntax_highlighter.rb +238 -0
  48. data/lib/asciidoctor/syntax_highlighter/coderay.rb +87 -0
  49. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +26 -0
  50. data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
  51. data/lib/asciidoctor/syntax_highlighter/prettify.rb +27 -0
  52. data/lib/asciidoctor/syntax_highlighter/pygments.rb +149 -0
  53. data/lib/asciidoctor/syntax_highlighter/rouge.rb +129 -0
  54. data/lib/asciidoctor/table.rb +73 -66
  55. data/lib/asciidoctor/timings.rb +4 -2
  56. data/lib/asciidoctor/version.rb +2 -1
  57. data/lib/asciidoctor/writer.rb +30 -0
  58. data/man/asciidoctor.1 +19 -15
  59. data/man/asciidoctor.adoc +14 -12
  60. metadata +69 -216
  61. data/CONTRIBUTING.adoc +0 -185
  62. data/Gemfile +0 -60
  63. data/Rakefile +0 -129
  64. data/bin/asciidoctor-safe +0 -15
  65. data/features/open_block.feature +0 -92
  66. data/features/pass_block.feature +0 -66
  67. data/features/step_definitions.rb +0 -49
  68. data/features/text_formatting.feature +0 -57
  69. data/features/xref.feature +0 -1039
  70. data/lib/asciidoctor/converter/base.rb +0 -59
  71. data/lib/asciidoctor/converter/docbook45.rb +0 -93
  72. data/lib/asciidoctor/converter/factory.rb +0 -226
  73. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
  74. data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
  75. data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
  76. data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
  77. data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
  78. data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
  79. data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
  80. data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
  81. data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
  82. data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
  83. data/test/api_test.rb +0 -1240
  84. data/test/attribute_list_test.rb +0 -242
  85. data/test/attributes_test.rb +0 -1623
  86. data/test/blocks_test.rb +0 -3870
  87. data/test/converter_test.rb +0 -470
  88. data/test/document_test.rb +0 -1853
  89. data/test/extensions_test.rb +0 -1560
  90. data/test/fixtures/asciidoc_index.txt +0 -521
  91. data/test/fixtures/basic-docinfo-footer.html +0 -6
  92. data/test/fixtures/basic-docinfo-footer.xml +0 -8
  93. data/test/fixtures/basic-docinfo.html +0 -1
  94. data/test/fixtures/basic-docinfo.xml +0 -4
  95. data/test/fixtures/basic.asciidoc +0 -5
  96. data/test/fixtures/chapter-a.adoc +0 -3
  97. data/test/fixtures/child-include.adoc +0 -5
  98. data/test/fixtures/circle.svg +0 -9
  99. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
  100. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
  101. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
  102. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
  103. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
  104. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
  105. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
  106. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
  107. data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
  108. data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
  109. data/test/fixtures/docinfo-footer.html +0 -1
  110. data/test/fixtures/docinfo-footer.xml +0 -9
  111. data/test/fixtures/docinfo.html +0 -1
  112. data/test/fixtures/docinfo.xml +0 -3
  113. data/test/fixtures/doctime-localtime.adoc +0 -2
  114. data/test/fixtures/dot.gif +0 -0
  115. data/test/fixtures/encoding.asciidoc +0 -13
  116. data/test/fixtures/file-with-missing-include.adoc +0 -1
  117. data/test/fixtures/grandchild-include.adoc +0 -3
  118. data/test/fixtures/hello-asciidoctor.pdf +0 -69
  119. data/test/fixtures/include-file.asciidoc +0 -24
  120. data/test/fixtures/include-file.jsx +0 -8
  121. data/test/fixtures/include-file.ml +0 -3
  122. data/test/fixtures/include-file.xml +0 -5
  123. data/test/fixtures/lists.adoc +0 -96
  124. data/test/fixtures/master.adoc +0 -5
  125. data/test/fixtures/mismatched-end-tag.adoc +0 -7
  126. data/test/fixtures/other-chapters.adoc +0 -11
  127. data/test/fixtures/outer-include.adoc +0 -5
  128. data/test/fixtures/parent-include-restricted.adoc +0 -5
  129. data/test/fixtures/parent-include.adoc +0 -5
  130. data/test/fixtures/sample.asciidoc +0 -30
  131. data/test/fixtures/section-a.adoc +0 -4
  132. data/test/fixtures/stylesheets/custom.css +0 -3
  133. data/test/fixtures/subdir/index.adoc +0 -3
  134. data/test/fixtures/subdir/inner-include.adoc +0 -3
  135. data/test/fixtures/subdir/middle-include.adoc +0 -5
  136. data/test/fixtures/subs-docinfo.html +0 -2
  137. data/test/fixtures/subs.adoc +0 -6
  138. data/test/fixtures/tagged-class-enclosed.rb +0 -25
  139. data/test/fixtures/tagged-class.rb +0 -23
  140. data/test/fixtures/tip.gif +0 -0
  141. data/test/fixtures/unclosed-tag.adoc +0 -3
  142. data/test/fixtures/unexpected-end-tag.adoc +0 -4
  143. data/test/invoker_test.rb +0 -745
  144. data/test/links_test.rb +0 -855
  145. data/test/lists_test.rb +0 -5151
  146. data/test/logger_test.rb +0 -211
  147. data/test/manpage_test.rb +0 -660
  148. data/test/options_test.rb +0 -262
  149. data/test/paragraphs_test.rb +0 -562
  150. data/test/parser_test.rb +0 -742
  151. data/test/paths_test.rb +0 -395
  152. data/test/preamble_test.rb +0 -173
  153. data/test/reader_test.rb +0 -2161
  154. data/test/sections_test.rb +0 -3575
  155. data/test/substitutions_test.rb +0 -2066
  156. data/test/tables_test.rb +0 -2036
  157. data/test/test_helper.rb +0 -447
  158. data/test/text_test.rb +0 -309
@@ -1,7 +1,6 @@
1
- # NOTE .to_s hides require from Opal
2
- require 'asciidoctor'.to_s unless defined? Asciidoctor
1
+ # frozen_string_literal: true
2
+ (require 'asciidoctor' unless defined? Asciidoctor.load) unless RUBY_ENGINE == 'opal'
3
3
 
4
- # encoding: UTF-8
5
4
  module Asciidoctor
6
5
  # Extensions provide a way to participate in the parsing and converting
7
6
  # phases of the AsciiDoc processor or extend the AsciiDoc syntax.
@@ -57,27 +56,23 @@ module Extensions
57
56
  config[key] = default_value
58
57
  end
59
58
 
60
- # Include the DSL class for this processor into this processor class or instance.
59
+ # Mixes the DSL class for this processor into this processor class or instance.
61
60
  #
62
- # This method automatically detects whether to use the include or extend keyword
63
- # based on what is appropriate.
61
+ # This method automatically detects whether to use the include or extend keyword to mix in the module.
64
62
  #
65
63
  # NOTE Inspiration for this DSL design comes from https://corcoran.io/2013/09/04/simple-pattern-ruby-dsl/
66
64
  #
67
- # Returns nothing
68
- def use_dsl
69
- if self.name.nil_or_empty?
70
- # NOTE contants(false) doesn't exist in Ruby 1.8.7
71
- #include const_get :DSL if constants(false).grep :DSL
72
- include const_get :DSL if constants.grep :DSL
73
- else
74
- # NOTE contants(false) doesn't exist in Ruby 1.8.7
75
- #extend const_get :DSL if constants(false).grep :DSL
76
- extend const_get :DSL if constants.grep :DSL
65
+ # Returns self
66
+ def enable_dsl
67
+ if const_defined? :DSL
68
+ if singleton_class?
69
+ include const_get :DSL
70
+ else
71
+ extend const_get :DSL
72
+ end
77
73
  end
78
74
  end
79
- alias extend_dsl use_dsl
80
- alias include_dsl use_dsl
75
+ alias use_dsl enable_dsl
81
76
  end
82
77
 
83
78
  # Public: Get the configuration Hash for this processor instance.
@@ -92,7 +87,7 @@ module Extensions
92
87
  end
93
88
 
94
89
  def process *args
95
- raise ::NotImplementedError, %(Asciidoctor::Extensions::Processor subclass must implement ##{__method__} method)
90
+ raise ::NotImplementedError, %(#{Processor} subclass #{self.class} must implement the ##{__method__} method)
96
91
  end
97
92
 
98
93
  # QUESTION should attributes be an option instead of a parameter?
@@ -156,7 +151,7 @@ module Extensions
156
151
  end
157
152
 
158
153
  def create_block parent, context, source, attrs, opts = {}
159
- Block.new parent, context, { :source => source, :attributes => attrs }.merge(opts)
154
+ Block.new parent, context, { source: source, attributes: attrs }.merge(opts)
160
155
  end
161
156
 
162
157
  # Public: Creates a list node and links it to the specified parent.
@@ -250,20 +245,20 @@ module Extensions
250
245
  def process *args, &block
251
246
  if block_given?
252
247
  raise ::ArgumentError, %(wrong number of arguments (given #{args.size}, expected 0)) unless args.empty?
248
+ unless block.binding && self == block.binding.receiver
249
+ # NOTE remap self in process method to processor instance
250
+ context = self
251
+ block.define_singleton_method(:call) {|*m_args| context.instance_exec(*m_args, &block) }
252
+ end
253
253
  @process_block = block
254
254
  # TODO enable if we want to support passing proc or lambda as argument instead of block
255
255
  #elsif ::Proc === args[0]
256
- # block = args.shift
257
- # raise ::ArgumentError, %(wrong number of arguments (given #{args.size}, expected 0)) unless args.empty?
258
- # @process_block = block
256
+ # raise ::ArgumentError, %(wrong number of arguments (given #{args.size - 1}, expected 0)) unless args.size == 1
257
+ # @process_block = args.shift
259
258
  elsif defined? @process_block
260
- # NOTE Proc automatically expands a single array argument
261
- # ...but lambda doesn't (and we want to accept lambdas too)
262
- # TODO need a test for this!
263
259
  @process_block.call(*args)
264
260
  else
265
- # TODO add exception message here
266
- raise ::NotImplementedError
261
+ raise ::NotImplementedError, %(#{self.class} ##{__method__} method called before being registered)
267
262
  end
268
263
  end
269
264
 
@@ -291,28 +286,25 @@ module Extensions
291
286
  option :name, value
292
287
  end
293
288
  end
294
- # NOTE match_name may get deprecated
295
- alias match_name named
296
289
 
297
290
  def content_model value
298
291
  option :content_model, value
299
292
  end
300
293
  alias parse_content_as content_model
301
- alias parses_content_as content_model
302
- #alias parse_as content_model
303
- #alias parsed_as content_model
304
294
 
305
- def positional_attrs *value
295
+ def positional_attributes *value
306
296
  option :pos_attrs, value.flatten
307
297
  end
308
- alias name_attributes positional_attrs
309
- alias name_positional_attributes positional_attrs
298
+ alias name_positional_attributes positional_attributes
299
+ # NOTE positional_attrs alias is deprecated
300
+ alias positional_attrs positional_attributes
310
301
 
311
302
  def default_attrs value
312
303
  option :default_attrs, value
313
304
  end
305
+ alias default_attributes default_attrs
314
306
 
315
- def resolves_attributes *args
307
+ def resolve_attributes *args
316
308
  # NOTE assume true as default value; rewrap single-argument string or symbol
317
309
  if (args = args.fetch 0, true).respond_to? :to_sym
318
310
  args = [args]
@@ -325,15 +317,15 @@ module Extensions
325
317
  names, defaults = [], {}
326
318
  args.each do |arg|
327
319
  if (arg = arg.to_s).include? '='
328
- name, value = arg.split '=', 2
320
+ name, _, value = arg.partition '='
329
321
  if name.include? ':'
330
- idx, name = name.split ':', 2
322
+ idx, _, name = name.partition ':'
331
323
  idx = idx == '@' ? names.size : idx.to_i
332
324
  names[idx] = name
333
325
  end
334
326
  defaults[name] = value
335
327
  elsif arg.include? ':'
336
- idx, name = arg.split ':', 2
328
+ idx, _, name = arg.partition ':'
337
329
  idx = idx == '@' ? names.size : idx.to_i
338
330
  names[idx] = name
339
331
  else
@@ -346,7 +338,7 @@ module Extensions
346
338
  names, defaults = [], {}
347
339
  args.each do |key, val|
348
340
  if (name = key.to_s).include? ':'
349
- idx, name = name.split ':', 2
341
+ idx, _, name = name.partition ':'
350
342
  idx = idx == '@' ? names.size : idx.to_i
351
343
  names[idx] = name
352
344
  end
@@ -358,8 +350,8 @@ module Extensions
358
350
  raise ::ArgumentError, %(unsupported attributes specification for macro: #{args.inspect})
359
351
  end
360
352
  end
361
- # NOTE we may decide to drop this alias
362
- alias resolve_attributes resolves_attributes
353
+ # NOTE resolves_attributes alias is deprecated
354
+ alias resolves_attributes resolve_attributes
363
355
  end
364
356
 
365
357
  # Public: Preprocessors are run after the source text is split into lines and
@@ -377,7 +369,7 @@ module Extensions
377
369
  # Preprocessor implementations must extend the Preprocessor class.
378
370
  class Preprocessor < Processor
379
371
  def process document, reader
380
- raise ::NotImplementedError, %(Asciidoctor::Extensions::Preprocessor subclass must implement ##{__method__} method)
372
+ raise ::NotImplementedError, %(#{Preprocessor} subclass #{self.class} must implement the ##{__method__} method)
381
373
  end
382
374
  end
383
375
  Preprocessor::DSL = DocumentProcessorDsl
@@ -394,7 +386,7 @@ module Extensions
394
386
  # QUESTION should the tree processor get invoked after parse header too?
395
387
  class TreeProcessor < Processor
396
388
  def process document
397
- raise ::NotImplementedError, %(Asciidoctor::Extensions::TreeProcessor subclass must implement ##{__method__} method)
389
+ raise ::NotImplementedError, %(#{TreeProcessor} subclass #{self.class} must implement the ##{__method__} method)
398
390
  end
399
391
  end
400
392
  TreeProcessor::DSL = DocumentProcessorDsl
@@ -419,7 +411,7 @@ module Extensions
419
411
  # Postprocessor implementations must Postprocessor.
420
412
  class Postprocessor < Processor
421
413
  def process document, output
422
- raise ::NotImplementedError, %(Asciidoctor::Extensions::Postprocessor subclass must implement ##{__method__} method)
414
+ raise ::NotImplementedError, %(#{Postprocessor} subclass #{self.class} must implement the ##{__method__} method)
423
415
  end
424
416
  end
425
417
  Postprocessor::DSL = DocumentProcessorDsl
@@ -437,7 +429,7 @@ module Extensions
437
429
  # TODO add file extension or regexp as shortcut for handles? method
438
430
  class IncludeProcessor < Processor
439
431
  def process document, reader, target, attributes
440
- raise ::NotImplementedError, %(Asciidoctor::Extensions::IncludeProcessor subclass must implement ##{__method__} method)
432
+ raise ::NotImplementedError, %(#{IncludeProcessor} subclass #{self.class} must implement the ##{__method__} method)
441
433
  end
442
434
 
443
435
  def handles? target
@@ -483,7 +475,7 @@ module Extensions
483
475
  end
484
476
 
485
477
  def process document
486
- raise ::NotImplementedError, %(Asciidoctor::Extensions::DocinfoProcessor subclass must implement ##{__method__} method)
478
+ raise ::NotImplementedError, %(#{DocinfoProcessor} subclass #{self.class} must implement the ##{__method__} method)
487
479
  end
488
480
  end
489
481
 
@@ -539,7 +531,7 @@ module Extensions
539
531
  end
540
532
 
541
533
  def process parent, reader, attributes
542
- raise ::NotImplementedError, %(Asciidoctor::Extensions::BlockProcessor subclass must implement ##{__method__} method)
534
+ raise ::NotImplementedError, %(#{BlockProcessor} subclass #{self.class} must implement the ##{__method__} method)
543
535
  end
544
536
  end
545
537
 
@@ -551,7 +543,7 @@ module Extensions
551
543
  end
552
544
  alias on_contexts contexts
553
545
  alias on_context contexts
554
- alias bound_to contexts
546
+ alias bind_to contexts
555
547
  end
556
548
  BlockProcessor::DSL = BlockProcessorDsl
557
549
 
@@ -565,14 +557,14 @@ module Extensions
565
557
  end
566
558
 
567
559
  def process parent, target, attributes
568
- raise ::NotImplementedError, %(Asciidoctor::Extensions::MacroProcessor subclass must implement ##{__method__} method)
560
+ raise ::NotImplementedError, %(#{MacroProcessor} subclass #{self.class} must implement the ##{__method__} method)
569
561
  end
570
562
  end
571
563
 
572
564
  module MacroProcessorDsl
573
565
  include SyntaxProcessorDsl
574
566
 
575
- def resolves_attributes *args
567
+ def resolve_attributes *args
576
568
  if args.size == 1 && !args[0]
577
569
  option :content_model, :text
578
570
  return
@@ -580,8 +572,8 @@ module Extensions
580
572
  super
581
573
  option :content_model, :attributes
582
574
  end
583
- # NOTE we may decide to drop this alias
584
- alias resolve_attributes resolves_attributes
575
+ # NOTE resolves_attributes alias is deprecated
576
+ alias resolves_attributes resolve_attributes
585
577
  end
586
578
 
587
579
  # Public: BlockMacroProcessors are used to handle block macros that have a
@@ -622,16 +614,16 @@ module Extensions
622
614
  module InlineMacroProcessorDsl
623
615
  include MacroProcessorDsl
624
616
 
625
- def with_format value
617
+ def format value
626
618
  option :format, value
627
619
  end
628
- alias using_format with_format
620
+ alias match_format format
621
+ # NOTE using_format alias is deprecated
622
+ alias using_format format
629
623
 
630
- def matches value
624
+ def match value
631
625
  option :regexp, value
632
626
  end
633
- alias match matches
634
- alias matching matches
635
627
  end
636
628
  InlineMacroProcessor::DSL = InlineMacroProcessorDsl
637
629
 
@@ -965,7 +957,7 @@ module Extensions
965
957
  # docinfo_processor MetaRobotsDocinfoProcessor
966
958
  #
967
959
  # # as an instance of a DocinfoProcessor subclass with an explicit location
968
- # docinfo_processor JQueryDocinfoProcessor.new, :location => :footer
960
+ # docinfo_processor JQueryDocinfoProcessor.new, location: :footer
969
961
  #
970
962
  # # as a name of a DocinfoProcessor subclass
971
963
  # docinfo_processor 'MetaRobotsDocinfoProcessor'
@@ -1319,30 +1311,27 @@ module Extensions
1319
1311
  def add_document_processor kind, args, &block
1320
1312
  kind_name = kind.to_s.tr '_', ' '
1321
1313
  kind_class_symbol = kind_name.split.map {|it| it.capitalize }.join.to_sym
1322
- kind_class = Extensions.const_get kind_class_symbol
1323
- kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol) : nil
1314
+ kind_class = Extensions.const_get kind_class_symbol, false
1315
+ kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol, false) : nil
1324
1316
  kind_store = instance_variable_get(%(@#{kind}_extensions).to_sym) || instance_variable_set(%(@#{kind}_extensions).to_sym, [])
1325
1317
  # style 1: specified as block
1326
1318
  extension = if block_given?
1327
1319
  config = resolve_args args, 1
1328
- # TODO if block arity is 0, assume block is process method
1329
- processor = kind_class.new config
1330
- # NOTE class << processor idiom doesn't work in Opal
1331
- #class << processor
1332
- # include_dsl
1333
- #end
1334
- # NOTE kind_class.contants(false) doesn't exist in Ruby 1.8.7
1335
- processor.extend kind_class.const_get :DSL if kind_class.constants.grep :DSL
1336
- processor.instance_exec(&block)
1337
- processor.freeze
1320
+ (processor = kind_class.new config).singleton_class.enable_dsl
1321
+ if block.arity == 0
1322
+ processor.instance_exec(&block)
1323
+ else
1324
+ yield processor
1325
+ end
1338
1326
  unless processor.process_block_given?
1339
1327
  raise ::ArgumentError, %(No block specified to process #{kind_name} extension at #{block.source_location})
1340
1328
  end
1329
+ processor.freeze
1341
1330
  ProcessorExtension.new kind, processor
1342
1331
  else
1343
1332
  processor, config = resolve_args args, 2
1344
1333
  # style 2: specified as Class or String class name
1345
- if (processor_class = Extensions.resolve_class processor)
1334
+ if (processor_class = Helpers.resolve_class processor)
1346
1335
  unless processor_class < kind_class || (kind_java_class && processor_class < kind_java_class)
1347
1336
  raise ::ArgumentError, %(Invalid type for #{kind_name} extension: #{processor})
1348
1337
  end
@@ -1365,24 +1354,18 @@ module Extensions
1365
1354
 
1366
1355
  def add_syntax_processor kind, args, &block
1367
1356
  kind_name = kind.to_s.tr '_', ' '
1368
- kind_class_symbol = (kind_name.split.map {|it| it.capitalize }.push 'Processor').join.to_sym
1369
- kind_class = Extensions.const_get kind_class_symbol
1370
- kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol) : nil
1357
+ kind_class_symbol = (kind_name.split.map {|it| it.capitalize } << 'Processor').join.to_sym
1358
+ kind_class = Extensions.const_get kind_class_symbol, false
1359
+ kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol, false) : nil
1371
1360
  kind_store = instance_variable_get(%(@#{kind}_extensions).to_sym) || instance_variable_set(%(@#{kind}_extensions).to_sym, {})
1372
1361
  # style 1: specified as block
1373
1362
  if block_given?
1374
1363
  name, config = resolve_args args, 2
1375
- processor = kind_class.new as_symbol(name), config
1376
- # NOTE class << processor idiom doesn't work in Opal
1377
- #class << processor
1378
- # include_dsl
1379
- #end
1380
- # NOTE kind_class.contants(false) doesn't exist in Ruby 1.8.7
1381
- processor.extend kind_class.const_get :DSL if kind_class.constants.grep :DSL
1382
- if block.arity == 1
1383
- yield processor
1384
- else
1364
+ (processor = kind_class.new (as_symbol name), config).singleton_class.enable_dsl
1365
+ if block.arity == 0
1385
1366
  processor.instance_exec(&block)
1367
+ else
1368
+ yield processor
1386
1369
  end
1387
1370
  unless (name = as_symbol processor.name)
1388
1371
  raise ::ArgumentError, %(No name specified for #{kind_name} extension at #{block.source_location})
@@ -1395,7 +1378,7 @@ module Extensions
1395
1378
  else
1396
1379
  processor, name, config = resolve_args args, 3
1397
1380
  # style 2: specified as Class or String class name
1398
- if (processor_class = Extensions.resolve_class processor)
1381
+ if (processor_class = Helpers.resolve_class processor)
1399
1382
  unless processor_class < kind_class || (kind_java_class && processor_class < kind_java_class)
1400
1383
  raise ::ArgumentError, %(Class specified for #{kind_name} extension does not inherit from #{kind_class}: #{processor})
1401
1384
  end
@@ -1453,13 +1436,11 @@ module Extensions
1453
1436
 
1454
1437
  def create name = nil, &block
1455
1438
  if block_given?
1456
- Registry.new({ (name || generate_name) => block })
1439
+ Registry.new (name || generate_name) => block
1457
1440
  else
1458
1441
  Registry.new
1459
1442
  end
1460
1443
  end
1461
- # Deprecated: Use create instead of build_registry
1462
- alias build_registry create
1463
1444
 
1464
1445
  # Public: Registers an extension Group that subsequently registers a
1465
1446
  # collection of extensions.
@@ -1501,7 +1482,7 @@ module Extensions
1501
1482
  resolved_group = block
1502
1483
  elsif (group = args.pop)
1503
1484
  # QUESTION should we instantiate the group class here or defer until activation??
1504
- resolved_group = (resolve_class group) || group
1485
+ resolved_group = (Helpers.resolve_class group) || group
1505
1486
  else
1506
1487
  raise ::ArgumentError, %(Extension group to register not specified)
1507
1488
  end
@@ -1529,55 +1510,6 @@ module Extensions
1529
1510
  names.each {|group| @groups.delete group.to_sym }
1530
1511
  nil
1531
1512
  end
1532
-
1533
- # Internal: Resolve the specified object as a Class
1534
- #
1535
- # object - The object to resolve as a Class
1536
- #
1537
- # Returns a Class if the specified object is a Class (but not a Module) or
1538
- # a String that resolves to a Class; otherwise, nil
1539
- def resolve_class object
1540
- case object
1541
- when ::Class
1542
- object
1543
- when ::String
1544
- class_for_name object
1545
- end
1546
- end
1547
-
1548
- # Public: Resolves the Class object for the qualified name.
1549
- #
1550
- # Returns Class
1551
- if ::RUBY_MIN_VERSION_2
1552
- def class_for_name qualified_name
1553
- resolved = ::Object.const_get qualified_name, false
1554
- raise unless ::Class === resolved
1555
- resolved
1556
- rescue
1557
- raise ::NameError, %(Could not resolve class for name: #{qualified_name})
1558
- end
1559
- elsif ::RUBY_MIN_VERSION_1_9
1560
- def class_for_name qualified_name
1561
- resolved = (qualified_name.split '::').reduce ::Object do |current, name|
1562
- name.empty? ? current : (current.const_get name, false)
1563
- end
1564
- raise unless ::Class === resolved
1565
- resolved
1566
- rescue
1567
- raise ::NameError, %(Could not resolve class for name: #{qualified_name})
1568
- end
1569
- else
1570
- def class_for_name qualified_name
1571
- resolved = (qualified_name.split '::').reduce ::Object do |current, name|
1572
- # NOTE on Ruby 1.8, const_defined? only checks for constant in current scope
1573
- name.empty? ? current : ((current.const_defined? name) ? (current.const_get name) : raise)
1574
- end
1575
- raise unless ::Class === resolved
1576
- resolved
1577
- rescue
1578
- raise ::NameError, %(Could not resolve class for name: #{qualified_name})
1579
- end
1580
- end
1581
1513
  end
1582
1514
  end
1583
1515
  end
@@ -1,5 +1,6 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
  module Asciidoctor
3
+ # Internal: Except where noted, a module that contains internal helper functions.
3
4
  module Helpers
4
5
  # Internal: Require the specified library using Kernel#require.
5
6
  #
@@ -43,85 +44,63 @@ module Helpers
43
44
  nil
44
45
  end
45
46
 
46
- # Public: Normalize the data to prepare for parsing
47
- #
48
- # Delegates to Helpers#normalize_lines_from_string if data is a String.
49
- # Delegates to Helpers#normalize_lines_array if data is a String Array.
50
- #
51
- # returns a String Array of normalized lines
52
- def self.normalize_lines data
53
- ::String === data ? (normalize_lines_from_string data) : (normalize_lines_array data)
54
- end
55
-
56
- # Public: Normalize the array of lines to prepare them for parsing
57
- #
58
- # Force encodes the data to UTF-8 and removes trailing whitespace from each line.
59
- #
60
- # If a BOM is present at the beginning of the data, a best attempt
61
- # is made to encode from the specified encoding to UTF-8.
62
- #
63
- # data - a String Array of lines to normalize
64
- #
65
- # returns a String Array of normalized lines
66
- def self.normalize_lines_array data
67
- return data if data.empty?
68
-
69
- leading_bytes = (first_line = data[0]).unpack 'C3'
70
- if COERCE_ENCODING
71
- utf8 = ::Encoding::UTF_8
72
- if (leading_2_bytes = leading_bytes.slice 0, 2) == BOM_BYTES_UTF_16LE
73
- # HACK Ruby messes up trailing whitespace on UTF-16LE, so reencode whole document first
74
- data = data.join
75
- return (((data.force_encoding ::Encoding::UTF_16LE).slice 1, data.length).encode utf8).each_line.map {|line| line.rstrip }
76
- elsif leading_2_bytes == BOM_BYTES_UTF_16BE
77
- data[0] = (first_line.force_encoding ::Encoding::UTF_16BE).slice 1, first_line.length
78
- return data.map {|line| ((line.force_encoding ::Encoding::UTF_16BE).encode utf8).rstrip }
79
- elsif leading_bytes == BOM_BYTES_UTF_8
80
- data[0] = (first_line.force_encoding utf8).slice 1, first_line.length
81
- end
82
-
83
- data.map {|line| line.encoding == utf8 ? line.rstrip : (line.force_encoding utf8).rstrip }
84
- else
85
- # Ruby 1.8 has no built-in re-encoding, so no point in removing the UTF-16 BOMs
86
- data[0] = first_line.slice 3, first_line.length if leading_bytes == BOM_BYTES_UTF_8
47
+ # Internal: Prepare the source data Array for parsing.
48
+ #
49
+ # Encodes the data to UTF-8, if necessary, and removes any trailing
50
+ # whitespace from every line.
51
+ #
52
+ # If a BOM is found at the beginning of the data, a best attempt is made to
53
+ # encode it to UTF-8 from the specified source encoding.
54
+ #
55
+ # data - the source data Array to prepare (no nil entries allowed)
56
+ #
57
+ # returns a String Array of prepared lines
58
+ def self.prepare_source_array data
59
+ return [] if data.empty?
60
+ if (leading_2_bytes = (leading_bytes = (first = data[0]).unpack 'C3').slice 0, 2) == BOM_BYTES_UTF_16LE
61
+ data[0] = first.byteslice 2, first.bytesize
62
+ # NOTE you can't split a UTF-16LE string using .lines when encoding is UTF-8; doing so will cause this line to fail
63
+ return data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16LE).rstrip }
64
+ elsif leading_2_bytes == BOM_BYTES_UTF_16BE
65
+ data[0] = first.byteslice 2, first.bytesize
66
+ return data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16BE).rstrip }
67
+ elsif leading_bytes == BOM_BYTES_UTF_8
68
+ data[0] = first.byteslice 3, first.bytesize
69
+ end
70
+ if first.encoding == UTF_8
87
71
  data.map {|line| line.rstrip }
72
+ else
73
+ data.map {|line| (line.encode UTF_8).rstrip }
88
74
  end
89
75
  end
90
76
 
91
- # Public: Normalize the String and split into lines to prepare them for parsing
77
+ # Internal: Prepare the source data String for parsing.
92
78
  #
93
- # Force encodes the data to UTF-8 and removes trailing whitespace from each line.
94
- # Converts the data to a String Array.
79
+ # Encodes the data to UTF-8, if necessary, splits it into an array, and
80
+ # removes any trailing whitespace from every line.
95
81
  #
96
- # If a BOM is present at the beginning of the data, a best attempt
97
- # is made to encode from the specified encoding to UTF-8.
82
+ # If a BOM is found at the beginning of the data, a best attempt is made to
83
+ # encode it to UTF-8 from the specified source encoding.
98
84
  #
99
- # data - a String of lines to normalize
85
+ # data - the source data String to prepare
100
86
  #
101
- # returns a String Array of normalized lines
102
- def self.normalize_lines_from_string data
87
+ # returns a String Array of prepared lines
88
+ def self.prepare_source_string data
103
89
  return [] if data.nil_or_empty?
104
-
105
- leading_bytes = data.unpack 'C3'
106
- if COERCE_ENCODING
107
- utf8 = ::Encoding::UTF_8
108
- if (leading_2_bytes = leading_bytes.slice 0, 2) == BOM_BYTES_UTF_16LE
109
- data = ((data.force_encoding ::Encoding::UTF_16LE).slice 1, data.length).encode utf8
110
- elsif leading_2_bytes == BOM_BYTES_UTF_16BE
111
- data = ((data.force_encoding ::Encoding::UTF_16BE).slice 1, data.length).encode utf8
112
- elsif leading_bytes == BOM_BYTES_UTF_8
113
- data = data.encoding == utf8 ? (data.slice 1, data.length) : ((data.force_encoding utf8).slice 1, data.length)
114
- else
115
- data = data.force_encoding utf8 unless data.encoding == utf8
116
- end
117
- else
118
- # Ruby 1.8 has no built-in re-encoding, so no point in removing the UTF-16 BOMs
119
- data = data.slice 3, data.length if leading_bytes == BOM_BYTES_UTF_8
90
+ if (leading_2_bytes = (leading_bytes = data.unpack 'C3').slice 0, 2) == BOM_BYTES_UTF_16LE
91
+ data = (data.byteslice 2, data.bytesize).encode UTF_8, ::Encoding::UTF_16LE
92
+ elsif leading_2_bytes == BOM_BYTES_UTF_16BE
93
+ data = (data.byteslice 2, data.bytesize).encode UTF_8, ::Encoding::UTF_16BE
94
+ elsif leading_bytes == BOM_BYTES_UTF_8
95
+ data = data.byteslice 3, data.bytesize
96
+ data = data.encode UTF_8 unless data.encoding == UTF_8
97
+ elsif data.encoding != UTF_8
98
+ data = data.encode UTF_8
120
99
  end
121
- data.each_line.map {|line| line.rstrip }
100
+ [].tap {|lines| data.each_line {|line| lines << line.rstrip } }
122
101
  end
123
102
 
124
- # Public: Efficiently checks whether the specified String resembles a URI
103
+ # Internal: Efficiently checks whether the specified String resembles a URI
125
104
  #
126
105
  # Uses the Asciidoctor::UriSniffRx regex to check whether the String begins
127
106
  # with a URI prefix (e.g., http://). No validation of the URI is performed.
@@ -133,7 +112,7 @@ module Helpers
133
112
  (str.include? ':') && (UriSniffRx.match? str)
134
113
  end
135
114
 
136
- # Public: Efficiently retrieves the URI prefix of the specified String
115
+ # Internal: Efficiently retrieves the URI prefix of the specified String
137
116
  #
138
117
  # Uses the Asciidoctor::UriSniffRx regex to match the URI prefix in the
139
118
  # specified String (e.g., http://), if present.
@@ -145,16 +124,35 @@ module Helpers
145
124
  (str.include? ':') && UriSniffRx =~ str ? $& : nil
146
125
  end
147
126
 
148
- # Matches the characters in a URI to encode
149
- REGEXP_ENCODE_URI_CHARS = /[^\w\-.!~*';:@=+$,()\[\]]/
127
+ # Internal: Encode a URI component String for safe inclusion in a URI.
128
+ #
129
+ # str - the URI component String to encode
130
+ #
131
+ # Returns the String with all reserved URI characters encoded (e.g., /, &, =, space, etc).
132
+ if RUBY_ENGINE == 'opal'
133
+ def self.encode_uri_component str
134
+ # patch necessary to adhere with RFC-3986 (and thus CGI.escape)
135
+ # see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#Description
136
+ %x(
137
+ return encodeURIComponent(str).replace(/%20|[!'()*]/g, function (m) {
138
+ return m === '%20' ? '+' : '%' + m.charCodeAt(0).toString(16)
139
+ })
140
+ )
141
+ end
142
+ else
143
+ CGI = ::CGI
144
+ def self.encode_uri_component str
145
+ CGI.escape str
146
+ end
147
+ end
150
148
 
151
- # Public: Encode a String for inclusion in a URI.
149
+ # Internal: Encode a URI String (namely the path portion).
152
150
  #
153
- # str - the String to URI encode
151
+ # str - the String to encode
154
152
  #
155
- # Returns the String with all URI reserved characters encoded.
156
- def self.uri_encode str
157
- str.gsub(REGEXP_ENCODE_URI_CHARS) { $&.each_byte.map {|c| sprintf '%%%02X', c }.join }
153
+ # Returns the String with all spaces replaced with %20.
154
+ def self.encode_uri str
155
+ (str.include? ' ') ? (str.gsub ' ', '%20') : str
158
156
  end
159
157
 
160
158
  # Public: Removes the file extension from filename and returns the result
@@ -163,7 +161,7 @@ module Helpers
163
161
  #
164
162
  # Examples
165
163
  #
166
- # Helpers.rootname('part1/chapter1.adoc')
164
+ # Helpers.rootname 'part1/chapter1.adoc'
167
165
  # # => "part1/chapter1"
168
166
  #
169
167
  # Returns the String filename with the file extension removed
@@ -179,14 +177,14 @@ module Helpers
179
177
  #
180
178
  # Examples
181
179
  #
182
- # Helpers.basename('images/tiger.png', true)
180
+ # Helpers.basename 'images/tiger.png', true
183
181
  # # => "tiger"
184
182
  #
185
- # Helpers.basename('images/tiger.png', '.png')
183
+ # Helpers.basename 'images/tiger.png', '.png'
186
184
  # # => "tiger"
187
185
  #
188
186
  # Returns the String filename with leading directories removed and, if specified, the extension removed
189
- def self.basename(filename, drop_ext = nil)
187
+ def self.basename filename, drop_ext = nil
190
188
  if drop_ext
191
189
  ::File.basename filename, (drop_ext == true ? (::File.extname filename) : drop_ext)
192
190
  else
@@ -194,6 +192,7 @@ module Helpers
194
192
  end
195
193
  end
196
194
 
195
+ # Internal: Make a directory, ensuring all parent directories exist.
197
196
  def self.mkdir_p dir
198
197
  unless ::File.directory? dir
199
198
  unless (parent_dir = ::File.dirname dir) == '.'
@@ -212,16 +211,56 @@ module Helpers
212
211
  'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1
213
212
  }
214
213
 
215
- # Converts an integer to a Roman numeral.
214
+ # Internal: Converts an integer to a Roman numeral.
216
215
  #
217
216
  # val - the [Integer] value to convert
218
217
  #
219
218
  # Returns the [String] roman numeral for this integer
220
219
  def self.int_to_roman val
221
- ROMAN_NUMERALS.map {|l, i|
220
+ ROMAN_NUMERALS.map do |l, i|
222
221
  repeat, val = val.divmod i
223
222
  l * repeat
224
- }.join
223
+ end.join
224
+ end
225
+
226
+ # Internal: Get the next value in the sequence.
227
+ #
228
+ # Handles both integer and character sequences.
229
+ #
230
+ # current - the value to increment as a String or Integer
231
+ #
232
+ # returns the next value in the sequence according to the current value's type
233
+ def self.nextval current
234
+ if ::Integer === current
235
+ current + 1
236
+ else
237
+ intval = current.to_i
238
+ if intval.to_s != current.to_s
239
+ (current[0].ord + 1).chr
240
+ else
241
+ intval + 1
242
+ end
243
+ end
244
+ end
245
+
246
+ # Internal: Resolve the specified object as a Class
247
+ #
248
+ # object - The Object to resolve as a Class
249
+ #
250
+ # Returns a Class if the specified object is a Class (but not a Module) or
251
+ # a String that resolves to a Class; otherwise, nil
252
+ def self.resolve_class object
253
+ ::Class === object ? object : (::String === object ? (class_for_name object) : nil)
254
+ end
255
+
256
+ # Internal: Resolves a Class object (not a Module) for the qualified name.
257
+ #
258
+ # Returns Class
259
+ def self.class_for_name qualified_name
260
+ raise unless ::Class === (resolved = ::Object.const_get qualified_name, false)
261
+ resolved
262
+ rescue
263
+ raise ::NameError, %(Could not resolve class for name: #{qualified_name})
225
264
  end
226
265
  end
227
266
  end