lib/asciidoctor/abstract_block.rb in asciidoctor-1.5.8 vs lib/asciidoctor/abstract_block.rb in asciidoctor-2.0.0.rc.1

- old
+ new

@@ -1,53 +1,59 @@ -# encoding: UTF-8 +# frozen_string_literal: true module Asciidoctor class AbstractBlock < AbstractNode - # Public: Get the Array of Asciidoctor::AbstractBlock sub-blocks for this block + # Public: Get the Array of {AbstractBlock} child blocks for this block. Only applies if content model is :compound. attr_reader :blocks - # Public: Set the caption for this block + # Public: Set the caption for this block. attr_writer :caption - # Public: The types of content that this block can accomodate + # Public: Describes the type of content this block accepts and how it should be converted. Acceptable values are: + # * :compound - this block contains other blocks + # * :simple - this block holds a paragraph of prose that receives normal substitutions + # * :verbatim - this block holds verbatim text (displayed "as is") that receives verbatim substitutions + # * :raw - this block holds unprocessed content passed directly to the output with no sustitutions applied + # * :empty - this block has no content attr_accessor :content_model - # Public: Set the Integer level of this Section or the Section level in which this Block resides + # Public: Set the Integer level of this {Section} or the level of the Section to which this {AbstractBlock} belongs. attr_accessor :level - # Public: Get/Set the numeral of this block (if section, relative to parent, otherwise absolute) - # Only assigned to section if automatic section numbering is enabled - # Only assigned to formal block (block with title) if corresponding caption attribute is present + # Public: Get/Set the numeral of this block (if section, relative to parent, otherwise absolute). + # Only assigned to section if automatic section numbering is enabled. + # Only assigned to formal block (block with title) if corresponding caption attribute is present. attr_accessor :numeral - # Deprecated: Legacy property to get/set the numeral of this block + # Deprecated: Legacy property to get/set the numeral of this block. alias number numeral alias number= numeral= - # Public: Gets/Sets the location in the AsciiDoc source where this block begins + # Public: Gets/Sets the location in the AsciiDoc source where this block begins. attr_accessor :source_location # Public: Get/Set the String style (block type qualifier) for this block. attr_accessor :style - # Public: Substitutions to be applied to content in this block + # Public: Substitutions to be applied to content in this block. attr_reader :subs + # Internal: Set the default subs applied to this block; used during block creation + attr_writer :default_subs + def initialize parent, context, opts = {} super @content_model = :compound @blocks = [] @subs = [] - @id = @title = @title_converted = @caption = @numeral = @style = @default_subs = @source_location = nil - if context == :document - @level = 0 - elsif parent && context != :section - @level = parent.level + @id = @title = @caption = @numeral = @style = @default_subs = @source_location = nil + case context + when :document, :section + @level = @next_section_index = 0 + @next_section_ordinal = 1 else - @level = nil + @level = AbstractBlock === parent ? parent.level : nil end - @next_section_index = 0 - @next_section_ordinal = 1 end def block? true end @@ -99,14 +105,14 @@ # # block - The new child block. # # Examples # - # block = Block.new(parent, :preamble, :content_model => :compound) + # block = Block.new(parent, :preamble, content_model: :compound) # - # block << Block.new(block, :paragraph, :source => 'p1') - # block << Block.new(block, :paragraph, :source => 'p2') + # block << Block.new(block, :paragraph, source: 'p1') + # block << Block.new(block, :paragraph, source: 'p2') # block.blocks? # # => true # block.blocks.size # # => 2 # @@ -168,60 +174,10 @@ result end alias query find_by - # Internal: Performs the work for find_by, but does not handle the StopIteration exception. - def find_by_internal selector = {}, result = [], &block - if ((any_context = !(context_selector = selector[:context])) || context_selector == @context) && - (!(style_selector = selector[:style]) || style_selector == @style) && - (!(role_selector = selector[:role]) || (has_role? role_selector)) && - (!(id_selector = selector[:id]) || id_selector == @id) - if id_selector - result.replace block_given? ? ((yield self) ? [self] : []) : [self] - raise ::StopIteration - elsif block_given? - if (verdict = yield self) - case verdict - when :skip_children - result << self - return result - when :skip - return result - else - result << self - end - end - else - result << self - end - end - - # process document header as a section if present - if @context == :document && (any_context || context_selector == :section) && header? - @header.find_by_internal selector, result, &block - end - - unless context_selector == :document # optimization - # yuck, dlist is a special case - if @context == :dlist - if any_context || context_selector != :section # optimization - @blocks.flatten.each do |li| - # NOTE the list item of a dlist can be nil, so we have to check - li.find_by_internal selector, result, &block if li - end - end - elsif - @blocks.each do |b| - next if (context_selector == :section && b.context != :section) # optimization - b.find_by_internal selector, result, &block - end - end - end - result - end - # Move to the next adjacent block in document order. If the current block is the last # item in a list, this method will return the following sibling of the list block. def next_adjacent_block (sib = (p = parent).blocks[(p.blocks.find_index self) + 1]) ? sib : p.next_adjacent_block unless @context == :document end @@ -232,16 +188,16 @@ # # Examples # # doc << (sect1 = Section.new doc, 1) # sect1.title = 'Section 1' - # para1 = Block.new sect1, :paragraph, :source => 'Paragraph 1' - # para2 = Block.new sect1, :paragraph, :source => 'Paragraph 2' + # para1 = Block.new sect1, :paragraph, source: 'Paragraph 1' + # para2 = Block.new sect1, :paragraph, source: 'Paragraph 2' # sect1 << para1 << para2 # sect1 << (sect1_1 = Section.new sect1, 2) # sect1_1.title = 'Section 1.1' - # sect1_1 << (Block.new sect1_1, :paragraph, :source => 'Paragraph 3') + # sect1_1 << (Block.new sect1_1, :paragraph, source: 'Paragraph 3') # sect1.blocks? # # => true # sect1.blocks.size # # => 3 # sect1.sections.size @@ -316,11 +272,11 @@ # => "Foo 3^ # :: Bar(1)" # # Returns the converted String title for this Block, or nil if the source title is falsy def title # prevent substitutions from being applied to title multiple times - @title_converted ? @converted_title : (@converted_title = (@title_converted = true) && @title && (apply_title_subs @title)) + @converted_title ||= @title && (apply_title_subs @title) end # Public: A convenience method that checks whether the title of this block is defined. # # Returns a [Boolean] indicating whether this block has a title. @@ -330,11 +286,12 @@ # Public: Set the String block title. # # Returns the new String title assigned to this Block def title= val - @title, @title_converted = val, nil + @converted_title = nil + @title = val end # Public: A convenience method that checks whether the specified # substitution is enabled for this block. # @@ -377,11 +334,11 @@ val # NOTE xrefstyle only applies to blocks with a title and a caption or number elsif xrefstyle && @title && @caption case xrefstyle when 'full' - quoted_title = sprintf sub_quotes(@document.compat_mode ? %q(``%s'') : '"`%s`"'), title + quoted_title = sub_placeholder (sub_quotes @document.compat_mode ? %q(``%s'') : '"`%s`"'), title if @numeral && (prefix = @document.attributes[@context == :image ? 'figure-caption' : %(#{@context}-caption)]) %(#{prefix} #{@numeral}, #{quoted_title}) else %(#{@caption.chomp '. '}, #{quoted_title}) end @@ -475,37 +432,71 @@ block.reindex_sections end end end -# stage the Enumerable mixin until we're sure we've got it right -=begin - include ::Enumerable - - # Public: Yield the block on this block node and all its descendant - # block node children to satisfy the Enumerable contract. - # - # Returns nothing - def each &block - # yucky, dlist is a special case - if @context == :dlist - @blocks.flatten.each &block + # Internal: Performs the work for find_by, but does not handle the StopIteration exception. + protected def find_by_internal selector = {}, result = [], &block + if ((any_context = (context_selector = selector[:context]) ? nil : true) || context_selector == @context) && + (!(style_selector = selector[:style]) || style_selector == @style) && + (!(role_selector = selector[:role]) || (has_role? role_selector)) && + (!(id_selector = selector[:id]) || id_selector == @id) + if id_selector + block_given? && !(yield self) ? result.clear : (result.replace [self]) + raise ::StopIteration + elsif block_given? + if (verdict = yield self) + case verdict + when :skip_children + result << self + return result + when :skip + return result + else + result << self + end + end + else + result << self + end + end + case @context + when :document + unless context_selector == :document + # process document header as a section, if present + if header? && (any_context || context_selector == :section) + @header.find_by_internal selector, result, &block + end + @blocks.each do |b| + next if (context_selector == :section && b.context != :section) # optimization + b.find_by_internal selector, result, &block + end + end + when :dlist + # dlist has different structure than other blocks + if any_context || context_selector != :section # optimization + # NOTE the list item of a dlist can be nil, so we have to check + @blocks.flatten.each {|b| b.find_by_internal selector, result, &block if b } + end + when :table + if selector[:traverse_documents] + rows.head.each {|r| r.each {|c| c.find_by_internal selector, result, &block } } + selector = selector.merge context: :document if context_selector == :inner_document + (rows.body + rows.foot).each do |r| + r.each do |c| + c.find_by_internal selector, result, &block + c.inner_document.find_by_internal selector, result, &block if c.style == :asciidoc + end + end + else + (rows.head + rows.body + rows.foot).each {|r| r.each {|c| c.find_by_internal selector, result, &block } } + end else - #yield self.header if @context == :document && header? - @blocks.each &block + @blocks.each do |b| + next if (context_selector == :section && b.context != :section) # optimization + b.find_by_internal selector, result, &block + end end + result end - - #-- - # TODO is there a way to make this lazy? - def each_recursive &block - block = lambda {|node| node } unless block_given? - results = [] - self.each do |node| - results << block.call(node) - results.concat(node.each_recursive(&block)) if ::Enumerable === node - end - block_given? ? results : results.to_enum - end -=end end end