Class: Asciidoctor::AbstractNode
- Inherits:
-
Object
- Object
- Asciidoctor::AbstractNode
- Includes:
- Logging, Substitutors
- Defined in:
- lib/asciidoctor/abstract_node.rb
Overview
all content segments in an AsciiDoc document.
Direct Known Subclasses
Constant Summary
Constants included from Substitutors
Substitutors::CAN, Substitutors::CGI, Substitutors::DEL, Substitutors::ESC_R_SB, Substitutors::HighlightedPassSlotRx, Substitutors::PASS_END, Substitutors::PASS_START, Substitutors::PLUS, Substitutors::PassSlotRx, Substitutors::QuotedTextSniffRx, Substitutors::RS, Substitutors::R_SB, Substitutors::SUB_GROUPS, Substitutors::SUB_HINTS, Substitutors::SUB_OPTIONS, Substitutors::SpecialCharsRx, Substitutors::SpecialCharsTr
Instance Attribute Summary collapse
-
#attributes ⇒ Object
readonly
Get the Hash of attributes for this node.
-
#context ⇒ Object
readonly
Get the Symbol context for this node.
-
#document ⇒ Object
readonly
Get the Asciidoctor::Document to which this node belongs.
-
#id ⇒ Object
Get/Set the String id of this node.
-
#node_name ⇒ Object
readonly
Get the String name of this node.
-
#parent ⇒ Object
Get the AbstractBlock parent element of this node.
Instance Method Summary collapse
-
#add_role(name) ⇒ Boolean
Adds the given role directly to this node.
-
#attr(name, default_value = nil, fallback_name = nil) ⇒ Object
Get the value of the specified attribute.
-
#attr?(name, expected_value = nil, fallback_name = nil) ⇒ Boolean
Check if the specified attribute is defined using the same logic as #attr, optionally performing a comparison with the expected value if specified.
-
#block? ⇒ Boolean
Returns whether this AbstractNode is an instance of Block.
-
#converter ⇒ Object
Get the Asciidoctor::Converter instance being used to convert the current Asciidoctor::Document.
-
#enabled_options ⇒ Set
Retrieve the Set of option names that are enabled on this node.
-
#generate_data_uri(target_image, asset_dir_key = nil) ⇒ A
Generate a data URI that can be used to embed an image in the output document.
-
#generate_data_uri_from_uri(image_uri, cache_uri = false) ⇒ A
Read the image data from the specified URI and generate a data URI.
-
#has_role?(name) ⇒ Boolean
Checks if the specified role is present in the list of roles for this node.
-
#icon_uri(name) ⇒ A
Construct a reference or data URI to an icon image for the specified icon name.
-
#image_uri(target_image, asset_dir_key = 'imagesdir') ⇒ A
Construct a URI reference or data URI to the target image.
-
#initialize(parent, context, opts = {}) ⇒ AbstractNode
constructor
A new instance of AbstractNode.
-
#inline? ⇒ Boolean
Returns whether this AbstractNode is an instance of Inline.
-
#is_uri?(str) ⇒ Boolean
deprecated
Deprecated.
Do not use this in new code, and replace it when updating old code.
-
#media_uri(target, asset_dir_key = 'imagesdir') ⇒ A
Construct a URI reference to the target media.
-
#normalize_asset_path(asset_ref, asset_name = 'path', autocorrect = true) ⇒ Object
Normalize the asset file or directory to a concrete and rinsed path.
-
#normalize_system_path(target, start = nil, jail = nil, opts = {}) ⇒ String
Resolve and normalize a secure path from the target and start paths using the PathResolver.
-
#normalize_web_path(target, start = nil, preserve_uri_target = true) ⇒ String
Normalize the web path using the PathResolver.
-
#option?(name) ⇒ Boolean
A convenience method to check if the specified option attribute is enabled on the current node.
-
#read_asset(path, opts = {}) ⇒ String
Read the contents of the file at the specified path.
-
#read_contents(target, opts = {}) ⇒ Object
Resolve the URI or system path to the specified target, then read and return its contents.
-
#reftext ⇒ Object
A convenience method that returns the value of the reftext attribute with substitutions applied.
-
#reftext? ⇒ Boolean
A convenience method that checks if the reftext attribute is defined.
-
#remove_attr(name) ⇒ String
Remove the attribute from the current node.
-
#remove_role(name) ⇒ Boolean
Removes the given role directly from this node.
-
#role ⇒ String
Retrieves the space-separated String role for this node.
-
#role=(names) ⇒ Object
Sets the value of the role attribute on this node.
-
#role?(expected_value = nil) ⇒ Boolean
Checks if the role attribute is set on this node and, if an expected value is given, whether the space-separated role matches that value.
-
#roles ⇒ Array
Retrieves the String role names for this node as an Array.
-
#set_attr(name, value = '', overwrite = true) ⇒ Boolean
Assign the value to the attribute name for the current node.
-
#set_option(name) ⇒ void
Set the specified option on this node.
-
#update_attributes(new_attributes) ⇒ Hash
Update the attributes of this node with the new values in the attributes argument.
Methods included from Substitutors
#apply_header_subs, #apply_normal_subs, #apply_reftext_subs, #apply_subs, #expand_subs, #extract_passthroughs, #highlight_source, #resolve_block_subs, #resolve_lines_to_highlight, #resolve_pass_subs, #resolve_subs, #restore_passthroughs, #sub_attributes, #sub_callouts, #sub_macros, #sub_post_replacements, #sub_quotes, #sub_replacements, #sub_source, #sub_specialchars
Methods included from Logging
#logger, #message_with_context
Constructor Details
#initialize(parent, context, opts = {}) ⇒ AbstractNode
Returns a new instance of AbstractNode.
28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/asciidoctor/abstract_node.rb', line 28 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 |
Instance Attribute Details
#attributes ⇒ Object (readonly)
Get the Hash of attributes for this node
11 12 13 |
# File 'lib/asciidoctor/abstract_node.rb', line 11 def attributes @attributes end |
#context ⇒ Object (readonly)
Get the Symbol context for this node
14 15 16 |
# File 'lib/asciidoctor/abstract_node.rb', line 14 def context @context end |
#document ⇒ Object (readonly)
Get the Asciidoctor::Document to which this node belongs
17 18 19 |
# File 'lib/asciidoctor/abstract_node.rb', line 17 def document @document end |
#id ⇒ Object
Get/Set the String id of this node
20 21 22 |
# File 'lib/asciidoctor/abstract_node.rb', line 20 def id @id end |
#node_name ⇒ Object (readonly)
Get the String name of this node
23 24 25 |
# File 'lib/asciidoctor/abstract_node.rb', line 23 def node_name @node_name end |
#parent ⇒ Object
Get the AbstractBlock parent element of this node
26 27 28 |
# File 'lib/asciidoctor/abstract_node.rb', line 26 def parent @parent end |
Instance Method Details
#add_role(name) ⇒ Boolean
Adds the given role directly to this node.
232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/asciidoctor/abstract_node.rb', line 232 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 |
#attr(name, default_value = nil, fallback_name = nil) ⇒ Object
Get the value of the specified attribute. If the attribute is not found on this node, fallback_name is set, and this node is not the Document node, get the value of the specified attribute from the Document node.
Look for the specified attribute in the attributes on this node and return the value of the attribute, if found. Otherwise, if fallback_name is set (default: same as name) and this node is not the Document node, look for that attribute on the Document node and return its value, if found. Otherwise, return the default value (default: nil).
87 88 89 |
# File 'lib/asciidoctor/abstract_node.rb', line 87 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 |
#attr?(name, expected_value = nil, fallback_name = nil) ⇒ Boolean
Check if the specified attribute is defined using the same logic as #attr, optionally performing a comparison with the expected value if specified.
Look for the specified attribute in the attributes on this node. If not found, fallback_name is specified (default: same as name), and this node is not the Document node, look for that attribute on the Document node. In either case, if the attribute is found, and the comparison value is truthy, return whether the two values match. Otherwise, return whether the attribute was found.
106 107 108 109 110 111 112 |
# File 'lib/asciidoctor/abstract_node.rb', line 106 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 |
#block? ⇒ Boolean
Returns whether this Asciidoctor::AbstractNode is an instance of Block
44 45 46 47 48 |
# File 'lib/asciidoctor/abstract_node.rb', line 44 def block? # :nocov: raise ::NotImplementedError # :nocov: end |
#converter ⇒ Object
Get the Asciidoctor::Converter instance being used to convert the current Asciidoctor::Document.
61 62 63 |
# File 'lib/asciidoctor/abstract_node.rb', line 61 def converter @document.converter end |
#enabled_options ⇒ Set
Retrieve the Set of option names that are enabled on this node
168 169 170 |
# File 'lib/asciidoctor/abstract_node.rb', line 168 def ::Set.new.tap {|accum| @attributes.each_key {|k| accum << (k.slice 0, k.length - 7) if k.to_s.end_with? '-option' } } end |
#generate_data_uri(target_image, asset_dir_key = nil) ⇒ A
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 base64. Finally, a data URI is built which can be used in an image tag.
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
# File 'lib/asciidoctor/abstract_node.rb', line 365 def generate_data_uri(target_image, asset_dir_key = nil) if (ext = Helpers.extname target_image, nil) mimetype = ext == '.svg' ? 'image/svg+xml' : %(image/#{ext.slice 1, ext.length}) else mimetype = 'application/octet-stream' end 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 pack 'm0' is equivalent to Base64.strict_encode64 %(data:#{mimetype};base64,#{[(::File.binread image_path)].pack 'm0'}) 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 |
#generate_data_uri_from_uri(image_uri, cache_uri = false) ⇒ A
Read the image data from the specified URI and generate a data URI
The image data is read from the URI and converted to Base64. A data URI is constructed from the content_type header and Base64 data and returned, which can then be used in an image tag.
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
# File 'lib/asciidoctor/abstract_node.rb', line 401 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 pack 'm0' is equivalent to Base64.strict_encode64 %(data:#{mimetype};base64,#{[bindata].pack 'm0'}) 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 |
#has_role?(name) ⇒ Boolean
Checks if the specified role is present in the list of roles for this node.
215 216 217 218 |
# File 'lib/asciidoctor/abstract_node.rb', line 215 def has_role? name # NOTE center + include? is faster than split + include? (val = @attributes['role']) ? (%( #{val} ).include? %( #{name} )) : false end |
#icon_uri(name) ⇒ A
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, construct a target image path by concatenating the value of the ‘iconsdir’ attribute, the icon name, and the value of the ‘icontype’ attribute (defaulting to ‘png’).
The target image path is then passed through the #image_uri() method. If the ‘data-uri’ attribute is set on the document, the image will be safely converted to a data URI.
The return value of this method can be safely used in an image tag.
291 292 293 294 295 296 297 298 299 300 |
# File 'lib/asciidoctor/abstract_node.rb', line 291 def icon_uri name if attr? 'icon' icon = attr 'icon' # QUESTION should we be adding the extension if the icon is an absolute URI? icon = %(#{icon}.#{@document.attr 'icontype', 'png'}) unless Helpers.extname? icon else icon = %(#{name}.#{@document.attr 'icontype', 'png'}) end image_uri icon, 'iconsdir' end |
#image_uri(target_image, asset_dir_key = 'imagesdir') ⇒ A
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 specified attribute key, if provided.
If the ‘data-uri’ attribute is set on the document, and the safe mode level is less than SafeMode::SECURE, the image will be safely converted to a data URI by reading it from the same directory. If neither of these conditions are satisfied, a relative path (i.e., URL) will be returned.
The return value of this method can be safely used in an image tag.
321 322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'lib/asciidoctor/abstract_node.rb', line 321 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_spaces_in_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)) (doc.attr? 'allow-uri-read') ? (generate_data_uri_from_uri target_image, (doc.attr? 'cache-uri')) : target_image 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 |
#inline? ⇒ Boolean
Returns whether this Asciidoctor::AbstractNode is an instance of Inline
53 54 55 56 57 |
# File 'lib/asciidoctor/abstract_node.rb', line 53 def inline? # :nocov: raise ::NotImplementedError # :nocov: end |
#is_uri?(str) ⇒ Boolean
Do not use this in new code, and replace it when updating old code.
Check whether the specified String is a URI by matching it against the Asciidoctor::UriSniffRx regex.
In use by Asciidoctor PDF
@deprecated Use Helpers.uriish? instead
563 564 565 |
# File 'lib/asciidoctor/abstract_node.rb', line 563 def is_uri? str Helpers.uriish? str end |
#media_uri(target, asset_dir_key = 'imagesdir') ⇒ A
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).
349 350 351 |
# File 'lib/asciidoctor/abstract_node.rb', line 349 def media_uri(target, asset_dir_key = 'imagesdir') normalize_web_path target, (asset_dir_key ? @document.attr(asset_dir_key) : nil) end |
#normalize_asset_path(asset_ref, asset_name = 'path', autocorrect = true) ⇒ Object
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.
429 430 431 |
# File 'lib/asciidoctor/abstract_node.rb', line 429 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 |
#normalize_system_path(target, start = nil, jail = nil, opts = {}) ⇒ String
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).
458 459 460 461 462 463 464 465 466 467 468 469 470 |
# File 'lib/asciidoctor/abstract_node.rb', line 458 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 jail ||= doc.base_dir end doc.path_resolver.system_path target, start, jail, opts end |
#normalize_web_path(target, start = nil, preserve_uri_target = true) ⇒ String
Normalize the web path using the PathResolver.
See PathResolver#web_path for details about path resolution and encoding.
481 482 483 484 485 486 487 |
# File 'lib/asciidoctor/abstract_node.rb', line 481 def normalize_web_path(target, start = nil, preserve_uri_target = true) if preserve_uri_target && (Helpers.uriish? target) Helpers.encode_spaces_in_uri target else @document.path_resolver.web_path target, start end end |
#option?(name) ⇒ Boolean
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.
149 150 151 |
# File 'lib/asciidoctor/abstract_node.rb', line 149 def option? name @attributes[%(#{name}-option)] ? true : false end |
#read_asset(path, opts = {}) ⇒ String
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.
502 503 504 505 506 507 508 509 510 511 512 |
# File 'lib/asciidoctor/abstract_node.rb', line 502 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 |
#read_contents(target, opts = {}) ⇒ Object
Resolve the URI or system path to the specified target, then read and return its contents
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.
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 |
# File 'lib/asciidoctor/abstract_node.rb', line 531 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] contents = (Helpers.prepare_source_string ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }).join LF else contents = ::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 end elsif opts.fetch :warn_on_failure, true logger.warn %(cannot retrieve contents of #{opts[:label] || 'asset'} at URI: #{target} (allow-uri-read attribute not enabled)) end else target = normalize_system_path target, opts[:start], nil, target_name: (opts[:label] || 'asset') contents = read_asset target, normalize: opts[:normalize], warn_on_failure: (opts.fetch :warn_on_failure, true), label: opts[:label] end logger.warn %(contents of #{opts[:label] || 'asset'} is empty: #{target}) if contents && opts[:warn_if_empty] && contents.empty? contents end |
#reftext ⇒ Object
A convenience method that returns the value of the reftext attribute with substitutions applied.
264 265 266 |
# File 'lib/asciidoctor/abstract_node.rb', line 264 def reftext (val = @attributes['reftext']) ? (apply_reftext_subs val) : nil end |
#reftext? ⇒ Boolean
A convenience method that checks if the reftext attribute is defined.
269 270 271 |
# File 'lib/asciidoctor/abstract_node.rb', line 269 def reftext? @attributes.key? 'reftext' end |
#remove_attr(name) ⇒ String
Remove the attribute from the current node.
136 137 138 |
# File 'lib/asciidoctor/abstract_node.rb', line 136 def remove_attr name @attributes.delete name end |
#remove_role(name) ⇒ Boolean
Removes the given role directly from this node.
250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/asciidoctor/abstract_node.rb', line 250 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 |
#role ⇒ String
Retrieves the space-separated String role for this node.
188 189 190 |
# File 'lib/asciidoctor/abstract_node.rb', line 188 def role @attributes['role'] end |
#role=(names) ⇒ Object
Sets the value of the role attribute on this node.
225 226 227 |
# File 'lib/asciidoctor/abstract_node.rb', line 225 def role= names @attributes['role'] = (::Array === names) ? (names.join ' ') : names end |
#role?(expected_value = nil) ⇒ Boolean
Checks if the role attribute is set on this node and, if an expected value is given, whether the space-separated role matches that value.
206 207 208 |
# File 'lib/asciidoctor/abstract_node.rb', line 206 def role? expected_value = nil expected_value ? expected_value == @attributes['role'] : (@attributes.key? 'role') end |
#roles ⇒ Array
Retrieves the String role names for this node as an Array.
195 196 197 |
# File 'lib/asciidoctor/abstract_node.rb', line 195 def roles (val = @attributes['role']) ? val.split : [] end |
#set_attr(name, value = '', overwrite = true) ⇒ Boolean
Assign the value to the attribute name for the current node.
122 123 124 125 126 127 128 129 |
# File 'lib/asciidoctor/abstract_node.rb', line 122 def set_attr name, value = '', overwrite = true if overwrite == false && (@attributes.key? name) false else @attributes[name] = value true end end |
#set_option(name) ⇒ void
This method returns an undefined value.
Set the specified option on this node.
This method sets the specified option on this node by setting the <name>-option attribute.
160 161 162 163 |
# File 'lib/asciidoctor/abstract_node.rb', line 160 def set_option name @attributes[%(#{name}-option)] = '' nil end |
#update_attributes(new_attributes) ⇒ Hash
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 overwritten.
181 182 183 |
# File 'lib/asciidoctor/abstract_node.rb', line 181 def update_attributes new_attributes @attributes.update new_attributes end |