asciidoctor 1.5.6.2 → 1.5.7
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 +330 -143
- data/README-fr.adoc +441 -0
- data/README-jp.adoc +418 -0
- data/README-zh_CN.adoc +430 -0
- data/README.adoc +454 -0
- data/Rakefile +57 -0
- data/asciidoctor.gemspec +7 -1
- data/data/locale/attributes-ar.adoc +22 -0
- data/data/locale/attributes-bg.adoc +22 -0
- data/data/locale/attributes-ca.adoc +22 -0
- data/data/locale/attributes-cs.adoc +22 -0
- data/data/locale/attributes-da.adoc +22 -0
- data/data/locale/attributes-de.adoc +22 -0
- data/data/locale/attributes-en.adoc +23 -0
- data/data/locale/attributes-es.adoc +22 -0
- data/data/locale/attributes-fa.adoc +22 -0
- data/data/locale/attributes-fi.adoc +22 -0
- data/data/locale/attributes-fr.adoc +22 -0
- data/data/locale/attributes-hu.adoc +22 -0
- data/data/locale/attributes-id.adoc +22 -0
- data/data/locale/attributes-it.adoc +22 -0
- data/data/locale/attributes-ja.adoc +22 -0
- data/data/locale/attributes-kr.adoc +22 -0
- data/data/locale/attributes-nb.adoc +22 -0
- data/data/locale/attributes-nl.adoc +22 -0
- data/data/locale/attributes-nn.adoc +22 -0
- data/data/locale/attributes-pl.adoc +22 -0
- data/data/locale/attributes-pt.adoc +22 -0
- data/data/locale/attributes-pt_BR.adoc +22 -0
- data/data/locale/attributes-ro.adoc +22 -0
- data/data/locale/attributes-ru.adoc +22 -0
- data/data/locale/attributes-sr.adoc +22 -0
- data/data/locale/attributes-sr_Latn.adoc +22 -0
- data/data/locale/attributes-tr.adoc +22 -0
- data/data/locale/attributes-uk.adoc +22 -0
- data/data/locale/attributes-zh_CN.adoc +22 -0
- data/data/locale/attributes-zh_TW.adoc +22 -0
- data/data/locale/attributes.adoc +8 -649
- data/data/stylesheets/asciidoctor-default.css +77 -72
- data/features/xref.feature +366 -7
- data/lib/asciidoctor.rb +107 -93
- data/lib/asciidoctor/abstract_block.rb +247 -239
- data/lib/asciidoctor/abstract_node.rb +56 -58
- data/lib/asciidoctor/block.rb +3 -3
- data/lib/asciidoctor/callouts.rb +1 -1
- data/lib/asciidoctor/cli/invoker.rb +36 -9
- data/lib/asciidoctor/cli/options.rb +63 -25
- data/lib/asciidoctor/converter.rb +23 -13
- data/lib/asciidoctor/converter/base.rb +4 -0
- data/lib/asciidoctor/converter/docbook45.rb +16 -9
- data/lib/asciidoctor/converter/docbook5.rb +115 -97
- data/lib/asciidoctor/converter/factory.rb +29 -31
- data/lib/asciidoctor/converter/html5.rb +229 -192
- data/lib/asciidoctor/converter/manpage.rb +72 -50
- data/lib/asciidoctor/converter/template.rb +12 -12
- data/lib/asciidoctor/core_ext.rb +5 -1
- data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +6 -0
- data/lib/asciidoctor/document.rb +168 -77
- data/lib/asciidoctor/extensions.rb +79 -47
- data/lib/asciidoctor/helpers.rb +33 -11
- data/lib/asciidoctor/inline.rb +3 -2
- data/lib/asciidoctor/list.rb +2 -1
- data/lib/asciidoctor/logging.rb +122 -0
- data/lib/asciidoctor/parser.rb +406 -382
- data/lib/asciidoctor/path_resolver.rb +169 -162
- data/lib/asciidoctor/reader.rb +166 -121
- data/lib/asciidoctor/section.rb +45 -28
- data/lib/asciidoctor/stylesheets.rb +13 -5
- data/lib/asciidoctor/substitutors.rb +328 -254
- data/lib/asciidoctor/table.rb +105 -48
- data/lib/asciidoctor/timings.rb +34 -6
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +41 -23
- data/man/asciidoctor.adoc +14 -8
- data/test/api_test.rb +1004 -0
- data/test/attributes_test.rb +241 -50
- data/test/blocks_test.rb +549 -124
- data/test/converter_test.rb +170 -78
- data/test/document_test.rb +208 -767
- data/test/extensions_test.rb +188 -53
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +1 -1
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +1 -1
- data/test/fixtures/file-with-missing-include.adoc +1 -0
- data/test/fixtures/include-file.jsx +8 -0
- data/test/fixtures/lists.adoc +96 -0
- data/test/fixtures/other-chapters.adoc +11 -0
- data/test/fixtures/outer-include.adoc +5 -0
- data/test/fixtures/sample.asciidoc +5 -1
- data/test/fixtures/subdir/index.adoc +3 -0
- data/test/fixtures/subdir/inner-include.adoc +3 -0
- data/test/fixtures/subdir/middle-include.adoc +5 -0
- data/test/fixtures/tagged-class-enclosed.rb +0 -1
- data/test/fixtures/unclosed-tag.adoc +3 -0
- data/test/fixtures/unexpected-end-tag.adoc +4 -0
- data/test/invoker_test.rb +101 -40
- data/test/links_test.rb +266 -72
- data/test/lists_test.rb +243 -45
- data/test/logger_test.rb +211 -0
- data/test/manpage_test.rb +124 -6
- data/test/options_test.rb +46 -1
- data/test/paragraphs_test.rb +23 -10
- data/test/parser_test.rb +30 -1
- data/test/paths_test.rb +115 -33
- data/test/preamble_test.rb +1 -1
- data/test/reader_test.rb +337 -81
- data/test/sections_test.rb +656 -72
- data/test/substitutions_test.rb +182 -57
- data/test/tables_test.rb +324 -57
- data/test/test_helper.rb +77 -32
- data/test/text_test.rb +7 -7
- metadata +67 -3
| @@ -4,26 +4,26 @@ module Asciidoctor | |
| 4 4 | 
             
            # node of AsciiDoc content. The state and methods on this class are comment to
         | 
| 5 5 | 
             
            # all content segments in an AsciiDoc document.
         | 
| 6 6 | 
             
            class AbstractNode
         | 
| 7 | 
            -
             | 
| 7 | 
            +
              include Logging
         | 
| 8 8 | 
             
              include Substitutors
         | 
| 9 9 |  | 
| 10 | 
            -
              # Public: Get the  | 
| 11 | 
            -
              attr_reader : | 
| 12 | 
            -
             | 
| 13 | 
            -
              # Public: Get the Asciidoctor::Document to which this node belongs
         | 
| 14 | 
            -
              attr_reader :document
         | 
| 10 | 
            +
              # Public: Get the Hash of attributes for this node
         | 
| 11 | 
            +
              attr_reader :attributes
         | 
| 15 12 |  | 
| 16 13 | 
             
              # Public: Get the Symbol context for this node
         | 
| 17 14 | 
             
              attr_reader :context
         | 
| 18 15 |  | 
| 19 | 
            -
              # Public: Get the  | 
| 20 | 
            -
              attr_reader : | 
| 16 | 
            +
              # Public: Get the Asciidoctor::Document to which this node belongs
         | 
| 17 | 
            +
              attr_reader :document
         | 
| 21 18 |  | 
| 22 19 | 
             
              # Public: Get/Set the id of this node
         | 
| 23 20 | 
             
              attr_accessor :id
         | 
| 24 21 |  | 
| 25 | 
            -
              # Public: Get the  | 
| 26 | 
            -
              attr_reader : | 
| 22 | 
            +
              # Public: Get the String name of this node
         | 
| 23 | 
            +
              attr_reader :node_name
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              # Public: Get the element which is the parent of this node
         | 
| 26 | 
            +
              attr_reader :parent
         | 
| 27 27 |  | 
| 28 28 | 
             
              def initialize parent, context, opts = {}
         | 
| 29 29 | 
             
                if context == :document
         | 
| @@ -42,22 +42,6 @@ class AbstractNode | |
| 42 42 | 
             
                @passthroughs = {}
         | 
| 43 43 | 
             
              end
         | 
| 44 44 |  | 
| 45 | 
            -
              # Public: Associate this Block with a new parent Block
         | 
| 46 | 
            -
              #
         | 
| 47 | 
            -
              # parent - The Block to set as the parent of this Block
         | 
| 48 | 
            -
              #
         | 
| 49 | 
            -
              # Returns nothing
         | 
| 50 | 
            -
              def parent=(parent)
         | 
| 51 | 
            -
                @parent, @document = parent, parent.document
         | 
| 52 | 
            -
                nil
         | 
| 53 | 
            -
              end
         | 
| 54 | 
            -
             | 
| 55 | 
            -
              # Public: Get the Asciidoctor::Converter instance being used to convert the
         | 
| 56 | 
            -
              # current Asciidoctor::Document.
         | 
| 57 | 
            -
              def converter
         | 
| 58 | 
            -
                @document.converter
         | 
| 59 | 
            -
              end
         | 
| 60 | 
            -
             | 
| 61 45 | 
             
              # Public: Returns whether this {AbstractNode} is an instance of {Block}
         | 
| 62 46 | 
             
              #
         | 
| 63 47 | 
             
              # Returns [Boolean]
         | 
| @@ -76,6 +60,21 @@ class AbstractNode | |
| 76 60 | 
             
                # :nocov:
         | 
| 77 61 | 
             
              end
         | 
| 78 62 |  | 
| 63 | 
            +
              # Public: Get the Asciidoctor::Converter instance being used to convert the
         | 
| 64 | 
            +
              # current Asciidoctor::Document.
         | 
| 65 | 
            +
              def converter
         | 
| 66 | 
            +
                @document.converter
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              # Public: Associate this Block with a new parent Block
         | 
| 70 | 
            +
              #
         | 
| 71 | 
            +
              # parent - The Block to set as the parent of this Block
         | 
| 72 | 
            +
              #
         | 
| 73 | 
            +
              # Returns the new parent Block associated with this Block
         | 
| 74 | 
            +
              def parent= parent
         | 
| 75 | 
            +
                @parent, @document = parent, parent.document
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 79 78 | 
             
              # Public: Get the value of the specified attribute
         | 
| 80 79 | 
             
              #
         | 
| 81 80 | 
             
              # Get the value for the specified attribute. First look in the attributes on
         | 
| @@ -212,7 +211,7 @@ class AbstractNode | |
| 212 211 | 
             
              # in the list of roles on this node
         | 
| 213 212 | 
             
              def has_role?(name)
         | 
| 214 213 | 
             
                # NOTE center + include? is faster than split + include?
         | 
| 215 | 
            -
                (val = @attributes['role'] || @document.attributes['role']) | 
| 214 | 
            +
                (val = @attributes['role'] || @document.attributes['role']) ? %( #{val} ).include?(%( #{name} )) : false
         | 
| 216 215 | 
             
              end
         | 
| 217 216 |  | 
| 218 217 | 
             
              # Public: A convenience method that adds the given role directly to this node
         | 
| @@ -279,15 +278,14 @@ class AbstractNode | |
| 279 278 | 
             
              # Returns A String reference or data URI for an icon image
         | 
| 280 279 | 
             
              def icon_uri name
         | 
| 281 280 | 
             
                if attr? 'icon'
         | 
| 282 | 
            -
                   | 
| 283 | 
            -
             | 
| 284 | 
            -
                    %(#{ | 
| 285 | 
            -
                  else
         | 
| 286 | 
            -
                    uri
         | 
| 281 | 
            +
                  if ::File.extname(icon = (attr 'icon')).empty?
         | 
| 282 | 
            +
                    # QUESTION should we be adding the extension if the icon is an absolute URI?
         | 
| 283 | 
            +
                    icon = %(#{icon}.#{@document.attr 'icontype', 'png'})
         | 
| 287 284 | 
             
                  end
         | 
| 288 285 | 
             
                else
         | 
| 289 | 
            -
                   | 
| 286 | 
            +
                  icon = %(#{name}.#{@document.attr 'icontype', 'png'})
         | 
| 290 287 | 
             
                end
         | 
| 288 | 
            +
                image_uri icon, 'iconsdir'
         | 
| 291 289 | 
             
              end
         | 
| 292 290 |  | 
| 293 291 | 
             
              # Public: Construct a URI reference or data URI to the target image.
         | 
| @@ -367,15 +365,15 @@ class AbstractNode | |
| 367 365 | 
             
                  image_path = normalize_system_path(target_image)
         | 
| 368 366 | 
             
                end
         | 
| 369 367 |  | 
| 370 | 
            -
                 | 
| 371 | 
            -
                   | 
| 372 | 
            -
                   | 
| 368 | 
            +
                if ::File.readable? image_path
         | 
| 369 | 
            +
                  # NOTE base64 is autoloaded by reference to ::Base64
         | 
| 370 | 
            +
                  %(data:#{mimetype};base64,#{::Base64.strict_encode64 ::IO.binread image_path})
         | 
| 371 | 
            +
                else
         | 
| 372 | 
            +
                  logger.warn %(image to embed not found or not readable: #{image_path})
         | 
| 373 | 
            +
                  %(data:#{mimetype};base64,)
         | 
| 373 374 | 
             
                  # uncomment to return 1 pixel white dot instead
         | 
| 374 | 
            -
                  # | 
| 375 | 
            +
                  #'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
         | 
| 375 376 | 
             
                end
         | 
| 376 | 
            -
             | 
| 377 | 
            -
                # NOTE base64 is autoloaded by reference to ::Base64
         | 
| 378 | 
            -
                %(data:#{mimetype};base64,#{::Base64.encode64(::IO.binread image_path).delete LF})
         | 
| 379 377 | 
             
              end
         | 
| 380 378 |  | 
| 381 379 | 
             
              # Public: Read the image data from the specified URI and generate a data URI
         | 
| @@ -402,14 +400,14 @@ class AbstractNode | |
| 402 400 |  | 
| 403 401 | 
             
                begin
         | 
| 404 402 | 
             
                  mimetype = nil
         | 
| 405 | 
            -
                  bindata = open | 
| 403 | 
            +
                  bindata = open image_uri, 'rb' do |fd|
         | 
| 406 404 | 
             
                    mimetype = fd.content_type
         | 
| 407 405 | 
             
                    fd.read
         | 
| 408 | 
            -
                   | 
| 406 | 
            +
                  end
         | 
| 409 407 | 
             
                  # NOTE base64 is autoloaded by reference to ::Base64
         | 
| 410 | 
            -
                  %(data:#{mimetype};base64,#{::Base64. | 
| 408 | 
            +
                  %(data:#{mimetype};base64,#{::Base64.strict_encode64 bindata})
         | 
| 411 409 | 
             
                rescue
         | 
| 412 | 
            -
                  warn %( | 
| 410 | 
            +
                  logger.warn %(could not retrieve image data from URI: #{image_uri})
         | 
| 413 411 | 
             
                  image_uri
         | 
| 414 412 | 
             
                  # uncomment to return empty data (however, mimetype needs to be resolved)
         | 
| 415 413 | 
             
                  #%(data:#{mimetype}:base64,)
         | 
| @@ -442,8 +440,8 @@ class AbstractNode | |
| 442 440 | 
             
              # start  - the String start (i.e., parent) path
         | 
| 443 441 | 
             
              # jail   - the String jail path to confine the resolved path
         | 
| 444 442 | 
             
              # opts   - an optional Hash of options to control processing (default: {}):
         | 
| 445 | 
            -
              #          * :recover is used to control whether the processor should | 
| 446 | 
            -
              # | 
| 443 | 
            +
              #          * :recover is used to control whether the processor should
         | 
| 444 | 
            +
              #            automatically recover when an illegal path is encountered
         | 
| 447 445 | 
             
              #          * :target_name is used in messages to refer to the path being resolved
         | 
| 448 446 | 
             
              #
         | 
| 449 447 | 
             
              # raises a SecurityError if a jail is specified and the resolved path is
         | 
| @@ -453,10 +451,9 @@ class AbstractNode | |
| 453 451 | 
             
              # parent references resolved and self references removed. If a jail is provided,
         | 
| 454 452 | 
             
              # this path will be guaranteed to be contained within the jail.
         | 
| 455 453 | 
             
              def normalize_system_path target, start = nil, jail = nil, opts = {}
         | 
| 456 | 
            -
                path_resolver = (@path_resolver ||= PathResolver.new)
         | 
| 457 454 | 
             
                if (doc = @document).safe < SafeMode::SAFE
         | 
| 458 455 | 
             
                  if start
         | 
| 459 | 
            -
                    start = ::File.join doc.base_dir, start unless path_resolver.root? start
         | 
| 456 | 
            +
                    start = ::File.join doc.base_dir, start unless doc.path_resolver.root? start
         | 
| 460 457 | 
             
                  else
         | 
| 461 458 | 
             
                    start = doc.base_dir
         | 
| 462 459 | 
             
                  end
         | 
| @@ -464,7 +461,7 @@ class AbstractNode | |
| 464 461 | 
             
                  start = doc.base_dir unless start
         | 
| 465 462 | 
             
                  jail = doc.base_dir unless jail
         | 
| 466 463 | 
             
                end
         | 
| 467 | 
            -
                path_resolver.system_path target, start, jail, opts
         | 
| 464 | 
            +
                doc.path_resolver.system_path target, start, jail, opts
         | 
| 468 465 | 
             
              end
         | 
| 469 466 |  | 
| 470 467 | 
             
              # Public: Normalize the web path using the PathResolver.
         | 
| @@ -480,7 +477,7 @@ class AbstractNode | |
| 480 477 | 
             
                if preserve_uri_target && (Helpers.uriish? target)
         | 
| 481 478 | 
             
                  uri_encode_spaces target
         | 
| 482 479 | 
             
                else
         | 
| 483 | 
            -
                   | 
| 480 | 
            +
                  @document.path_resolver.web_path target, start
         | 
| 484 481 | 
             
                end
         | 
| 485 482 | 
             
              end
         | 
| 486 483 |  | 
| @@ -508,7 +505,8 @@ class AbstractNode | |
| 508 505 | 
             
                    ::IO.read path
         | 
| 509 506 | 
             
                  end
         | 
| 510 507 | 
             
                elsif opts[:warn_on_failure]
         | 
| 511 | 
            -
                  warn %( | 
| 508 | 
            +
                  logger.warn %(#{(attr 'docfile') || '<stdin>'}: #{opts[:label] || 'file'} does not exist or cannot be read: #{path})
         | 
| 509 | 
            +
                  nil
         | 
| 512 510 | 
             
                end
         | 
| 513 511 | 
             
              end
         | 
| 514 512 |  | 
| @@ -531,25 +529,25 @@ class AbstractNode | |
| 531 529 | 
             
              def read_contents target, opts = {}
         | 
| 532 530 | 
             
                doc = @document
         | 
| 533 531 | 
             
                if (Helpers.uriish? target) || ((start = opts[:start]) && (Helpers.uriish? start) &&
         | 
| 534 | 
            -
                    (target =  | 
| 532 | 
            +
                    (target = doc.path_resolver.web_path target, start))
         | 
| 535 533 | 
             
                  if doc.attr? 'allow-uri-read'
         | 
| 536 534 | 
             
                    Helpers.require_library 'open-uri/cached', 'open-uri-cached' if doc.attr? 'cache-uri'
         | 
| 537 535 | 
             
                    begin
         | 
| 538 536 | 
             
                      data = ::OpenURI.open_uri(target) {|fd| fd.read }
         | 
| 539 537 | 
             
                      data = (Helpers.normalize_lines_from_string data) * LF if opts[:normalize]
         | 
| 538 | 
            +
                      return data
         | 
| 540 539 | 
             
                    rescue
         | 
| 541 | 
            -
                      warn %( | 
| 542 | 
            -
                       | 
| 540 | 
            +
                      logger.warn %(could not retrieve contents of #{opts[:label] || 'asset'} at URI: #{target}) if opts.fetch :warn_on_failure, true
         | 
| 541 | 
            +
                      return
         | 
| 543 542 | 
             
                    end
         | 
| 544 543 | 
             
                  else
         | 
| 545 | 
            -
                    warn %( | 
| 546 | 
            -
                     | 
| 544 | 
            +
                    logger.warn %(cannot retrieve contents of #{opts[:label] || 'asset'} at URI: #{target} (allow-uri-read attribute not enabled)) if opts.fetch :warn_on_failure, true
         | 
| 545 | 
            +
                    return
         | 
| 547 546 | 
             
                  end
         | 
| 548 547 | 
             
                else
         | 
| 549 548 | 
             
                  target = normalize_system_path target, opts[:start], nil, :target_name => (opts[:label] || 'asset')
         | 
| 550 | 
            -
                   | 
| 549 | 
            +
                  return read_asset target, :normalize => opts[:normalize], :warn_on_failure => (opts.fetch :warn_on_failure, true), :label => opts[:label]
         | 
| 551 550 | 
             
                end
         | 
| 552 | 
            -
                data
         | 
| 553 551 | 
             
              end
         | 
| 554 552 |  | 
| 555 553 | 
             
              # Internal: URI encode spaces in a String
         | 
    
        data/lib/asciidoctor/block.rb
    CHANGED
    
    | @@ -124,15 +124,15 @@ class Block < AbstractBlock | |
| 124 124 | 
             
                    result * LF
         | 
| 125 125 | 
             
                  end
         | 
| 126 126 | 
             
                else
         | 
| 127 | 
            -
                  warn %(Unknown content model '#{@content_model}' for block: #{to_s}) unless @content_model == :empty
         | 
| 127 | 
            +
                  logger.warn %(Unknown content model '#{@content_model}' for block: #{to_s}) unless @content_model == :empty
         | 
| 128 128 | 
             
                  nil
         | 
| 129 129 | 
             
                end
         | 
| 130 130 | 
             
              end
         | 
| 131 131 |  | 
| 132 132 | 
             
              # Public: Returns the preprocessed source of this block
         | 
| 133 133 | 
             
              #
         | 
| 134 | 
            -
              # Returns the a String containing the lines joined together or  | 
| 135 | 
            -
              # are no lines
         | 
| 134 | 
            +
              # Returns the a String containing the lines joined together or empty string
         | 
| 135 | 
            +
              # if there are no lines
         | 
| 136 136 | 
             
              def source
         | 
| 137 137 | 
             
                @lines * LF
         | 
| 138 138 | 
             
              end
         | 
    
        data/lib/asciidoctor/callouts.rb
    CHANGED
    
    | @@ -59,7 +59,7 @@ class Callouts | |
| 59 59 | 
             
              #
         | 
| 60 60 | 
             
              # Returns A space-separated String of callout ids associated with the specified list item
         | 
| 61 61 | 
             
              def callout_ids li_ordinal
         | 
| 62 | 
            -
                current_list.map {| | 
| 62 | 
            +
                current_list.map {|it| it[:ordinal] == li_ordinal ? %(#{it[:id]} ) : '' }.join.chop
         | 
| 63 63 | 
             
              end
         | 
| 64 64 |  | 
| 65 65 | 
             
              # Public: The current list for which callouts are being collected
         | 
| @@ -3,6 +3,7 @@ module Asciidoctor | |
| 3 3 | 
             
              module Cli
         | 
| 4 4 | 
             
                # Public Invocation class for starting Asciidoctor via CLI
         | 
| 5 5 | 
             
                class Invoker
         | 
| 6 | 
            +
             | 
| 6 7 | 
             
                  attr_reader :options
         | 
| 7 8 | 
             
                  attr_reader :documents
         | 
| 8 9 | 
             
                  attr_reader :code
         | 
| @@ -29,13 +30,15 @@ module Asciidoctor | |
| 29 30 | 
             
                  end
         | 
| 30 31 |  | 
| 31 32 | 
             
                  def invoke!
         | 
| 32 | 
            -
                    old_verbose = -1
         | 
| 33 33 | 
             
                    return unless @options
         | 
| 34 34 |  | 
| 35 35 | 
             
                    old_verbose = $VERBOSE
         | 
| 36 | 
            +
                    old_logger = old_logger_level = nil
         | 
| 36 37 | 
             
                    opts = {}
         | 
| 37 38 | 
             
                    infiles = []
         | 
| 38 39 | 
             
                    outfile = nil
         | 
| 40 | 
            +
                    abs_srcdir_posix = nil
         | 
| 41 | 
            +
                    non_posix_env = ::File::ALT_SEPARATOR == RS
         | 
| 39 42 | 
             
                    err = @err || $stderr
         | 
| 40 43 | 
             
                    show_timings = false
         | 
| 41 44 |  | 
| @@ -45,6 +48,11 @@ module Asciidoctor | |
| 45 48 | 
             
                        infiles = val
         | 
| 46 49 | 
             
                      when :output_file
         | 
| 47 50 | 
             
                        outfile = val
         | 
| 51 | 
            +
                      when :source_dir
         | 
| 52 | 
            +
                        if val
         | 
| 53 | 
            +
                          abs_srcdir_posix = ::File.expand_path val
         | 
| 54 | 
            +
                          abs_srcdir_posix = abs_srcdir_posix.tr RS, FS if non_posix_env && (abs_srcdir_posix.include? RS)
         | 
| 55 | 
            +
                        end
         | 
| 48 56 | 
             
                      when :destination_dir
         | 
| 49 57 | 
             
                        opts[:to_dir] = val if val
         | 
| 50 58 | 
             
                      when :attributes
         | 
| @@ -58,34 +66,36 @@ module Asciidoctor | |
| 58 66 | 
             
                        case val
         | 
| 59 67 | 
             
                        when 0
         | 
| 60 68 | 
             
                          $VERBOSE = nil
         | 
| 69 | 
            +
                          old_logger = LoggerManager.logger
         | 
| 70 | 
            +
                          LoggerManager.logger = NullLogger.new
         | 
| 61 71 | 
             
                        when 1
         | 
| 62 72 | 
             
                          $VERBOSE = false
         | 
| 63 73 | 
             
                        when 2
         | 
| 64 74 | 
             
                          $VERBOSE = true
         | 
| 75 | 
            +
                          old_logger_level, LoggerManager.logger.level = LoggerManager.logger.level, ::Logger::Severity::DEBUG
         | 
| 65 76 | 
             
                        end
         | 
| 66 77 | 
             
                      else
         | 
| 67 78 | 
             
                        opts[key] = val unless val.nil?
         | 
| 68 79 | 
             
                      end
         | 
| 69 80 | 
             
                    end
         | 
| 70 81 |  | 
| 71 | 
            -
                     | 
| 82 | 
            +
                    if infiles.size == 1
         | 
| 72 83 | 
             
                      if (infile0 = infiles[0]) == '-'
         | 
| 73 84 | 
             
                        outfile ||= infile0
         | 
| 74 | 
            -
                        true
         | 
| 85 | 
            +
                        stdin = true
         | 
| 75 86 | 
             
                      elsif ::File.pipe? infile0
         | 
| 76 87 | 
             
                        outfile ||= '-'
         | 
| 77 | 
            -
                        nil
         | 
| 78 88 | 
             
                      end
         | 
| 79 89 | 
             
                    end
         | 
| 80 90 |  | 
| 81 | 
            -
                     | 
| 82 | 
            -
                      @out || $stdout
         | 
| 91 | 
            +
                    if outfile == '-'
         | 
| 92 | 
            +
                      tofile = @out || $stdout
         | 
| 83 93 | 
             
                    elsif outfile
         | 
| 84 94 | 
             
                      opts[:mkdirs] = true
         | 
| 85 | 
            -
                      outfile
         | 
| 95 | 
            +
                      tofile = outfile
         | 
| 86 96 | 
             
                    else
         | 
| 87 97 | 
             
                      opts[:mkdirs] = true
         | 
| 88 | 
            -
                       | 
| 98 | 
            +
                      # automatically calculate outfile based on infile
         | 
| 89 99 | 
             
                    end
         | 
| 90 100 |  | 
| 91 101 | 
             
                    if stdin
         | 
| @@ -101,6 +111,17 @@ module Asciidoctor | |
| 101 111 | 
             
                    else
         | 
| 102 112 | 
             
                      infiles.each do |infile|
         | 
| 103 113 | 
             
                        input_opts = opts.merge :to_file => tofile
         | 
| 114 | 
            +
                        if abs_srcdir_posix && (input_opts.key? :to_dir)
         | 
| 115 | 
            +
                          abs_indir = ::File.dirname ::File.expand_path infile
         | 
| 116 | 
            +
                          if non_posix_env
         | 
| 117 | 
            +
                            abs_indir_posix = (abs_indir.include? RS) ? (abs_indir.tr RS, FS) : abs_indir
         | 
| 118 | 
            +
                          else
         | 
| 119 | 
            +
                            abs_indir_posix = abs_indir
         | 
| 120 | 
            +
                          end
         | 
| 121 | 
            +
                          if abs_indir_posix.start_with? %(#{abs_srcdir_posix}/)
         | 
| 122 | 
            +
                            input_opts[:to_dir] += abs_indir.slice abs_srcdir_posix.length, abs_indir.length
         | 
| 123 | 
            +
                          end
         | 
| 124 | 
            +
                        end
         | 
| 104 125 | 
             
                        if show_timings
         | 
| 105 126 | 
             
                          @documents << (::Asciidoctor.convert_file infile, (input_opts.merge :timings => (timings = Timings.new)))
         | 
| 106 127 | 
             
                          timings.print_report err, infile
         | 
| @@ -109,6 +130,7 @@ module Asciidoctor | |
| 109 130 | 
             
                        end
         | 
| 110 131 | 
             
                      end
         | 
| 111 132 | 
             
                    end
         | 
| 133 | 
            +
                    @code = 1 if ((logger = LoggerManager.logger).respond_to? :max_severity) && logger.max_severity && logger.max_severity >= opts[:failure_level]
         | 
| 112 134 | 
             
                  rescue ::Exception => e
         | 
| 113 135 | 
             
                    if ::SignalException === e
         | 
| 114 136 | 
             
                      @code = e.signo
         | 
| @@ -129,7 +151,12 @@ module Asciidoctor | |
| 129 151 | 
             
                    end
         | 
| 130 152 | 
             
                    nil
         | 
| 131 153 | 
             
                  ensure
         | 
| 132 | 
            -
                    $VERBOSE = old_verbose | 
| 154 | 
            +
                    $VERBOSE = old_verbose
         | 
| 155 | 
            +
                    if old_logger
         | 
| 156 | 
            +
                      LoggerManager.logger = old_logger
         | 
| 157 | 
            +
                    elsif old_logger_level
         | 
| 158 | 
            +
                      LoggerManager.logger.level = old_logger_level
         | 
| 159 | 
            +
                    end
         | 
| 133 160 | 
             
                  end
         | 
| 134 161 |  | 
| 135 162 | 
             
                  def document
         | 
| @@ -1,6 +1,8 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 | 
             
            module Asciidoctor
         | 
| 3 3 | 
             
              module Cli
         | 
| 4 | 
            +
                FS = '/'
         | 
| 5 | 
            +
                RS = '\\'
         | 
| 4 6 |  | 
| 5 7 | 
             
                # Public: List of options that can be specified on the command line
         | 
| 6 8 | 
             
                class Options < ::Hash
         | 
| @@ -24,7 +26,9 @@ module Asciidoctor | |
| 24 26 | 
             
                    self[:load_paths] = options[:load_paths] || nil
         | 
| 25 27 | 
             
                    self[:requires] = options[:requires] || nil
         | 
| 26 28 | 
             
                    self[:base_dir] = options[:base_dir]
         | 
| 29 | 
            +
                    self[:source_dir] = options[:source_dir] || nil
         | 
| 27 30 | 
             
                    self[:destination_dir] = options[:destination_dir] || nil
         | 
| 31 | 
            +
                    self[:failure_level] = ::Logger::Severity::FATAL
         | 
| 28 32 | 
             
                    self[:trace] = false
         | 
| 29 33 | 
             
                    self[:timings] = false
         | 
| 30 34 | 
             
                  end
         | 
| @@ -75,8 +79,6 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 75 79 | 
             
                              'specify eRuby implementation to use when rendering custom ERB templates: [erb, erubis] (default: erb)') do |eruby|
         | 
| 76 80 | 
             
                        self[:eruby] = eruby
         | 
| 77 81 | 
             
                      end
         | 
| 78 | 
            -
                      opts.on('-C', '--compact', 'compact the output by removing blank lines. (No longer in use)') do
         | 
| 79 | 
            -
                      end
         | 
| 80 82 | 
             
                      opts.on('-a', '--attribute key[=value]', 'a document attribute to set in the form of key, key! or key=value pair',
         | 
| 81 83 | 
             
                              'unless @ is appended to the value, this attributes takes precedence over attributes',
         | 
| 82 84 | 
             
                              'defined in the source document') do |attr|
         | 
| @@ -104,6 +106,9 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 104 106 | 
             
                      opts.on('-B', '--base-dir DIR', 'base directory containing the document and resources (default: directory of source file)') do |base_dir|
         | 
| 105 107 | 
             
                        self[:base_dir] = base_dir
         | 
| 106 108 | 
             
                      end
         | 
| 109 | 
            +
                      opts.on('-R', '--source-dir DIR', 'source root directory (used for calculating path in destination directory)') do |src_dir|
         | 
| 110 | 
            +
                        self[:source_dir] = src_dir
         | 
| 111 | 
            +
                      end
         | 
| 107 112 | 
             
                      opts.on('-D', '--destination-dir DIR', 'destination output directory (default: directory of source file)') do |dest_dir|
         | 
| 108 113 | 
             
                        self[:destination_dir] = dest_dir
         | 
| 109 114 | 
             
                      end
         | 
| @@ -115,6 +120,10 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 115 120 | 
             
                          'may be specified more than once') do |path|
         | 
| 116 121 | 
             
                        (self[:requires] ||= []).concat(path.split ',')
         | 
| 117 122 | 
             
                      end
         | 
| 123 | 
            +
                      opts.on('--failure-level LEVEL', %w(warning WARNING error ERROR), 'set minimum logging level that triggers a non-zero exit code: [WARN, ERROR] (default: FATAL)') do |level|
         | 
| 124 | 
            +
                        level = 'WARN' if (level = level.upcase) == 'WARNING'
         | 
| 125 | 
            +
                        self[:failure_level] = ::Logger::Severity.const_get level
         | 
| 126 | 
            +
                      end
         | 
| 118 127 | 
             
                      opts.on('-q', '--quiet', 'suppress warnings (default: false)') do |verbose|
         | 
| 119 128 | 
             
                        self[:verbose] = 0
         | 
| 120 129 | 
             
                      end
         | 
| @@ -132,11 +141,32 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 132 141 | 
             
                          'show the command usage if TOPIC is not specified (or not recognized)',
         | 
| 133 142 | 
             
                          'dump the Asciidoctor man page (in troff/groff format) if TOPIC is manpage') do |topic|
         | 
| 134 143 | 
             
                        if topic == 'manpage'
         | 
| 135 | 
            -
                          if  | 
| 136 | 
            -
                             | 
| 144 | 
            +
                          if (manpage_path = ENV['ASCIIDOCTOR_MANPAGE_PATH'])
         | 
| 145 | 
            +
                            if ::File.exist? manpage_path
         | 
| 146 | 
            +
                              if manpage_path.end_with? '.gz'
         | 
| 147 | 
            +
                                require 'zlib' unless defined? ::Zlib::GzipReader
         | 
| 148 | 
            +
                                $stdout.puts ::Zlib::GzipReader.open(manpage_path) {|gz| gz.read }
         | 
| 149 | 
            +
                              else
         | 
| 150 | 
            +
                                $stdout.puts ::IO.read manpage_path
         | 
| 151 | 
            +
                              end
         | 
| 152 | 
            +
                            else
         | 
| 153 | 
            +
                              $stderr.puts %(asciidoctor: FAILED: manual page not found: #{manpage_path})
         | 
| 154 | 
            +
                              return 1
         | 
| 155 | 
            +
                            end
         | 
| 156 | 
            +
                          elsif ::File.exist?(manpage_path = (::File.join ::Asciidoctor::ROOT_PATH, 'man', 'asciidoctor.1'))
         | 
| 157 | 
            +
                            $stdout.puts ::IO.read manpage_path
         | 
| 137 158 | 
             
                          else
         | 
| 138 | 
            -
                             | 
| 139 | 
            -
                             | 
| 159 | 
            +
                            require 'open3' unless defined? ::Open3.popen3
         | 
| 160 | 
            +
                            manpage_path = ::Open3.popen3('man -w asciidoctor') {|_, out| out.read }.chop rescue ''
         | 
| 161 | 
            +
                            if manpage_path.empty?
         | 
| 162 | 
            +
                              $stderr.puts 'asciidoctor: FAILED: manual page not found; try `man asciidoctor`'
         | 
| 163 | 
            +
                              return 1
         | 
| 164 | 
            +
                            elsif manpage_path.end_with? '.gz'
         | 
| 165 | 
            +
                              require 'zlib' unless defined? ::Zlib::GzipReader
         | 
| 166 | 
            +
                              $stdout.puts ::Zlib::GzipReader.open(manpage_path) {|gz| gz.read }
         | 
| 167 | 
            +
                            else
         | 
| 168 | 
            +
                              $stdout.puts ::IO.read manpage_path
         | 
| 169 | 
            +
                            end
         | 
| 140 170 | 
             
                          end
         | 
| 141 171 | 
             
                        else
         | 
| 142 172 | 
             
                          $stdout.puts opts
         | 
| @@ -171,31 +201,39 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 171 201 | 
             
                          # warn, but don't panic; we may have enough to proceed, so we won't force a failure
         | 
| 172 202 | 
             
                          $stderr.puts %(asciidoctor: WARNING: extra arguments detected (unparsed arguments: '#{args * "', '"}') or incorrect usage of stdin)
         | 
| 173 203 | 
             
                        else
         | 
| 174 | 
            -
                          if ::File. | 
| 175 | 
            -
                             | 
| 204 | 
            +
                          if ::File.file? file
         | 
| 205 | 
            +
                            infiles << file
         | 
| 206 | 
            +
                          # NOTE only attempt to glob if file is not found
         | 
| 176 207 | 
             
                          else
         | 
| 177 208 | 
             
                            # Tilt backslashes in Windows paths the Ruby-friendly way
         | 
| 178 | 
            -
                            if ::File::ALT_SEPARATOR ==  | 
| 179 | 
            -
                              file = file.tr  | 
| 209 | 
            +
                            if ::File::ALT_SEPARATOR == RS && (file.include? RS)
         | 
| 210 | 
            +
                              file = file.tr RS, FS
         | 
| 180 211 | 
             
                            end
         | 
| 181 212 | 
             
                            if (matches = ::Dir.glob file).empty?
         | 
| 182 | 
            -
                               | 
| 183 | 
            -
                               | 
| 213 | 
            +
                              # NOTE if no matches, assume it's just a missing file and proceed
         | 
| 214 | 
            +
                              infiles << file
         | 
| 215 | 
            +
                            else
         | 
| 216 | 
            +
                              infiles.concat matches
         | 
| 184 217 | 
             
                            end
         | 
| 185 218 | 
             
                          end
         | 
| 186 | 
            -
             | 
| 187 | 
            -
                          infiles.concat matches
         | 
| 188 219 | 
             
                        end
         | 
| 189 220 | 
             
                      end
         | 
| 190 221 | 
             
                    end
         | 
| 191 222 |  | 
| 192 | 
            -
                    infiles.each do |file|
         | 
| 193 | 
            -
                       | 
| 194 | 
            -
                         | 
| 195 | 
            -
             | 
| 223 | 
            +
                    infiles.reject {|file| file == '-' }.each do |file|
         | 
| 224 | 
            +
                      begin
         | 
| 225 | 
            +
                        fstat = ::File.stat file
         | 
| 226 | 
            +
                        if fstat.file? || fstat.pipe?
         | 
| 227 | 
            +
                          unless fstat.readable?
         | 
| 228 | 
            +
                            $stderr.puts %(asciidoctor: FAILED: input file #{file} is not readable)
         | 
| 229 | 
            +
                            return 1
         | 
| 230 | 
            +
                          end
         | 
| 196 231 | 
             
                        else
         | 
| 197 | 
            -
                          $stderr.puts %(asciidoctor: FAILED: input  | 
| 232 | 
            +
                          $stderr.puts %(asciidoctor: FAILED: input path #{file} is a #{fstat.ftype}, not a file)
         | 
| 233 | 
            +
                          return 1
         | 
| 198 234 | 
             
                        end
         | 
| 235 | 
            +
                      rescue ::Errno::ENOENT
         | 
| 236 | 
            +
                        $stderr.puts %(asciidoctor: FAILED: input file #{file} is missing)
         | 
| 199 237 | 
             
                        return 1
         | 
| 200 238 | 
             
                      end
         | 
| 201 239 | 
             
                    end
         | 
| @@ -206,7 +244,7 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 206 244 |  | 
| 207 245 | 
             
                    if self[:template_dirs]
         | 
| 208 246 | 
             
                      begin
         | 
| 209 | 
            -
                        require 'tilt' unless defined? ::Tilt
         | 
| 247 | 
            +
                        require 'tilt' unless defined? ::Tilt::VERSION
         | 
| 210 248 | 
             
                      rescue ::LoadError
         | 
| 211 249 | 
             
                        raise $! if self[:trace]
         | 
| 212 250 | 
             
                        $stderr.puts 'asciidoctor: FAILED: \'tilt\' could not be loaded'
         | 
| @@ -220,7 +258,7 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 220 258 |  | 
| 221 259 | 
             
                    if (load_paths = self[:load_paths])
         | 
| 222 260 | 
             
                      (self[:load_paths] = load_paths.uniq).reverse_each do |path|
         | 
| 223 | 
            -
                        $:.unshift File.expand_path(path)
         | 
| 261 | 
            +
                        $:.unshift ::File.expand_path(path)
         | 
| 224 262 | 
             
                      end
         | 
| 225 263 | 
             
                    end
         | 
| 226 264 |  | 
| @@ -251,10 +289,10 @@ Example: asciidoctor -b html5 source.asciidoc | |
| 251 289 | 
             
                  end
         | 
| 252 290 |  | 
| 253 291 | 
             
                  def print_version os = $stdout
         | 
| 254 | 
            -
                    os.puts %(Asciidoctor #{::Asciidoctor::VERSION} [ | 
| 255 | 
            -
                    if  | 
| 256 | 
            -
                      encoding_info = {'lc' => 'locale', 'fs' => 'filesystem', 'in' => 'internal', 'ex' => 'external'}.map do |k,v|
         | 
| 257 | 
            -
                        %(#{k}:#{:: | 
| 292 | 
            +
                    os.puts %(Asciidoctor #{::Asciidoctor::VERSION} [https://asciidoctor.org])
         | 
| 293 | 
            +
                    if RUBY_MIN_VERSION_1_9
         | 
| 294 | 
            +
                      encoding_info = { 'lc' => 'locale', 'fs' => 'filesystem', 'in' => 'internal', 'ex' => 'external' }.map do |k, v|
         | 
| 295 | 
            +
                        %(#{k}:#{v == 'internal' ? (::File.open(__FILE__) {|f| f.getc }).encoding : (::Encoding.find v)})
         | 
| 258 296 | 
             
                      end
         | 
| 259 297 | 
             
                      os.puts %(Runtime Environment (#{RUBY_DESCRIPTION}) (#{encoding_info * ' '}))
         | 
| 260 298 | 
             
                    else
         |