# frozen_string_literal: truemoduleAsciidoctor# Public: Methods for managing sections of AsciiDoc content in a document.# The section responds as an Array of content blocks by delegating# block-related methods to its @blocks Array.## Examples## section = Asciidoctor::Section.new# section.title = 'Section 1'# section.id = 'sect1'## section.size# => 0## section.id# => "sect1"## section << new_block# section.size# => 1classSection<AbstractBlock# Public: Get/Set the 0-based index order of this section within the parent blockattr_accessor:index# Public: Get/Set the section name of this sectionattr_accessor:sectname# Public: Get/Set the flag to indicate whether this is a special section or a child of oneattr_accessor:special# Public: Get/Set the flag to indicate whether this section should be numbered.# The sectnum method should only be called if this flag is true.attr_accessor:numbered# Public: Get the caption for this section (only relevant for appendices)attr_reader:caption# Public: Initialize an Asciidoctor::Section object.## parent - The parent AbstractBlock. If set, must be a Document or Section object (default: nil)# level - The Integer level of this section (default: 1 more than parent level or 1 if parent not defined)# numbered - A Boolean indicating whether numbering is enabled for this Section (default: false)# opts - An optional Hash of options (default: {})definitializeparent=nil,level=nil,numbered=false,opts={}superparent,:section,optsifSection===parent@level,@special=level||(parent.level+1),parent.specialelse@level,@special=level||1,falseend@numbered=numbered@index=0end# Public: The name of this section, an alias of the section titlealiasnametitle# Public: Generate a String ID from the title of this section.## See Section.generate_id for details.defgenerate_idSection.generate_idtitle,@documentend# Public: Check whether this Section has any child Section objects.## Returns A [Boolean] to indicate whether this Section has child Section objectsdefsections?@next_section_index>0end# Public: Get the section number for the current Section## The section number is a dot-separated String that uniquely describes the position of this# Section in the document. Each entry represents a level of nesting. The value of each entry is# the 1-based outline number of the Section amongst its numbered sibling Sections.## This method assumes that both the @level and @parent instance variables have been assigned.# The method also assumes that the value of @parent is either a Document or Section.## delimiter - the delimiter to separate the number for each level# append - the String to append at the end of the section number# or Boolean to indicate the delimiter should not be# appended to the final level# (default: nil)## Examples## sect1 = Section.new(document)# sect1.level = 1# sect1_1 = Section.new(sect1)# sect1_1.level = 2# sect1_2 = Section.new(sect1)# sect1_2.level = 2# sect1 << sect1_1# sect1 << sect1_2# sect1_1_1 = Section.new(sect1_1)# sect1_1_1.level = 3# sect1_1 << sect1_1_1## sect1.sectnum# # => 1.## sect1_1.sectnum# # => 1.1.## sect1_2.sectnum# # => 1.2.## sect1_1_1.sectnum# # => 1.1.1.## sect1_1_1.sectnum(',', false)# # => 1,1,1## Returns the section number as a Stringdefsectnum(delimiter='.',append=nil)append||=(append==false?'':delimiter)@level>1&&Section===@parent?%(#{@parent.sectnum(delimiter,delimiter)}#{@numeral}#{append}):%(#{@numeral}#{append})end# (see AbstractBlock#xreftext)defxreftextxrefstyle=nilif(val=reftext)&&!val.empty?valelsifxrefstyleif@numberedcasexrefstylewhen'full'if(type=@sectname)=='chapter'||type=='appendix'quoted_title=sub_placeholder(sub_quotes'_%s_'),titleelsequoted_title=sub_placeholder(sub_quotes@document.compat_mode?%q(``%s''):'"`%s`"'),titleendif(signifier=@document.attributes[%(#{type}-refsig)])%(#{signifier}#{sectnum'.',','}#{quoted_title})else%(#{sectnum'.',','}#{quoted_title})endwhen'short'if(signifier=@document.attributes[%(#{@sectname}-refsig)])%(#{signifier}#{sectnum'.',''})elsesectnum'.',''endelse# 'basic'(type=@sectname)=='chapter'||type=='appendix'?(sub_placeholder(sub_quotes'_%s_'),title):titleendelse# apply basic styling(type=@sectname)=='chapter'||type=='appendix'?(sub_placeholder(sub_quotes'_%s_'),title):titleendelsetitleendend# Public: Append a content block to this block's list of blocks.## If the child block is a Section, assign an index to it.## block - The child Block to append to this parent Block## Returns The parent Blockdef<<blockassign_numeralblockifblock.context==:sectionsuperenddefto_sif@titleformal_title=@numbered?%(#{sectnum}#{@title}):@title%(#<#{self.class}@#{object_id} {level: #{@level}, title: #{formal_title.inspect}, blocks: #{@blocks.size}}>)elsesuperendend# Public: Generate a String ID from the given section title.## The generated ID is prefixed with value of the 'idprefix' attribute, which# is an underscore (_) by default. Invalid characters are then removed and# spaces are replaced with the value of the 'idseparator' attribute, which is# an underscore (_) by default.## If the generated ID is already in use in the document, a count is appended,# offset by the separator, until a unique ID is found.## Section ID generation can be disabled by unsetting the 'sectids' document attribute.## Examples## Section.generate_id 'Foo', document# => "_foo"## Returns the generated [String] ID.defself.generate_idtitle,documentattrs=document.attributespre=attrs['idprefix']||'_'if(sep=attrs['idseparator'])ifsep.length==1||(!(no_sep=sep.empty?)&&(sep=attrs['idseparator']=sep.chr))sep_sub=sep=='-'||sep=='.'?' .-':%( #{sep}.-)endelsesep,sep_sub='_',' _.-'endgen_id=%(#{pre}#{title.downcase.gsubInvalidSectionIdCharsRx,''})ifno_sepgen_id=gen_id.delete' 'else# replace space with separator and remove repeating and trailing separator charactersgen_id=gen_id.tr_ssep_sub,sepgen_id=gen_id.chopifgen_id.end_with?sep# ensure id doesn't begin with idseparator if idprefix is empty (assuming idseparator is not empty)gen_id=gen_id.slice1,gen_id.lengthifpre.empty?&&(gen_id.start_with?sep)endifdocument.catalog[:refs].key?gen_idids=document.catalog[:refs]cnt=Compliance.unique_id_start_indexcnt+=1whileids[candidate_id=%(#{gen_id}#{sep}#{cnt})]candidate_idelsegen_idendendendend