class Asciidoctor::AbstractNode

all content segments in an AsciiDoc document.
node of AsciiDoc content. The state and methods on this class are common to
Public: An abstract base class that provides state and methods for managing a

def add_role name

Returns a [Boolean] indicating whether the role was added.

Public: Adds the given role directly to this node.
def add_role name
  if (val = @attributes['role'])
    # NOTE center + include? is faster than split + include?
    if %( #{val} ).include? %( #{name} )
      false
    else
      @attributes['role'] = %(#{val} #{name})
      true
    end
  else
    @attributes['role'] = name
    true
  end
end

def attr name, default_value = nil, fallback_name = nil

Returns the [Object] value (typically a String) of the attribute or default_value if the attribute is not found.

this node (default: same as name).
fallback_name - The String or Symbol of the attribute to resolve on the Document if the attribute is not found on
default_value - The Object value to return if the attribute is not found (default: nil).
name - The String or Symbol name of the attribute to resolve.

attribute on the Document node and return its value, if found. Otherwise, return the default value (default: nil).
Otherwise, if fallback_name is set (default: same as name) and this node is not the Document node, look for that
Look for the specified attribute in the attributes on this node and return the value of the attribute, if found.

and this node is not the Document node, get the value of the specified attribute from the Document node.
Public: Get the value of the specified attribute. If the attribute is not found on this node, fallback_name is set,
def attr name, default_value = nil, fallback_name = nil
  @attributes[name.to_s] || (fallback_name && @parent && @document.attributes[(fallback_name == true ? name : fallback_name).to_s] || default_value)
end

def attr? name, expected_value = nil, fallback_name = nil

the value of the attribute matches the comparison value.
Returns a [Boolean] indicating whether the attribute exists and, if a truthy comparison value is specified, whether

this node (default: same as name).
fallback_name - The String or Symbol of the attribute to resolve on the Document if the attribute is not found on
expected_value - The expected Object value of the attribute (default: nil).
name - The String or Symbol name of the attribute to resolve.

return whether the attribute was found.
if the attribute is found, and the comparison value is truthy, return whether the two values match. Otherwise,
same as name), and this node is not the Document node, look for that attribute on the Document node. In either case,
Look for the specified attribute in the attributes on this node. If not found, fallback_name is specified (default:

comparison with the expected value if specified.
Public: Check if the specified attribute is defined using the same logic as {#attr}, optionally performing a
def attr? name, expected_value = nil, fallback_name = nil
  if expected_value
    expected_value == (@attributes[name.to_s] || (fallback_name && @parent ? @document.attributes[(fallback_name == true ? name : fallback_name).to_s] : nil))
  else
    (@attributes.key? name.to_s) || (fallback_name && @parent ? (@document.attributes.key? (fallback_name == true ? name : fallback_name).to_s) : false)
  end
end

def block?

Returns [Boolean]

Public: Returns whether this {AbstractNode} is an instance of {Block}
def block?
  # :nocov:
  raise ::NotImplementedError
  # :nocov:
end

def converter

current Asciidoctor::Document.
Public: Get the Asciidoctor::Converter instance being used to convert the
def converter
  @document.converter
end

def generate_data_uri(target_image, asset_dir_key = nil)

Returns A String data URI containing the content of the target image

the image is located (default: nil)
asset_dir_key - The String attribute key used to lookup the directory where
target_image - A String path to the target image

Base64. Finally, a data URI is built which can be used in an image tag.
to ancestor paths in the filesystem. The image data is then read and converted to
is set to at least SafeMode::SAFE (a condition which is true by default) to prevent access
First, and foremost, the target image path is cleaned if the document safe mode level

Public: Generate a data URI that can be used to embed an image in the output document
def generate_data_uri(target_image, asset_dir_key = nil)
  ext = ::File.extname target_image
  # QUESTION what if ext is empty?
  mimetype = (ext == '.svg' ? 'image/svg+xml' : %(image/#{ext.slice 1, ext.length}))
  if asset_dir_key
    image_path = normalize_system_path(target_image, @document.attr(asset_dir_key), nil, target_name: 'image')
  else
    image_path = normalize_system_path(target_image)
  end
  if ::File.readable? image_path
    # NOTE base64 is autoloaded by reference to ::Base64
    %(data:#{mimetype};base64,#{::Base64.strict_encode64 ::File.binread image_path})
  else
    logger.warn %(image to embed not found or not readable: #{image_path})
    %(data:#{mimetype};base64,)
    # uncomment to return 1 pixel white dot instead
    #'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
  end
end

def generate_data_uri_from_uri image_uri, cache_uri = false

and the mime type specified in the Content Type header.
Returns A data URI string built from Base64 encoded data read from the URI

is used to cache the image for subsequent reads. (default: false)
cache_uri - A Boolean to control caching. When true, the open-uri-cached library
image_uri - The URI from which to read the image data. Can be http://, https:// or ftp://

which can then be used in an image tag.
constructed from the content_type header and Base64 data and returned,
The image data is read from the URI and converted to Base64. A data URI is

Public: Read the image data from the specified URI and generate a data URI
def generate_data_uri_from_uri image_uri, cache_uri = false
  if cache_uri
    # caching requires the open-uri-cached gem to be installed
    # processing will be automatically aborted if these libraries can't be opened
    Helpers.require_library 'open-uri/cached', 'open-uri-cached'
  elsif !RUBY_ENGINE_OPAL
    # autoload open-uri
    ::OpenURI
  end
  begin
    mimetype, bindata = ::OpenURI.open_uri(image_uri, URI_READ_MODE) {|f| [f.content_type, f.read] }
    # NOTE base64 is autoloaded by reference to ::Base64
    %(data:#{mimetype};base64,#{::Base64.strict_encode64 bindata})
  rescue
    logger.warn %(could not retrieve image data from URI: #{image_uri})
    image_uri
    # uncomment to return empty data (however, mimetype needs to be resolved)
    #%(data:#{mimetype}:base64,)
    # uncomment to return 1 pixel white dot instead
    #'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
  end
end

def has_role? name

Returns a [Boolean] indicating whether this node has the specified role.

name - The String name of the role to find.

Public: Checks if the specified role is present in the list of roles for this node.
def has_role? name
  # NOTE center + include? is faster than split + include?
  (val = @attributes['role']) ? (%( #{val} ).include? %( #{name} )) : false
end

def icon_uri name

Returns A String reference or data URI for an icon image

name - The String name of the icon

The return value of this method can be safely used in an image tag.

safely converted to a data URI.
the 'data-uri' attribute is set on the document, the image will be
The target image path is then passed through the #image_uri() method. If

(defaulting to 'png').
attribute, the icon name, and the value of the 'icontype' attribute
construct a target image path by concatenating the value of the 'iconsdir'
value of this attribute is used as the target image path. Otherwise,
If the 'icon' attribute is set on this block, the name is ignored and the

specified icon name.
Public: Construct a reference or data URI to an icon image for the
def icon_uri name
  if attr? 'icon'
    # Ruby 2.3 requires the extra brackets around the attr method call
    if (::File.extname (icon = (attr 'icon'))).empty?
      # QUESTION should we be adding the extension if the icon is an absolute URI?
      icon = %(#{icon}.#{@document.attr 'icontype', 'png'})
    end
  else
    icon = %(#{name}.#{@document.attr 'icontype', 'png'})
  end
  image_uri icon, 'iconsdir'
end

def image_uri(target_image, asset_dir_key = 'imagesdir')

Returns A String reference or data URI for the target image

the image is located (default: 'imagesdir')
asset_dir_key - The String attribute key used to lookup the directory where
target_image - A String path to the target image

The return value of this method can be safely used in an image tag.

are satisfied, a relative path (i.e., URL) will be returned.
by reading it from the same directory. If neither of these conditions
is less than SafeMode::SECURE, the image will be safely converted to a data URI
If the 'data-uri' attribute is set on the document, and the safe mode level

specified attribute key, if provided.
The target image is resolved relative to the directory retrieved from the

If the target image is a URI reference, then leave it untouched.

Public: Construct a URI reference or data URI to the target image.
def image_uri(target_image, asset_dir_key = 'imagesdir')
  if (doc = @document).safe < SafeMode::SECURE && (doc.attr? 'data-uri')
    if ((Helpers.uriish? target_image) && (target_image = Helpers.encode_uri target_image)) ||
        (asset_dir_key && (images_base = doc.attr asset_dir_key) && (Helpers.uriish? images_base) &&
        (target_image = normalize_web_path target_image, images_base, false))
      if doc.attr? 'allow-uri-read'
        generate_data_uri_from_uri target_image, (doc.attr? 'cache-uri')
      else
        target_image
      end
    else
      generate_data_uri target_image, asset_dir_key
    end
  else
    normalize_web_path target_image, (asset_dir_key ? (doc.attr asset_dir_key) : nil)
  end
end

def initialize parent, context, opts = {}

def initialize parent, context, opts = {}
  # document is a special case, should refer to itself
  if context == :document
    @document = self
  elsif parent
    @document = (@parent = parent).document
  end
  @node_name = (@context = context).to_s
  # NOTE the value of the :attributes option may be nil on an Inline node
  @attributes = (attrs = opts[:attributes]) ? attrs.merge : {}
  @passthroughs = []
end

def inline?

Returns [Boolean]

Public: Returns whether this {AbstractNode} is an instance of {Inline}
def inline?
  # :nocov:
  raise ::NotImplementedError
  # :nocov:
end

def is_uri? str

Deprecated:
  • Use Helpers.uriish? instead
def is_uri? str
  Helpers.uriish? str
end

def media_uri(target, asset_dir_key = 'imagesdir')

Returns A String reference for the target media

the media is located (default: 'imagesdir')
asset_dir_key - The String attribute key used to lookup the directory where
target - A String reference to the target media

The return value can be safely used in a media tag (img, audio, video).

specified attribute key, if provided.
The target media is resolved relative to the directory retrieved from the

If the target media is a URI reference, then leave it untouched.

Public: Construct a URI reference to 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

def normalize_asset_path(asset_ref, asset_name = 'path', autocorrect = true)

the base_dir instance variable on the Document object.
Delegates to normalize_system_path, with the start path set to the value of

Public: Normalize the asset file or directory to a concrete and rinsed path
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

def normalize_system_path target, start = nil, jail = nil, opts = {}

this path will be guaranteed to be contained within the jail.
parent references resolved and self references removed. If a jail is provided,
Returns the [String] path resolved from the start and target paths, with any

outside the jail.
raises a SecurityError if a jail is specified and the resolved path is

* :target_name is used in messages to refer to the path being resolved
automatically recover when an illegal path is encountered
* :recover is used to control whether the processor should
opts - an optional Hash of options to control processing (default: {}):
jail - the String jail path to confine the resolved path
start - the String start (i.e., parent) path
target - the String target path

by default).
safe level is set to SafeMode::SAFE or greater (a condition which is true
file, stored in the base_dir instance variable on Document) if the document
path outside of the jail (which defaults to the directory of the source
The most important functionality in this method is to prevent resolving a

See {PathResolver#system_path} for details.

using the PathResolver.
Public: Resolve and normalize a secure path from the target and start paths
def normalize_system_path target, start = nil, jail = nil, opts = {}
  if (doc = @document).safe < SafeMode::SAFE
    if start
      start = ::File.join doc.base_dir, start unless doc.path_resolver.root? start
    else
      start = doc.base_dir
    end
  else
    start = doc.base_dir unless start
    jail = doc.base_dir unless jail
  end
  doc.path_resolver.system_path target, start, jail, opts
end

def normalize_web_path(target, start = nil, preserve_uri_target = true)

Returns the resolved [String] path

preserve_uri_target - a Boolean indicating whether target should be preserved if contains a URI (default: true)
start - the String start (i.e, parent) path (optional, default: nil)
target - the String target path

See {PathResolver#web_path} for details about path resolution and encoding.

Public: Normalize the web path using the PathResolver.
def normalize_web_path(target, start = nil, preserve_uri_target = true)
  if preserve_uri_target && (Helpers.uriish? target)
    Helpers.encode_uri target
  else
    @document.path_resolver.web_path target, start
  end
end

def option? name

return a Boolean indicating whether the option has been specified

name - the String or Symbol name of the option

-option attribute is defined on the current node.
Check if the option is enabled. This method simply checks to see if the

enabled on the current node.
Public: A convenience method to check if the specified option attribute is
def option? name
  @attributes[%(#{name}-option)] ? true : false
end

def options

Returns a [Set] of option names

Public: Retrieve the Set of option names that are set on this node
def options
  ::Set.new.tap {|accum| @attributes.each_key {|k| accum << (k.slice 0, k.length - 7) if k.to_s.end_with? '-option' } }
end

def parent= parent

Returns the new parent Block associated with this Block

parent - The Block to set as the parent of this Block

Public: Associate this Block with a new parent Block
def parent= parent
  @parent, @document = parent, parent.document
end

def read_asset path, opts = {}

if the file does not exist.
Returns the [String] content of the file at the specified path, or nil

are normalized and coerced to UTF-8 (default: false)
* :normalize a Boolean that controls whether the lines
is issued if the file cannot be read (default: false)
* :warn_on_failure a Boolean that controls whether a warning
opts - a Hash of options to control processing (default: {})
path - the String path from which to read the contents

that the file is readable before attempting to read it.
This method assumes that the path is safe to read. It checks
Public: Read the contents of the file at the specified path.
def read_asset path, opts = {}
  # remap opts for backwards compatibility
  opts = { warn_on_failure: (opts != false) } unless ::Hash === opts
  if ::File.readable? path
    # QUESTION should we chomp content if normalize is false?
    opts[:normalize] ? ((Helpers.prepare_source_string ::File.read path, mode: FILE_READ_MODE).join LF) : (::File.read path, mode: FILE_READ_MODE)
  elsif opts[:warn_on_failure]
    logger.warn %(#{(attr 'docfile') || '<stdin>'}: #{opts[:label] || 'file'} does not exist or cannot be read: #{path})
    nil
  end
end

def read_contents target, opts = {}

TODO refactor other methods in this class to use this method were possible (repurposing if necessary)
--
Returns the contents of the resolved target or nil if the resolved target cannot be read
* :warn_on_failure a Boolean that indicates whether warnings are issued if the target cannot be read (default: true)
* :start the String relative base path to use when resolving the target (default: nil)
* :normalize a Boolean that indicates whether the data should be normalized (default: false)
* :label the String label of the target to use in warning messages (default: 'asset')
opts - a Hash of options to control processing (default: {})
target - The URI or local path from which to read the data.

file system. If the normalize option is set, the data will be normalized.
attribute is also set. If the resolved path is not a URI, read the contents of the file from the
contents from the URI if the allow-uri-read attribute is set, enabling caching if the cache-uri
The URI or system path of the target is first resolved. If the resolved path is a URI, read the

Public: Resolve the URI or system path to the specified target, then read and return its contents
def read_contents target, opts = {}
  doc = @document
  if (Helpers.uriish? target) || ((start = opts[:start]) && (Helpers.uriish? start) &&
      (target = doc.path_resolver.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
        if opts[:normalize]
          (Helpers.prepare_source_string ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }).join LF
        else
          ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }
        end
      rescue
        logger.warn %(could not retrieve contents of #{opts[:label] || 'asset'} at URI: #{target}) if opts.fetch :warn_on_failure, true
        return
      end
    else
      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
      return
    end
  else
    target = normalize_system_path target, opts[:start], nil, target_name: (opts[:label] || 'asset')
    read_asset target, normalize: opts[:normalize], warn_on_failure: (opts.fetch :warn_on_failure, true), label: opts[:label]
  end
end

def reftext

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

def reftext?

Public: A convenience method that checks if the reftext attribute is defined.
def reftext?
  @attributes.key? 'reftext'
end

def remove_attr name

Returns the previous [String] value, or nil if the attribute was not present.

name - The String attribute name to remove

Public: Remove the attribute from the current node.
def remove_attr name
  @attributes.delete name
end

def remove_role name

Returns a [Boolean] indicating whether the role was removed.

Public: Removes the given role directly from this node.
def remove_role name
  if (val = @attributes['role']) && ((val = val.split).delete name)
    if val.empty?
      @attributes.delete 'role'
    else
      @attributes['role'] = val.join ' '
    end
    true
  else
    false
  end
end

def role

Returns the role as a space-separated [String].

Public: Retrieves the space-separated String role for this node.
def role
  @attributes['role']
end

def role? expected_value = nil

whether the space-separated role matches that value.
Returns a [Boolean] indicating whether the role attribute is set on this node and, if an expected value is given,

expected_value - The expected String value of the role (optional, default: nil)

space-separated role matches that value.
Public: Checks if the role attribute is set on this node and, if an expected value is given, whether the
def role? expected_value = nil
  expected_value ? expected_value == @attributes['role'] : (@attributes.key? 'role')
end

def roles

Returns the role names as a String [Array], which is empty if the role attribute is absent on this node.

Public: Retrieves the String role names for this node as an Array.
def roles
  (val = @attributes['role']) ? val.split : []
end

def set_attr name, value = '', overwrite = true

Returns a [Boolean] indicating whether the assignment was performed

if currently present in the attributes Hash (default: true)
overwrite - A Boolean indicating whether to assign the attribute
value - The Object value to assign to the attribute (default: '')
name - The String attribute name to assign

Public: Assign the value to the attribute name for the current node.
def set_attr name, value = '', overwrite = true
  if overwrite == false && (@attributes.key? name)
    false
  else
    @attributes[name] = value
    true
  end
end

def set_option name

Returns Nothing

name - the String name of the option

This method sets the specified option on this node by setting the -option attribute.

Public: Set the specified option on this node.
def set_option name
  @attributes[%(#{name}-option)] = ''
  nil
end

def update_attributes new_attributes

Returns the updated attributes [Hash] on this node.

new_attributes - A Hash of additional attributes to assign to this node.

be overwritten.
If an attribute already exists with the same key, it's value will

the attributes argument.
Public: Update the attributes of this node with the new values in
def update_attributes new_attributes
  @attributes.update new_attributes
end