lib/asciidoctor/abstract_node.rb in asciidoctor-1.5.6.1 vs lib/asciidoctor/abstract_node.rb in asciidoctor-1.5.6.2

- old
+ new

@@ -50,23 +50,29 @@ def parent=(parent) @parent, @document = parent, parent.document nil end - # Public: Returns whether this {AbstractNode} is an instance of {Inline} + # Public: Get the Asciidoctor::Converter instance being used to convert the + # current Asciidoctor::Document. + def converter + @document.converter + end + + # Public: Returns whether this {AbstractNode} is an instance of {Block} # # Returns [Boolean] - def inline? + def block? # :nocov: raise ::NotImplementedError # :nocov: end - # Public: Returns whether this {AbstractNode} is an instance of {Block} + # Public: Returns whether this {AbstractNode} is an instance of {Inline} # # Returns [Boolean] - def block? + def inline? # :nocov: raise ::NotImplementedError # :nocov: end @@ -142,20 +148,10 @@ # Returns the previous [String] value, or nil if the attribute was not present. def remove_attr name @attributes.delete name end - # TODO document me - def set_option(name) - if @attributes.key? 'options' - @attributes['options'] = %(#{@attributes['options']},#{name}) - else - @attributes['options'] = name - end - @attributes[%(#{name}-option)] = '' - end - # Public: A convenience method to check if the specified option attribute is # enabled on the current node. # # Check if the option is enabled. This method simply checks to see if the # %name%-option attribute is defined on the current node. @@ -165,10 +161,20 @@ # return a Boolean indicating whether the option has been specified def option?(name) @attributes.key? %(#{name}-option) end + # TODO document me + def set_option(name) + if @attributes.key? 'options' + @attributes['options'] = %(#{@attributes['options']},#{name}) + else + @attributes['options'] = name + end + @attributes[%(#{name}-option)] = '' + end + # Public: Update the attributes of this node with the new values in # the attributes argument. # # If an attribute already exists with the same key, it's value will # be overridden. @@ -179,44 +185,38 @@ def update_attributes(attributes) @attributes.update(attributes) nil end - # Public: Get the Asciidoctor::Converter instance being used to convert the - # current Asciidoctor::Document. - def converter - @document.converter + # Public: A convenience method that returns the value of the role attribute + def role + @attributes['role'] || @document.attributes['role'] end + # Public: A convenience method that returns the role names as an Array + # + # Returns the role names as an Array or an empty Array if the role attribute is absent. + def roles + (val = @attributes['role'] || @document.attributes['role']).nil_or_empty? ? [] : val.split + end + # Public: A convenience method that checks if the role attribute is specified def role? expect_val = nil if expect_val expect_val == (@attributes['role'] || @document.attributes['role']) else @attributes.key?('role') || @document.attributes.key?('role') end end - # Public: A convenience method that returns the value of the role attribute - def role - @attributes['role'] || @document.attributes['role'] - end - # Public: A convenience method that checks if the specified role is present # in the list of roles on this node def has_role?(name) # NOTE center + include? is faster than split + include? (val = @attributes['role'] || @document.attributes['role']).nil_or_empty? ? false : %( #{val} ).include?(%( #{name} )) end - # Public: A convenience method that returns the role names as an Array - # - # Returns the role names as an Array or an empty Array if the role attribute is absent. - def roles - (val = @attributes['role'] || @document.attributes['role']).nil_or_empty? ? [] : val.split - end - # Public: A convenience method that adds the given role directly to this node # # Returns a Boolean indicating whether the role was added. def add_role(name) if (val = @attributes['role']).nil_or_empty? @@ -247,20 +247,20 @@ else false end end - # Public: A convenience method that checks if the reftext attribute is defined. - def reftext? - @attributes.key? 'reftext' - end - # Public: A convenience method that returns the value of the reftext attribute with substitutions applied. def reftext (val = @attributes['reftext']) ? (apply_reftext_subs val) : nil end + # Public: A convenience method that checks if the reftext attribute is defined. + def reftext? + @attributes.key? 'reftext' + end + # Public: Construct a reference or data URI to an icon image for the # specified icon name. # # If the 'icon' attribute is set on this block, the name is ignored and the # value of this attribute is used as the target image path. Otherwise, @@ -288,28 +288,10 @@ else image_uri %(#{name}.#{@document.attr 'icontype', 'png'}), 'iconsdir' end end - # Public: Construct a URI reference to the target media. - # - # If the target media is a URI reference, then leave it untouched. - # - # The target media is resolved relative to the directory retrieved from the - # specified attribute key, if provided. - # - # The return value can be safely used in a media tag (img, audio, video). - # - # target - A String reference to the target media - # asset_dir_key - The String attribute key used to lookup the directory where - # the media is located (default: 'imagesdir') - # - # Returns A String reference for the target media - def media_uri(target, asset_dir_key = 'imagesdir') - normalize_web_path target, (asset_dir_key ? @document.attr(asset_dir_key) : nil) - end - # Public: Construct a URI reference or data URI to the target image. # # If the target image is a URI reference, then leave it untouched. # # The target image is resolved relative to the directory retrieved from the @@ -343,10 +325,28 @@ else normalize_web_path target_image, (asset_dir_key ? (doc.attr asset_dir_key) : nil) end end + # Public: Construct a URI reference to the target media. + # + # If the target media is a URI reference, then leave it untouched. + # + # The target media is resolved relative to the directory retrieved from the + # specified attribute key, if provided. + # + # The return value can be safely used in a media tag (img, audio, video). + # + # target - A String reference to the target media + # asset_dir_key - The String attribute key used to lookup the directory where + # the media is located (default: 'imagesdir') + # + # Returns A String reference for the target media + def media_uri(target, asset_dir_key = 'imagesdir') + normalize_web_path target, (asset_dir_key ? @document.attr(asset_dir_key) : nil) + end + # Public: Generate a data URI that can be used to embed an image in the output document # # First, and foremost, the target image path is cleaned if the document safe mode level # is set to at least SafeMode::SAFE (a condition which is true by default) to prevent access # to ancestor paths in the filesystem. The image data is then read and converted to @@ -416,50 +416,76 @@ # uncomment to return 1 pixel white dot instead #'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' end end - # Public: Resolve the URI or system path to the specified target, then read and return its contents + # Public: Normalize the asset file or directory to a concrete and rinsed path # - # The URI or system path of the target is first resolved. If the resolved path is a URI, read the - # contents from the URI if the allow-uri-read attribute is set, enabling caching if the cache-uri - # attribute is also set. If the resolved path is not a URI, read the contents of the file from the - # file system. If the normalize option is set, the data will be normalized. + # Delegates to normalize_system_path, with the start path set to the value of + # the base_dir instance variable on the Document object. + def normalize_asset_path(asset_ref, asset_name = 'path', autocorrect = true) + normalize_system_path(asset_ref, @document.base_dir, nil, + :target_name => asset_name, :recover => autocorrect) + end + + # Public: Resolve and normalize a secure path from the target and start paths + # using the PathResolver. # - # target - The URI or local path from which to read the data. - # opts - a Hash of options to control processing (default: {}) - # * :label the String label of the target to use in warning messages (default: 'asset') - # * :normalize a Boolean that indicates whether the data should be normalized (default: false) - # * :start the String relative base path to use when resolving the target (default: nil) - # * :warn_on_failure a Boolean that indicates whether warnings are issued if the target cannot be read (default: true) - # Returns the contents of the resolved target or nil if the resolved target cannot be read - # -- - # TODO refactor other methods in this class to use this method were possible (repurposing if necessary) - def read_contents target, opts = {} - doc = @document - if (Helpers.uriish? target) || ((start = opts[:start]) && (Helpers.uriish? start) && - (target = (@path_resolver ||= PathResolver.new).web_path target, start)) - if doc.attr? 'allow-uri-read' - Helpers.require_library 'open-uri/cached', 'open-uri-cached' if doc.attr? 'cache-uri' - begin - data = ::OpenURI.open_uri(target) {|fd| fd.read } - data = (Helpers.normalize_lines_from_string data) * LF if opts[:normalize] - rescue - warn %(asciidoctor: WARNING: could not retrieve contents of #{opts[:label] || 'asset'} at URI: #{target}) if opts.fetch :warn_on_failure, true - data = nil - end + # See {PathResolver#system_path} for details. + # + # The most important functionality in this method is to prevent resolving a + # path outside of the jail (which defaults to the directory of the source + # file, stored in the base_dir instance variable on Document) if the document + # safe level is set to SafeMode::SAFE or greater (a condition which is true + # by default). + # + # target - the String target path + # start - the String start (i.e., parent) path + # jail - the String jail path to confine the resolved path + # opts - an optional Hash of options to control processing (default: {}): + # * :recover is used to control whether the processor should auto-recover + # when an illegal path is encountered + # * :target_name is used in messages to refer to the path being resolved + # + # raises a SecurityError if a jail is specified and the resolved path is + # outside the jail. + # + # Returns the [String] path resolved from the start and target paths, with any + # parent references resolved and self references removed. If a jail is provided, + # this path will be guaranteed to be contained within the jail. + def normalize_system_path target, start = nil, jail = nil, opts = {} + path_resolver = (@path_resolver ||= PathResolver.new) + if (doc = @document).safe < SafeMode::SAFE + if start + start = ::File.join doc.base_dir, start unless path_resolver.root? start else - warn %(asciidoctor: WARNING: cannot retrieve contents of #{opts[:label] || 'asset'} at URI: #{target} (allow-uri-read attribute not enabled)) if opts.fetch :warn_on_failure, true - data = nil + start = doc.base_dir end else - target = normalize_system_path target, opts[:start], nil, :target_name => (opts[:label] || 'asset') - data = read_asset target, :normalize => opts[:normalize], :warn_on_failure => (opts.fetch :warn_on_failure, true), :label => opts[:label] + start = doc.base_dir unless start + jail = doc.base_dir unless jail end - data + path_resolver.system_path target, start, jail, opts end + # Public: Normalize the web path using the PathResolver. + # + # See {PathResolver#web_path} for details about path resolution and encoding. + # + # target - the String target path + # start - the String start (i.e, parent) path (optional, default: nil) + # preserve_uri_target - a Boolean indicating whether target should be preserved if contains a URI (default: true) + # + # Returns the resolved [String] path + def normalize_web_path(target, start = nil, preserve_uri_target = true) + if preserve_uri_target && (Helpers.uriish? target) + uri_encode_spaces target + else + (@path_resolver ||= PathResolver.new).web_path target, start + end + end + # Public: Read the contents of the file at the specified path. # This method assumes that the path is safe to read. It checks # that the file is readable before attempting to read it. # # path - the String path from which to read the contents @@ -484,82 +510,56 @@ elsif opts[:warn_on_failure] warn %(asciidoctor: WARNING: #{(attr 'docfile') || '<stdin>'}: #{opts[:label] || 'file'} does not exist or cannot be read: #{path}) end end - # Public: Normalize the web path using the PathResolver. + # Public: Resolve the URI or system path to the specified target, then read and return its contents # - # See {PathResolver#web_path} for details about path resolution and encoding. + # The URI or system path of the target is first resolved. If the resolved path is a URI, read the + # contents from the URI if the allow-uri-read attribute is set, enabling caching if the cache-uri + # attribute is also set. If the resolved path is not a URI, read the contents of the file from the + # file system. If the normalize option is set, the data will be normalized. # - # target - the String target path - # start - the String start (i.e, parent) path (optional, default: nil) - # preserve_uri_target - a Boolean indicating whether target should be preserved if contains a URI (default: true) - # - # Returns the resolved [String] path - def normalize_web_path(target, start = nil, preserve_uri_target = true) - if preserve_uri_target && (Helpers.uriish? target) - uri_encode_spaces target + # target - The URI or local path from which to read the data. + # opts - a Hash of options to control processing (default: {}) + # * :label the String label of the target to use in warning messages (default: 'asset') + # * :normalize a Boolean that indicates whether the data should be normalized (default: false) + # * :start the String relative base path to use when resolving the target (default: nil) + # * :warn_on_failure a Boolean that indicates whether warnings are issued if the target cannot be read (default: true) + # Returns the contents of the resolved target or nil if the resolved target cannot be read + # -- + # TODO refactor other methods in this class to use this method were possible (repurposing if necessary) + def read_contents target, opts = {} + doc = @document + if (Helpers.uriish? target) || ((start = opts[:start]) && (Helpers.uriish? start) && + (target = (@path_resolver ||= PathResolver.new).web_path target, start)) + if doc.attr? 'allow-uri-read' + Helpers.require_library 'open-uri/cached', 'open-uri-cached' if doc.attr? 'cache-uri' + begin + data = ::OpenURI.open_uri(target) {|fd| fd.read } + data = (Helpers.normalize_lines_from_string data) * LF if opts[:normalize] + rescue + warn %(asciidoctor: WARNING: could not retrieve contents of #{opts[:label] || 'asset'} at URI: #{target}) if opts.fetch :warn_on_failure, true + data = nil + end + else + warn %(asciidoctor: WARNING: cannot retrieve contents of #{opts[:label] || 'asset'} at URI: #{target} (allow-uri-read attribute not enabled)) if opts.fetch :warn_on_failure, true + data = nil + end else - (@path_resolver ||= PathResolver.new).web_path target, start + target = normalize_system_path target, opts[:start], nil, :target_name => (opts[:label] || 'asset') + data = read_asset target, :normalize => opts[:normalize], :warn_on_failure => (opts.fetch :warn_on_failure, true), :label => opts[:label] end + data end # Internal: URI encode spaces in a String # # str - the String to encode # # Returns the String with all spaces replaced with %20. def uri_encode_spaces str (str.include? ' ') ? (str.gsub ' ', '%20') : str - end - - # Public: Resolve and normalize a secure path from the target and start paths - # using the PathResolver. - # - # See {PathResolver#system_path} for details. - # - # The most important functionality in this method is to prevent resolving a - # path outside of the jail (which defaults to the directory of the source - # file, stored in the base_dir instance variable on Document) if the document - # safe level is set to SafeMode::SAFE or greater (a condition which is true - # by default). - # - # target - the String target path - # start - the String start (i.e., parent) path - # jail - the String jail path to confine the resolved path - # opts - an optional Hash of options to control processing (default: {}): - # * :recover is used to control whether the processor should auto-recover - # when an illegal path is encountered - # * :target_name is used in messages to refer to the path being resolved - # - # raises a SecurityError if a jail is specified and the resolved path is - # outside the jail. - # - # Returns the [String] path resolved from the start and target paths, with any - # parent references resolved and self references removed. If a jail is provided, - # this path will be guaranteed to be contained within the jail. - def normalize_system_path target, start = nil, jail = nil, opts = {} - path_resolver = (@path_resolver ||= PathResolver.new) - if (doc = @document).safe < SafeMode::SAFE - if start - start = ::File.join doc.base_dir, start unless path_resolver.is_root? start - else - start = doc.base_dir - end - else - start = doc.base_dir unless start - jail = doc.base_dir unless jail - end - path_resolver.system_path target, start, jail, opts - end - - # Public: Normalize the asset file or directory to a concrete and rinsed path - # - # Delegates to normalize_system_path, with the start path set to the value of - # the base_dir instance variable on the Document object. - def normalize_asset_path(asset_ref, asset_name = 'path', autocorrect = true) - normalize_system_path(asset_ref, @document.base_dir, nil, - :target_name => asset_name, :recover => autocorrect) end # Public: Check whether the specified String is a URI by # matching it against the Asciidoctor::UriSniffRx regex. #