"Fossies" - the Fresh Open Source Software Archive

Member "asciidoctor-2.0.10/lib/asciidoctor/section.rb" (1 Jun 2019, 7328 Bytes) of package /linux/www/asciidoctor-2.0.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Ruby source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 # frozen_string_literal: true
    2 module Asciidoctor
    3 # Public: Methods for managing sections of AsciiDoc content in a document.
    4 # The section responds as an Array of content blocks by delegating
    5 # block-related methods to its @blocks Array.
    6 #
    7 # Examples
    8 #
    9 #   section = Asciidoctor::Section.new
   10 #   section.title = 'Section 1'
   11 #   section.id = 'sect1'
   12 #
   13 #   section.size
   14 #   => 0
   15 #
   16 #   section.id
   17 #   => "sect1"
   18 #
   19 #   section << new_block
   20 #   section.size
   21 #   => 1
   22 class Section < AbstractBlock
   23 
   24   # Public: Get/Set the 0-based index order of this section within the parent block
   25   attr_accessor :index
   26 
   27   # Public: Get/Set the section name of this section
   28   attr_accessor :sectname
   29 
   30   # Public: Get/Set the flag to indicate whether this is a special section or a child of one
   31   attr_accessor :special
   32 
   33   # Public: Get/Set the flag to indicate whether this section should be numbered.
   34   # The sectnum method should only be called if this flag is true.
   35   attr_accessor :numbered
   36 
   37   # Public: Get the caption for this section (only relevant for appendices)
   38   attr_reader :caption
   39 
   40   # Public: Initialize an Asciidoctor::Section object.
   41   #
   42   # parent   - The parent AbstractBlock. If set, must be a Document or Section object (default: nil)
   43   # level    - The Integer level of this section (default: 1 more than parent level or 1 if parent not defined)
   44   # numbered - A Boolean indicating whether numbering is enabled for this Section (default: false)
   45   # opts     - An optional Hash of options (default: {})
   46   def initialize parent = nil, level = nil, numbered = false, opts = {}
   47     super parent, :section, opts
   48     if Section === parent
   49       @level, @special = level || (parent.level + 1), parent.special
   50     else
   51       @level, @special = level || 1, false
   52     end
   53     @numbered = numbered
   54     @index = 0
   55   end
   56 
   57   # Public: The name of this section, an alias of the section title
   58   alias name title
   59 
   60   # Public: Generate a String ID from the title of this section.
   61   #
   62   # See Section.generate_id for details.
   63   def generate_id
   64     Section.generate_id title, @document
   65   end
   66 
   67   # Public: Get the section number for the current Section
   68   #
   69   # The section number is a dot-separated String that uniquely describes the position of this
   70   # Section in the document. Each entry represents a level of nesting. The value of each entry is
   71   # the 1-based outline number of the Section amongst its numbered sibling Sections.
   72   #
   73   # This method assumes that both the @level and @parent instance variables have been assigned.
   74   # The method also assumes that the value of @parent is either a Document or Section.
   75   #
   76   # delimiter - the delimiter to separate the number for each level
   77   # append    - the String to append at the end of the section number
   78   #             or Boolean to indicate the delimiter should not be
   79   #             appended to the final level
   80   #             (default: nil)
   81   #
   82   # Examples
   83   #
   84   #   sect1 = Section.new(document)
   85   #   sect1.level = 1
   86   #   sect1_1 = Section.new(sect1)
   87   #   sect1_1.level = 2
   88   #   sect1_2 = Section.new(sect1)
   89   #   sect1_2.level = 2
   90   #   sect1 << sect1_1
   91   #   sect1 << sect1_2
   92   #   sect1_1_1 = Section.new(sect1_1)
   93   #   sect1_1_1.level = 3
   94   #   sect1_1 << sect1_1_1
   95   #
   96   #   sect1.sectnum
   97   #   # => 1.
   98   #
   99   #   sect1_1.sectnum
  100   #   # => 1.1.
  101   #
  102   #   sect1_2.sectnum
  103   #   # => 1.2.
  104   #
  105   #   sect1_1_1.sectnum
  106   #   # => 1.1.1.
  107   #
  108   #   sect1_1_1.sectnum(',', false)
  109   #   # => 1,1,1
  110   #
  111   # Returns the section number as a String
  112   def sectnum(delimiter = '.', append = nil)
  113     append ||= (append == false ? '' : delimiter)
  114     @level > 1 && Section === @parent ? %(#{@parent.sectnum(delimiter, delimiter)}#{@numeral}#{append}) : %(#{@numeral}#{append})
  115   end
  116 
  117   # (see AbstractBlock#xreftext)
  118   def xreftext xrefstyle = nil
  119     if (val = reftext) && !val.empty?
  120       val
  121     elsif xrefstyle
  122       if @numbered
  123         case xrefstyle
  124         when 'full'
  125           if (type = @sectname) == 'chapter' || type == 'appendix'
  126             quoted_title = sub_placeholder (sub_quotes '_%s_'), title
  127           else
  128             quoted_title = sub_placeholder (sub_quotes @document.compat_mode ? %q(``%s'') : '"`%s`"'), title
  129           end
  130           if (signifier = @document.attributes[%(#{type}-refsig)])
  131             %(#{signifier} #{sectnum '.', ','} #{quoted_title})
  132           else
  133             %(#{sectnum '.', ','} #{quoted_title})
  134           end
  135         when 'short'
  136           if (signifier = @document.attributes[%(#{@sectname}-refsig)])
  137             %(#{signifier} #{sectnum '.', ''})
  138           else
  139             sectnum '.', ''
  140           end
  141         else # 'basic'
  142           (type = @sectname) == 'chapter' || type == 'appendix' ? (sub_placeholder (sub_quotes '_%s_'), title) : title
  143         end
  144       else # apply basic styling
  145         (type = @sectname) == 'chapter' || type == 'appendix' ? (sub_placeholder (sub_quotes '_%s_'), title) : title
  146       end
  147     else
  148       title
  149     end
  150   end
  151 
  152   # Public: Append a content block to this block's list of blocks.
  153   #
  154   # If the child block is a Section, assign an index to it.
  155   #
  156   # block - The child Block to append to this parent Block
  157   #
  158   # Returns The parent Block
  159   def << block
  160     assign_numeral block if block.context == :section
  161     super
  162   end
  163 
  164   def to_s
  165     if @title
  166       formal_title = @numbered ? %(#{sectnum} #{@title}) : @title
  167       %(#<#{self.class}@#{object_id} {level: #{@level}, title: #{formal_title.inspect}, blocks: #{@blocks.size}}>)
  168     else
  169       super
  170     end
  171   end
  172 
  173   # Public: Generate a String ID from the given section title.
  174   #
  175   # The generated ID is prefixed with value of the 'idprefix' attribute, which
  176   # is an underscore (_) by default. Invalid characters are then removed and
  177   # spaces are replaced with the value of the 'idseparator' attribute, which is
  178   # an underscore (_) by default.
  179   #
  180   # If the generated ID is already in use in the document, a count is appended,
  181   # offset by the separator, until a unique ID is found.
  182   #
  183   # Section ID generation can be disabled by unsetting the 'sectids' document attribute.
  184   #
  185   # Examples
  186   #
  187   #   Section.generate_id 'Foo', document
  188   #   => "_foo"
  189   #
  190   # Returns the generated [String] ID.
  191   def self.generate_id title, document
  192     attrs = document.attributes
  193     pre = attrs['idprefix'] || '_'
  194     if (sep = attrs['idseparator'])
  195       if sep.length == 1 || (!(no_sep = sep.empty?) && (sep = attrs['idseparator'] = sep.chr))
  196         sep_sub = sep == '-' || sep == '.' ? ' .-' : %( #{sep}.-)
  197       end
  198     else
  199       sep, sep_sub = '_', ' _.-'
  200     end
  201     gen_id = %(#{pre}#{title.downcase.gsub InvalidSectionIdCharsRx, ''})
  202     if no_sep
  203       gen_id = gen_id.delete ' '
  204     else
  205       # replace space with separator and remove repeating and trailing separator characters
  206       gen_id = gen_id.tr_s sep_sub, sep
  207       gen_id = gen_id.chop if gen_id.end_with? sep
  208       # ensure id doesn't begin with idseparator if idprefix is empty (assuming idseparator is not empty)
  209       gen_id = gen_id.slice 1, gen_id.length if pre.empty? && (gen_id.start_with? sep)
  210     end
  211     if document.catalog[:refs].key? gen_id
  212       ids = document.catalog[:refs]
  213       cnt = Compliance.unique_id_start_index
  214       cnt += 1 while ids[candidate_id = %(#{gen_id}#{sep}#{cnt})]
  215       candidate_id
  216     else
  217       gen_id
  218     end
  219   end
  220 end
  221 end