class Asciidoctor::AbstractNode
all content segments in an AsciiDoc document.
node of AsciiDoc content. The state and methods on this class are comment to
Public: An abstract base class that provides state and methods for managing a
def add_role(name)
def add_role(name) unless (roles = (@attributes['role'] || '').split(' ')).include? name @attributes['role'] = roles.push(name) * ' ' end end
def attr(name, default_value = nil, inherit = true)
return the value of the attribute or the default value if the attribute
AsciiDoctor::Document if not found on this node (default: false)
inherit - a Boolean indicating whether to check for the attribute on the
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 lookup
return the default value, which defaults to nil.
Document node and return the value of the attribute if found. Otherwise,
this node is a child of the Document node, look in the attributes of the
this node and return the value of the attribute if found. Otherwise, if
Get the value for the specified attribute. First look in the attributes on
Public: Get the value of the specified attribute
def attr(name, default_value = nil, inherit = true) name = name.to_s if ::Symbol === name inherit = false if self == @document if inherit @attributes[name] || @document.attributes[name] || default_value else @attributes[name] || default_value end end
def attr?(name, expect = nil, inherit = true)
comparison value is specified, whether the value of the attribute matches
return a Boolean indicating whether the attribute exists and, if a
AsciiDoctor::Document if not found on this node (default: false)
inherit - a Boolean indicating whether to check for the attribute on the
expect - the expected Object value of the attribute (default: nil)
name - the String or Symbol name of the attribute to lookup
Otherwise, return whether the attribute was found.
comparison value is specified (not nil), return whether the two values match.
the attributes of the Document node. If the attribute is found and a
node. If not found, and this node is a child of the Document node, look in
Check if the attribute is defined. First look in the attributes on this
comparison of its value if expected is not nil
Public: Check if the attribute is defined, optionally performing a
def attr?(name, expect = nil, inherit = true) name = name.to_s if ::Symbol === name inherit = false if self == @document if expect.nil? @attributes.has_key?(name) || (inherit && @document.attributes.has_key?(name)) elsif inherit expect == (@attributes[name] || @document.attributes[name]) else expect == @attributes[name] end end
def block?
Public: Returns whether this {AbstractNode} is an instance of {Block}
def block? # :nocov: raise ::NotImplementedError # :nocov: end
def converter
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)
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[1..-1]})) 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 unless ::File.readable? image_path warn %(asciidoctor: WARNING: image to embed not found or not readable: #{image_path}) # must enclose string following return in " for Opal return "data:#{mimetype}:base64," # uncomment to return 1 pixel white dot instead #return 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' end bindata = nil if ::IO.respond_to? :binread bindata = ::IO.binread(image_path) else bindata = ::File.open(image_path, 'rb') {|file| file.read } end # NOTE base64 is autoloaded by reference to ::Base64 %(data:#{mimetype};base64,#{::Base64.encode64(bindata).delete EOL}) end
def generate_data_uri_from_uri image_uri, cache_uri = false
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 = nil bindata = open(image_uri, 'rb') {|file| mimetype = file.content_type file.read } # NOTE base64 is autoloaded by reference to ::Base64 %(data:#{mimetype};base64,#{::Base64.encode64(bindata).delete EOL}) rescue warn %(asciidoctor: WARNING: 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)
Public: A convenience method that checks if the specified role is present
def has_role?(name) if (val = (@attributes['role'] || @document.attributes['role'])) val.split(' ').include?(name) else false end end
def icon_uri(name)
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' image_uri(attr('icon'), nil) else image_uri(%(#{name}.#{@document.attr('icontype', 'png')}), 'iconsdir') end end
def image_uri(target_image, asset_dir_key = 'imagesdir')
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) || (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 = parent else if parent @parent = parent @document = parent.document else @parent = nil @document = nil end end @context = context @node_name = context.to_s # QUESTION are we correct in duplicating the attributes (seems to be just as fast) @attributes = (opts.key? :attributes) ? opts[:attributes].dup : {} @passthroughs = {} end
def inline?
Public: Returns whether this {AbstractNode} is an instance of {Inline}
def inline? # :nocov: raise ::NotImplementedError # :nocov: end
def is_uri? str
- Use Helpers.uriish? instead
def is_uri? str Helpers.uriish? str end
def list_marker_keyword(list_type = nil)
list_type - the type of list; default to the @style if not specified
For use in the HTML type attribute.
Public: Retrieve the list marker keyword for the specified list type.
def list_marker_keyword(list_type = nil) ORDERED_LIST_KEYWORDS[list_type || @style] end
def media_uri(target, asset_dir_key = 'imagesdir')
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)
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 = {}
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
when an illegal path is encountered
* :recover is used to control whether the processor should auto-recover
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 = {} 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
def normalize_web_path(target, start = nil, preserve_uri_target = true)
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.
Public: Normalize the web page using the PathResolver.
def normalize_web_path(target, start = nil, preserve_uri_target = true) if preserve_uri_target && (Helpers.uriish? target) target else (@path_resolver ||= PathResolver.new).web_path target, start end end
def option?(name)
name - the String or Symbol name of the option
%name%-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.has_key? %(#{name}-option) end
def parent=(parent)
parent - The Block to set as the parent of this Block
Public: Associate this Block with a new parent Block
def parent=(parent) @parent = parent @document = parent.document nil end
def read_asset(path, opts = {})
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 if opts[:normalize] Helpers.normalize_lines_from_string(::IO.read(path)) * EOL else # QUESTION should we chomp or rstrip content? ::IO.read(path) end else warn %(asciidoctor: WARNING: file does not exist or cannot be read: #{path}) if opts[:warn_on_failure] nil end end
def read_contents target, opts = {}
--
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 = (@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) * EOL 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 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) end data end
def reftext
def reftext @attributes['reftext'] || @document.attributes['reftext'] end
def reftext?
def reftext? @attributes.has_key?('reftext') || @document.attributes.has_key?('reftext') end
def relative_path(filename)
def relative_path(filename) (@path_resolver ||= PathResolver.new).relative_path filename, @document.base_dir end
def remove_role(name)
def remove_role(name) if (roles = (@attributes['role'] || '').split(' ')).include? name roles.delete name @attributes['role'] = roles * ' ' end end
def role
def role @attributes['role'] || @document.attributes['role'] end
def role?(expect = nil)
def role?(expect = nil) if expect expect == (@attributes['role'] || @document.attributes['role']) else @attributes.has_key?('role') || @document.attributes.has_key?('role') end end
def roles
def roles if (val = (@attributes['role'] || @document.attributes['role'])) val.split(' ') else [] end end
def set_attr name, value, overwrite = true
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
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)
def set_option(name) if @attributes.has_key? 'options' @attributes['options'] = "#{@attributes['options']},#{name}" else @attributes['options'] = name end @attributes["#{name}-option"] = '' end
def update_attributes(attributes)
attributes - A Hash of attributes to assign to this node.
be overridden.
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(attributes) @attributes.update(attributes) nil end