asciidoctor 1.5.5 → 1.5.6
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.
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 |  |