[RUBY] I checked the specification of cols attribute of AsciiDoc table & internal implementation of Asciidoctor

I tried to put together a cheat sheet for AsciiDoc's Table, but I was addicted to it, so I'll leave a note of it first.

Introduction --About the difference between AsciiDoc and Asciidoctor

I just understood (; ・ ∀ ・)

Quoted from AsciiDoc --Wikipedia:

A Ruby implementation of an AsciiDoc translator called "Asciidoctor" was announced on GitHub

Roughly summarized AsciiDoc = language specifications Asciidoctor = Software that processes AsciiDoc data (.adoc file) and converts it to HTML

Table attributes

Example



[grid="rows",format="csv"]
[options="header",cols="^,<,<s,<,>m"]

I found a lot of samples when I googled, but I couldn't find an exhaustive document, so I searched near the executable file and searched for the manual. As a result, I found such an adoc file (below), so I compiled (?) With asciidoctor. When I searched for GitHub, there was a document.

Excerpt from syntax.adoc [^ 1] below image.png

I can't find the explanation for colspec ... In the example, it corresponds to the contents of cols =" ^, <, <s, <,> m ".

And start investigating the internal implementation ...

I can't find the explanation of colspec, so I looked at the source. (The source is This on GitHub. If you have installed C: \ Ruby26-x64 \ lib \ ruby ​​\ gems \ 2.6.0 \ gems \ asciidoctor-2.0.12 \ lib \ asciidoctor \ It's around .)

Processing picking up'cols'

parser.rb (excerpt)



  def self.parse_table(table_reader, parent, attributes)
    :
    if (attributes.key? 'cols') && !(colspecs = parse_colspecs attributes['cols']).empty?
    :

parser.rb(Excerpt & Supplement)



                                                                                              # Line
def self.parse_colspecs records                                                                 #  1
  records = records.delete ' ' if records.include? ' '                                          #  2
  # check for deprecated syntax: single number, equal column spread                             #  3
  if records == records.to_i.to_s                                                               #  4
    return ::Array.new(records.to_i) { { 'width' => 1 } }                                       #  5
  end                                                                                           #  6
                                                                                                #  7
  specs = []                                                                                    #  8
  # NOTE -1 argument ensures we don't drop empty records                                        #  9
  ((records.include? ',') ? (records.split ',', -1) : (records.split ';', -1)).each do |record| # 10
    if record.empty?                                                                            # 11
      specs << { 'width' => 1 }                                                                 # 12
    # TODO might want to use scan rather than this mega-regexp                                  # 13
    elsif (m = ColumnSpecRx.match(record))                                                      # 14
    :

--In the 4th to 6th lines, the case where only the number of columns is specified like cols = 4 is processed. --From the 10th line onward, the case where the format is specified for each column such as cols =" ^, <, <s, <,> m " is processed.
If there is ,, it seems to be divided by ,, otherwise it seems to be divided by ;. --The 14th and subsequent lines will be examined in detail below.

Contents of parameters of'cols = "xxx, xxx, xxx"'xxx

First, check the regular expression ColumnSpecRx on the 14th line above.

rx.rb (excerpt & supplement)


#                   m[1]     m[2]                                    m[3]      m[4]
#                   <--->    <-------------------------------------> <-------> <----->
ColumnSpecRx = /^(?:(\d+)\*)?([<^>](?:\.[<^>]?)?|(?:[<^>]?\.)?[<^>])?(\d+%?|~)?([a-z])?$/

[Overview] Both can be omitted

--m [1]: integer * ・ ・ ・ Number of column repetitions --m [2]: Horizontal direction (< or^or>) . Vertical direction (< or^or>) ・ ・ ・ Alignment Horizontal (left justified, center justified, Right-justified) and vertical (top-justified, center-justified, bottom-justified).
. and later can be omitted. Alternatively, you can omit the part before .. --m [3]: integer% or ~ ・ ・ ・ Column width. % Can be omitted. --m [4]: ​​Character ・ ・ ・ Format specification

parser.rb(Excerpt & Supplement)



elsif (m = ColumnSpecRx.match(record))                                 # 14
  spec = {}                                                            # 15
  if m[2]                                                              # 16 m[2]
    # make this an operation                                           # 17
    colspec, rowspec = m[2].split '.'                                  # 18
    if !colspec.nil_or_empty? && TableCellHorzAlignments.key?(colspec) # 19
      spec['halign'] = TableCellHorzAlignments[colspec]                # 20
    end                                                                # 21
    if !rowspec.nil_or_empty? && TableCellVertAlignments.key?(rowspec) # 22
      spec['valign'] = TableCellVertAlignments[rowspec]                # 23
    end                                                                # 24
  end                                                                  # 25
                                                                       # 26
  if (width = m[3])                                                    # 27 m[3]
    # to_i will strip the optional %                                   # 28
    spec['width'] = width == '~' ? -1 : width.to_i                     # 29
  else                                                                 # 30
    spec['width'] = 1                                                  # 31
  end                                                                  # 32
                                                                       # 33
  # make this an operation                                             # 34
  if m[4] && TableCellStyles.key?(m[4])                                # 35 m[4]
    spec['style'] = TableCellStyles[m[4]]                              # 36
  end                                                                  # 37
                                                                       # 38
  if m[1]                                                              # 39 m[1]
    1.upto(m[1].to_i) { specs << spec.merge }                          # 40
  else                                                                 # 41
    specs << spec                                                      # 42
  end                                                                  # 43
end                                                                    # 44
:

Characters that can be used for alignment and formatting

parser.rb (excerpt)



  # Internal: A Hash mapping horizontal alignment abbreviations to alignments
  # that can be applied to a table cell (or to all cells in a column)
  TableCellHorzAlignments = {
    '<' => 'left',
    '>' => 'right',
    '^' => 'center'
  }

  # Internal: A Hash mapping vertical alignment abbreviations to alignments
  # that can be applied to a table cell (or to all cells in a column)
  TableCellVertAlignments = {
    '<' => 'top',
    '>' => 'bottom',
    '^' => 'middle'
  }

  # Internal: A Hash mapping styles abbreviations to styles that can be applied
  # to a table cell (or to all cells in a column)
  TableCellStyles = {
    'd' => :none,
    's' => :strong,
    'e' => :emphasis,
    'm' => :monospaced,
    'h' => :header,
    'l' => :literal,
    'a' => :asciidoc
  }

Sequel (I checked cell formatting)

Specification of cell attribute specification method of AsciiDoc table & I checked the internal implementation of Asciidoctor --Qiita

environment

Ruby 2.6.0 Asciidoctor 2.0.12

I don't remember Ruby because I installed it before I knew it. .. .. Asciidoctor was installed by referring to Asciidoctor installation procedure (Windows10).

In my environment, it is installed below. (Sources and manuals are also included.) C:\Ruby26-x64\lib\ruby\gems\2.6.0\gems\asciidoctor-2.0.12\

Reference site

[^ 1]: If installed, it is located around C: \ Ruby26-x64 \ lib \ ruby ​​\ gems \ 2.6.0 \ gems \ asciidoctor-2.0.12 \ data \ reference \ syntax.adoc .

Recommended Posts

I checked the specification of cols attribute of AsciiDoc table & internal implementation of Asciidoctor
I checked the specification of how to specify cell attributes of AsciiDoc table & internal implementation of Asciidoctor
I investigated the internal processing of Retrofit
I checked the place of concern of java.net.URL # getPath
I checked the number of taxis with Ruby
[Ruby] I want to reverse the order of the hash table
I checked the automatic unit test creation tool (end of 2019 version)
I want to change the value of Attribute in Selenium of Ruby