summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/asciidoctor.rb1
-rw-r--r--lib/asciidoctor/converter/template.rb15
-rw-r--r--lib/asciidoctor/document.rb334
3 files changed, 188 insertions, 162 deletions
diff --git a/lib/asciidoctor.rb b/lib/asciidoctor.rb
index 77eaa654..7f4b5a4a 100644
--- a/lib/asciidoctor.rb
+++ b/lib/asciidoctor.rb
@@ -1236,6 +1236,7 @@ module Asciidoctor
timings.start :parse
end
+ options[:parse] = true unless options.key? :parse
doc = Document.new lines, options
timings.record :parse if timings
doc
diff --git a/lib/asciidoctor/converter/template.rb b/lib/asciidoctor/converter/template.rb
index 765f5d0c..160f9772 100644
--- a/lib/asciidoctor/converter/template.rb
+++ b/lib/asciidoctor/converter/template.rb
@@ -248,15 +248,17 @@ module Asciidoctor
name = name[6..-1]
end
ext_name = path_segments[-1]
+ template_class = ::Tilt
+ extra_engine_options = {}
if ext_name == 'slim'
# slim doesn't get loaded by Tilt, so we have to load it explicitly
Helpers.require_library 'slim' unless defined? ::Slim
elsif ext_name == 'erb'
- eruby_loaded = load_eruby @eruby unless eruby_loaded
+ template_class, extra_engine_options = (eruby_loaded ||= load_eruby @eruby)
end
next unless ::Tilt.registered? ext_name
unless template_cache && (template = template_cache[file])
- template = ::Tilt.new file, 1, @engine_options[ext_name.to_sym]
+ template = template_class.new file, 1, (@engine_options[ext_name.to_sym] || {}).merge(extra_engine_options)
end
result[name] = template
end
@@ -270,14 +272,15 @@ module Asciidoctor
#
# name - the String name of the eRuby implementation
#
- # Returns the eRuby implementation [Class]
+ # Returns an [Array] containing the Tilt template Class for the eRuby implementation
+ # and a Hash of additional options to pass to the initializer
def load_eruby name
if !name || name == 'erb'
require 'erb' unless defined? ::ERB
- ::ERB
+ [::Tilt::ERBTemplate, {}]
elsif name == 'erubis'
- Helpers.require_library 'erubis' unless defined? ::Erubis
- ::Erubis::FastEruby
+ Helpers.require_library 'erubis' unless defined? ::Erubis::FastEruby
+ [::Tilt::ErubisTemplate, { :engine_class => ::Erubis::FastEruby }]
else
raise ::ArgumentError, %(Unknown ERB implementation: #{name})
end
diff --git a/lib/asciidoctor/document.rb b/lib/asciidoctor/document.rb
index e133c116..eb45358c 100644
--- a/lib/asciidoctor/document.rb
+++ b/lib/asciidoctor/document.rb
@@ -18,7 +18,7 @@ module Asciidoctor
# nofooter - the footer block should not be shown
class Document < AbstractBlock
- Footnote = Struct.new :index, :id, :text
+ Footnote = ::Struct.new :index, :id, :text
class AttributeEntry
attr_reader :name, :value, :negate
@@ -88,46 +88,49 @@ class Document < AbstractBlock
# Public: A reference to the parent document of this nested document.
attr_reader :parent_document
+ # Public: The Reader associated with this document
+ attr_reader :reader
+
# Public: The Converter associated with this document
attr_reader :converter
# Public: The extensions registry
attr_reader :extensions
- # Public: Initialize an Asciidoc object.
+ # Public: Initialize a {Document} object.
#
- # data - The Array of Strings holding the Asciidoc source document. (default: [])
- # options - A Hash of options to control processing, such as setting the safe mode (:safe),
- # suppressing the header/footer (:header_footer) and attribute overrides (:attributes)
- # (default: {})
+ # data - The AsciiDoc source data as a String or String Array. (default: nil)
+ # options - A Hash of options to control processing (e.g., safe mode value (:safe), backend (:backend),
+ # header/footer toggle (:header_footer), custom attributes (:attributes)). (default: {})
#
# Examples
#
- # data = File.readlines(filename)
- # doc = Asciidoctor::Document.new(data)
+ # data = File.read filename
+ # doc = Asciidoctor::Document.new data
# puts doc.convert
- def initialize(data = [], options = {})
- super(self, :document)
+ def initialize data = nil, options = {}
+ super self, :document
- if options[:parent]
- @parent_document = options.delete(:parent)
- options[:base_dir] ||= @parent_document.base_dir
- @references = @parent_document.references.inject({}) do |collector,(key,ref)|
+ if (parent_doc = options.delete :parent)
+ @parent_document = parent_doc
+ options[:base_dir] ||= parent_doc.base_dir
+ @references = parent_doc.references.inject({}) do |accum, (key,ref)|
if key == :footnotes
- collector[:footnotes] = []
+ accum[:footnotes] = []
else
- collector[key] = ref
+ accum[key] = ref
end
- collector
+ accum
end
# QUESTION should we support setting attribute in parent document from nested document?
# NOTE we must dup or else all the assignments to the overrides clobbers the real attributes
- @attribute_overrides = @parent_document.attributes.dup
- @attribute_overrides.delete 'doctype'
- @safe = @parent_document.safe
- @converter = @parent_document.converter
+ attr_overrides = parent_doc.attributes.dup
+ attr_overrides.delete 'doctype'
+ @attribute_overrides = attr_overrides
+ @safe = parent_doc.safe
+ @converter = parent_doc.converter
initialize_extensions = false
- @extensions = @parent_document.extensions
+ @extensions = parent_doc.extensions
else
@parent_document = nil
@references = {
@@ -142,195 +145,192 @@ class Document < AbstractBlock
# attribute overrides are attributes that can only be set from the commandline
# a direct assignment effectively makes the attribute a constant
# a nil value or name with leading or trailing ! will result in the attribute being unassigned
- overrides = {}
+ attr_overrides = {}
(options[:attributes] || {}).each do |key, value|
- if key.start_with?('!')
+ if key.start_with? '!'
key = key[1..-1]
value = nil
- elsif key.end_with?('!')
+ elsif key.end_with? '!'
key = key.chop
value = nil
end
- overrides[key.downcase] = value
+ attr_overrides[key.downcase] = value
end
- @attribute_overrides = overrides
+ @attribute_overrides = attr_overrides
@safe = nil
@converter = nil
initialize_extensions = defined? ::Asciidoctor::Extensions
@extensions = nil # initialize furthur down
end
+ @parsed = false
@header = nil
@counters = {}
@callouts = Callouts.new
@attributes_modified = ::Set.new
@options = options
- unless @parent_document
+ unless parent_doc
# safely resolve the safe mode from const, int or string
- if !@safe && !(safe_mode = options[:safe])
+ if !(safe_mode = options[:safe])
@safe = SafeMode::SECURE
- elsif safe_mode.is_a?(::Fixnum)
+ elsif safe_mode.is_a? ::Fixnum
# be permissive in case API user wants to define new levels
@safe = safe_mode
else
- begin
- @safe = SafeMode.const_get(safe_mode.to_s.upcase).to_i
- rescue
- @safe = SafeMode::SECURE.to_i
- end
+ @safe = SafeMode.const_get(safe_mode.to_s.upcase).to_i rescue SafeMode::SECURE.to_i
end
end
- options[:header_footer] ||= false
+ header_footer = (options[:header_footer] ||= false)
- @attributes['encoding'] = 'UTF-8'
- @attributes['sectids'] = ''
- @attributes['notitle'] = '' unless options[:header_footer]
- @attributes['toc-placement'] = 'auto'
- @attributes['stylesheet'] = ''
- @attributes['copycss'] = '' if options[:header_footer]
- @attributes['prewrap'] = ''
- @attributes['attribute-undefined'] = Compliance.attribute_undefined
- @attributes['attribute-missing'] = Compliance.attribute_missing
+ attrs = @attributes
+ attrs['encoding'] = 'UTF-8'
+ attrs['sectids'] = ''
+ attrs['notitle'] = '' unless header_footer
+ attrs['toc-placement'] = 'auto'
+ attrs['stylesheet'] = ''
+ attrs['copycss'] = '' if header_footer
+ attrs['prewrap'] = ''
+ attrs['attribute-undefined'] = Compliance.attribute_undefined
+ attrs['attribute-missing'] = Compliance.attribute_missing
# language strings
# TODO load these based on language settings
- @attributes['caution-caption'] = 'Caution'
- @attributes['important-caption'] = 'Important'
- @attributes['note-caption'] = 'Note'
- @attributes['tip-caption'] = 'Tip'
- @attributes['warning-caption'] = 'Warning'
- @attributes['appendix-caption'] = 'Appendix'
- @attributes['example-caption'] = 'Example'
- @attributes['figure-caption'] = 'Figure'
- #@attributes['listing-caption'] = 'Listing'
- @attributes['table-caption'] = 'Table'
- @attributes['toc-title'] = 'Table of Contents'
- @attributes['manname-title'] = 'NAME'
- @attributes['untitled-label'] = 'Untitled'
- @attributes['version-label'] = 'Version'
- @attributes['last-update-label'] = 'Last updated'
-
- @attribute_overrides['asciidoctor'] = ''
- @attribute_overrides['asciidoctor-version'] = VERSION
-
- safe_mode_name = SafeMode.constants.detect {|l| SafeMode.const_get(l) == @safe}.to_s.downcase
- @attribute_overrides['safe-mode-name'] = safe_mode_name
- @attribute_overrides["safe-mode-#{safe_mode_name}"] = ''
- @attribute_overrides['safe-mode-level'] = @safe
+ attrs['caution-caption'] = 'Caution'
+ attrs['important-caption'] = 'Important'
+ attrs['note-caption'] = 'Note'
+ attrs['tip-caption'] = 'Tip'
+ attrs['warning-caption'] = 'Warning'
+ attrs['appendix-caption'] = 'Appendix'
+ attrs['example-caption'] = 'Example'
+ attrs['figure-caption'] = 'Figure'
+ #attrs['listing-caption'] = 'Listing'
+ attrs['table-caption'] = 'Table'
+ attrs['toc-title'] = 'Table of Contents'
+ attrs['manname-title'] = 'NAME'
+ attrs['untitled-label'] = 'Untitled'
+ attrs['version-label'] = 'Version'
+ attrs['last-update-label'] = 'Last updated'
+
+ attr_overrides['asciidoctor'] = ''
+ attr_overrides['asciidoctor-version'] = VERSION
+
+ safe_mode_name = SafeMode.constants.detect {|l| SafeMode.const_get(l) == @safe }.to_s.downcase
+ attr_overrides['safe-mode-name'] = safe_mode_name
+ attr_overrides["safe-mode-#{safe_mode_name}"] = ''
+ attr_overrides['safe-mode-level'] = @safe
# sync the embedded attribute w/ the value of options...do not allow override
- @attribute_overrides['embedded'] = options[:header_footer] ? nil : ''
+ attr_overrides['embedded'] = header_footer ? nil : ''
# the only way to set the max-include-depth attribute is via the document options
# 64 is the AsciiDoc default
- @attribute_overrides['max-include-depth'] ||= 64
+ attr_overrides['max-include-depth'] ||= 64
# the only way to enable uri reads is via the document options, disabled by default
- unless !@attribute_overrides['allow-uri-read'].nil?
- @attribute_overrides['allow-uri-read'] = nil
+ unless !attr_overrides['allow-uri-read'].nil?
+ attr_overrides['allow-uri-read'] = nil
end
- @attribute_overrides['user-home'] = USER_HOME
+ attr_overrides['user-home'] = USER_HOME
# if the base_dir option is specified, it overrides docdir as the root for relative paths
# otherwise, the base_dir is the directory of the source file (docdir) or the current
# directory of the input is a string
- if !options[:base_dir]
- if @attribute_overrides['docdir']
- @base_dir = @attribute_overrides['docdir'] = ::File.expand_path(@attribute_overrides['docdir'])
+ if options[:base_dir]
+ @base_dir = attr_overrides['docdir'] = ::File.expand_path(options[:base_dir])
+ else
+ if attr_overrides['docdir']
+ @base_dir = attr_overrides['docdir'] = ::File.expand_path(attr_overrides['docdir'])
else
#warn 'asciidoctor: WARNING: setting base_dir is recommended when working with string documents' unless nested?
- @base_dir = @attribute_overrides['docdir'] = ::File.expand_path(::Dir.pwd)
+ @base_dir = attr_overrides['docdir'] = ::File.expand_path(::Dir.pwd)
end
- else
- @base_dir = @attribute_overrides['docdir'] = ::File.expand_path(options[:base_dir])
end
- # allow common attributes backend and doctype to be set using options hash
- if (value = options[:backend])
- @attribute_overrides['backend'] = %(#{value})
+ # allow common attributes backend and doctype to be set using options hash, coerce values to string
+ if (backend_val = options[:backend])
+ attr_overrides['backend'] = %(#{backend_val})
end
- if (value = options[:doctype])
- @attribute_overrides['doctype'] = %(#{value})
+ if (doctype_val = options[:doctype])
+ attr_overrides['doctype'] = %(#{doctype_val})
end
if @safe >= SafeMode::SERVER
# restrict document from setting copycss, source-highlighter and backend
- @attribute_overrides['copycss'] ||= nil
- @attribute_overrides['source-highlighter'] ||= nil
- @attribute_overrides['backend'] ||= DEFAULT_BACKEND
+ attr_overrides['copycss'] ||= nil
+ attr_overrides['source-highlighter'] ||= nil
+ attr_overrides['backend'] ||= DEFAULT_BACKEND
# restrict document from seeing the docdir and trim docfile to relative path
- if !@parent_document && @attribute_overrides.has_key?('docfile')
- @attribute_overrides['docfile'] = @attribute_overrides['docfile'][(@attribute_overrides['docdir'].length + 1)..-1]
+ if !parent_doc && attr_overrides.key?('docfile')
+ attr_overrides['docfile'] = attr_overrides['docfile'][(attr_overrides['docdir'].length + 1)..-1]
end
- @attribute_overrides['docdir'] = ''
- @attribute_overrides['user-home'] = '.'
+ attr_overrides['docdir'] = ''
+ attr_overrides['user-home'] = '.'
if @safe >= SafeMode::SECURE
# assign linkcss (preventing css embedding) unless explicitly disabled from the commandline or API
# effectively the same has "has key 'linkcss' and value == nil"
- unless @attribute_overrides.fetch('linkcss', '').nil?
- @attribute_overrides['linkcss'] = ''
+ unless attr_overrides.fetch('linkcss', '').nil?
+ attr_overrides['linkcss'] = ''
end
# restrict document from enabling icons
- @attribute_overrides['icons'] ||= nil
+ attr_overrides['icons'] ||= nil
end
end
- @attribute_overrides.delete_if {|key, val|
+ attr_overrides.delete_if do |key, val|
verdict = false
# a nil value undefines the attribute
if val.nil?
- @attributes.delete(key)
- # a negative key (trailing !) undefines the attribute
- # NOTE already normalize above as key with nil value
- #elsif key.end_with? '!'
- # @attributes.delete(key[0..-2])
- # a negative key (leading !) undefines the attribute
- # NOTE already normalize above as key with nil value
- #elsif key.start_with? '!'
- # @attributes.delete(key[1..-1])
- # otherwise it's an attribute assignment
+ attrs.delete(key)
else
# a value ending in @ indicates this attribute does not override
# an attribute with the same key in the document souce
- if val.is_a?(::String) && val.end_with?('@')
+ if (val.is_a? ::String) && (val.end_with? '@')
val = val.chop
verdict = true
end
- @attributes[key] = val
+ attrs[key] = val
end
verdict
- }
+ end
- if @parent_document
+ if parent_doc
# don't need to do the extra processing within our own document
# FIXME line info isn't reported correctly within include files in nested document
@reader = Reader.new data, options[:cursor]
+
+ # Now parse the lines in the reader into blocks
+ # Eagerly parse (for now) since a subdocument is not a publicly accessible object
+ Parser.parse @reader, self
+
+ # should we call rewind in some sort of post-parse function?
+ @callouts.rewind
+ @parsed = true
else
# setup default backend and doctype
- @attributes['backend'] ||= DEFAULT_BACKEND
- @attributes['doctype'] ||= DEFAULT_DOCTYPE
- update_backend_attributes @attributes['backend'], true
+ attrs['backend'] ||= DEFAULT_BACKEND
+ attrs['doctype'] ||= DEFAULT_DOCTYPE
+ update_backend_attributes attrs['backend'], true
- #@attributes['indir'] = @attributes['docdir']
- #@attributes['infile'] = @attributes['docfile']
+ #attrs['indir'] = attrs['docdir']
+ #attrs['infile'] = attrs['docfile']
# dynamic intrinstic attribute values
- now = Time.new
- @attributes['localdate'] ||= now.strftime('%Y-%m-%d')
- @attributes['localtime'] ||= now.strftime('%H:%M:%S %Z')
- @attributes['localdatetime'] ||= %(#{@attributes['localdate']} #{@attributes['localtime']})
+ now = ::Time.now
+ localdate = (attrs['localdate'] ||= now.strftime('%Y-%m-%d'))
+ localtime = (attrs['localtime'] ||= now.strftime('%H:%M:%S %Z'))
+ attrs['localdatetime'] ||= %(#{localdate} #{localtime})
# docdate, doctime and docdatetime should default to
# localdate, localtime and localdatetime if not otherwise set
- @attributes['docdate'] ||= @attributes['localdate']
- @attributes['doctime'] ||= @attributes['localtime']
- @attributes['docdatetime'] ||= @attributes['localdatetime']
+ attrs['docdate'] ||= localdate
+ attrs['doctime'] ||= localtime
+ attrs['docdatetime'] ||= %(#{localdate} #{localtime})
# fallback directories
- @attributes['stylesdir'] ||= '.'
- @attributes['iconsdir'] ||= File.join(@attributes.fetch('imagesdir', './images'), 'icons')
+ attrs['stylesdir'] ||= '.'
+ attrs['iconsdir'] ||= ::File.join(attrs.fetch('imagesdir', './images'), 'icons')
@extensions = if initialize_extensions
registry = if (ext_registry = options[:extensions_registry])
@@ -338,31 +338,54 @@ class Document < AbstractBlock
(::RUBY_ENGINE_JRUBY && (ext_registry.is_a? ::AsciidoctorJ::Extensions::ExtensionRegistry))
ext_registry
end
- elsif (ext_block = options[:extensions]) && (ext_block.is_a? ::Proc)
+ elsif (ext_block = options[:extensions]).is_a? ::Proc
Extensions.build_registry(&ext_block)
end
(registry ||= Extensions::Registry.new).activate self
end
- @reader = PreprocessorReader.new self, data, Reader::Cursor.new(@attributes['docfile'], @base_dir)
+ @reader = PreprocessorReader.new self, data, Reader::Cursor.new(attrs['docfile'], @base_dir)
+ parse if data && options[:parse]
+ end
+ end
+
+ # Public: Parse the AsciiDoc source stored in the {Reader} into an abstract syntax tree.
+ #
+ # If the data parameter is not nil, create a new {PreprocessorReader} and assigned it to the reader
+ # property of this object. Otherwise, continue with the reader that was created in {#initialize}.
+ # Pass the reader to {Parser.parse} to parse the source data into an abstract syntax tree.
+ #
+ # If parsing has already been performed, this method returns without performing any processing.
+ #
+ # data - The optional replacement AsciiDoc source data as a String or String Array. (default: nil)
+ #
+ # Returns this [Document]
+ def parse data = nil
+ unless @parsed
+ # create reader if data is provided (used when data is not known at the time the Document object is created)
+ @reader = PreprocessorReader.new self, data, Reader::Cursor.new(@attributes['docfile'], @base_dir) if data
- if @extensions && @extensions.preprocessors?
- @extensions.preprocessors.each do |ext|
+ if (exts = @parent_document ? nil : @extensions) && exts.preprocessors?
+ exts.preprocessors.each do |ext|
@reader = ext.process_method[self, @reader] || @reader
end
end
- end
- # Now parse the lines in the reader into blocks
- Parser.parse @reader, self, :header_only => !!options[:parse_header_only]
+ # Now parse the lines in the reader into blocks
+ Parser.parse @reader, self, :header_only => !!@options[:parse_header_only]
- @callouts.rewind
+ # should we call rewind in some sort of post-parse function?
+ @callouts.rewind
- if @extensions && !@parent_document && @extensions.treeprocessors?
- @extensions.treeprocessors.each do |ext|
- ext.process_method[self]
+ if exts && exts.treeprocessors?
+ exts.treeprocessors.each do |ext|
+ ext.process_method[self]
+ end
end
+
+ @parsed = true
end
+ self
end
# Public: Get the named counter and take the next number in the sequence.
@@ -372,7 +395,7 @@ class Document < AbstractBlock
#
# returns the next number in the sequence for the specified counter
def counter(name, seed = nil)
- if (attr_is_seed = !(attr_val = @attributes[name]).nil_or_empty?) && @counters.has_key?(name)
+ if (attr_is_seed = !(attr_val = @attributes[name]).nil_or_empty?) && @counters.key?(name)
@counters[name] = nextval(attr_val)
else
if seed.nil?
@@ -436,7 +459,7 @@ class Document < AbstractBlock
end
def footnotes?
- not @references[:footnotes].empty?
+ !@references[:footnotes].empty?
end
def footnotes
@@ -449,7 +472,7 @@ class Document < AbstractBlock
def embedded?
# QUESTION should this be !@options[:header_footer] ?
- @attributes.has_key? 'embedded'
+ @attributes.key? 'embedded'
end
def extensions?
@@ -521,15 +544,15 @@ class Document < AbstractBlock
end
def notitle
- !@attributes.has_key?('showtitle') && @attributes.has_key?('notitle')
+ !@attributes.key?('showtitle') && @attributes.key?('notitle')
end
def noheader
- @attributes.has_key? 'noheader'
+ @attributes.key? 'noheader'
end
def nofooter
- @attributes.has_key? 'nofooter'
+ @attributes.key? 'nofooter'
end
# QUESTION move to AbstractBlock?
@@ -578,14 +601,12 @@ class Document < AbstractBlock
@attributes['numbered'] = '' unless attribute_locked?('numbered') || @attributes_modified.include?('numbered')
end
- unless @attributes.has_key?('doctitle') || !(val = doctitle)
+ unless @attributes.key?('doctitle') || !(val = doctitle)
@attributes['doctitle'] = val
end
# css-signature cannot be updated after header attributes are processed
- if !@id && @attributes.has_key?('css-signature')
- @id = @attributes['css-signature']
- end
+ @id = @attributes['css-signature'] unless @id
toc_val = @attributes['toc']
toc2_val = @attributes['toc2']
@@ -627,7 +648,7 @@ class Document < AbstractBlock
FLEXIBLE_ATTRIBUTES.each do |name|
# turning a flexible attribute off should be permanent
# (we may need more config if that's not always the case)
- if @attribute_overrides.has_key?(name) && !@attribute_overrides[name].nil?
+ if @attribute_overrides.key?(name) && !@attribute_overrides[name].nil?
@attribute_overrides.delete(name)
end
end
@@ -647,8 +668,8 @@ class Document < AbstractBlock
# Internal: Replay attribute assignments at the block level
def playback_attributes(block_attributes)
- if (entries = block_attributes[:attribute_entries])
- entries.each do |entry|
+ if block_attributes.key? :attribute_entries
+ block_attributes[:attribute_entries].each do |entry|
if entry.negate
@attributes.delete(entry.name)
else
@@ -709,7 +730,7 @@ class Document < AbstractBlock
#
# Returns true if the attribute is locked, false otherwise
def attribute_locked?(name)
- @attribute_overrides.has_key?(name)
+ @attribute_overrides.key?(name)
end
# Internal: Apply substitutions to the attribute value
@@ -832,7 +853,7 @@ class Document < AbstractBlock
converter_opts[:eruby] = @options[:eruby]
end
converter_factory = if (converter = @options[:converter])
- Converter::Factory.new Hash[backend, converter]
+ Converter::Factory.new ::Hash[backend, converter]
else
Converter::Factory.default false
end
@@ -847,6 +868,7 @@ class Document < AbstractBlock
# or a template is missing, the converter will fall back to
# using the appropriate built-in template.
def convert opts = {}
+ parse unless @parsed
restore_attributes
# QUESTION should we add processors that execute before conversion begins?
@@ -863,9 +885,9 @@ class Document < AbstractBlock
output = @converter.convert self, transform
end
- if @extensions && !@parent_document
- if @extensions.postprocessors?
- @extensions.postprocessors.each do |ext|
+ unless @parent_document
+ if (exts = @extensions) && exts.postprocessors?
+ exts.postprocessors.each do |ext|
output = ext.process_method[self, output]
end
end
@@ -947,9 +969,9 @@ class Document < AbstractBlock
content = nil
- docinfo = @attributes.has_key?('docinfo')
- docinfo1 = @attributes.has_key?('docinfo1')
- docinfo2 = @attributes.has_key?('docinfo2')
+ docinfo = @attributes.key?('docinfo')
+ docinfo1 = @attributes.key?('docinfo1')
+ docinfo2 = @attributes.key?('docinfo2')
docinfo_filename = "docinfo#{qualifier}#{ext}"
if docinfo1 || docinfo2
docinfo_path = normalize_system_path(docinfo_filename)
@@ -961,7 +983,7 @@ class Document < AbstractBlock
end
end
- if (docinfo || docinfo2) && @attributes.has_key?('docname')
+ if (docinfo || docinfo2) && @attributes.key?('docname')
docinfo_path = normalize_system_path("#{@attributes['docname']}-#{docinfo_filename}")
content2 = read_asset(docinfo_path)
unless content2.nil?