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.
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