LoginSignup
0
1

More than 3 years have passed since last update.

AsciiDocの表(Table)のセル属性の指定方法の仕様&Asciidoctorの内部実装について調べてみた

Last updated at Posted at 2021-01-04

AsciiDocの表(Table)のcols属性の仕様&Asciidoctorの内部実装について調べてみた のセル版。

参考サイト1 Asciidoctor User Manual #cell に割と詳しく書いてありそう。

セル結合の記述例

セル(|で始まる)の直で指定する。下記の例でいうと、.2+^.^3+^ の部分。

AsciiDoc

[options="header"]
|===
      |Date          |Duration | Location | Plan
.2+^.^|2021.01.04    |08:00    | XXX      | game
                     |09:00    | YYY      | coding
      |2021.01.05    |08:00    | XXX      | no plan
      |2021.01.06 3+^| work
|===

出力は下記のようになる。
image.png

内部実装を追う

parser.rb の self.parse_tableメソッドから呼ばれている parse_cellspecメソッド

parser.rb(抜粋&行番号補足)

# Internal: Parse the cell specs for the current cell.
#
# The cell specs dictate the cell's alignments, styles or filters,
# colspan, rowspan and/or repeating content.
#
# The default spec when pos == :end is {} since we already know we're at a
# delimiter. When pos == :start, we *may* be at a delimiter, nil indicates
# we're not.
#
# returns the Hash of attributes that indicate how to layout
# and style this cell in the table.
def self.parse_cellspec(line, pos = :end, delimiter = nil)             #  1
  m, rest = nil, ''                                                    #  2
                                                                       #  3
  if pos == :start                                                     #  4
    if line.include? delimiter                                         #  5
      spec_part, delimiter, rest = line.partition delimiter            #  6
      if (m = CellSpecStartRx.match spec_part)                         #  7
        return [{}, rest] if m[0].empty?                               #  8
      else                                                             #  9
        return [nil, line]                                             # 10
      end                                                              # 11
    else                                                               # 12
      return [nil, line]                                               # 13
    end                                                                # 14
  else # pos == :end                                                   # 15
    if (m = CellSpecEndRx.match line)                                  # 16
      # NOTE return the line stripped of trailing whitespace if no cellspec is found in this case # 17
      return [{}, line.rstrip] if m[0].lstrip.empty?                   # 18
      rest = m.pre_match                                               # 19
    else                                                               # 20
      return [{}, line]                                                # 21
    end                                                                # 22
  end                                                                  # 23
                                                                       # 24
  spec = {}                                                            # 25
  if m[1]                                                              # 26
    colspec, rowspec = m[1].split '.'                                  # 27
    colspec = colspec.nil_or_empty? ? 1 : colspec.to_i                 # 28
    rowspec = rowspec.nil_or_empty? ? 1 : rowspec.to_i                 # 29
    if m[2] == '+'                                                     # 30
      spec['colspan'] = colspec unless colspec == 1                    # 31
      spec['rowspan'] = rowspec unless rowspec == 1                    # 32
    elsif m[2] == '*'                                                  # 33
      spec['repeatcol'] = colspec unless colspec == 1                  # 34
    end                                                                # 35
  end                                                                  # 36
                                                                       # 37
  if m[3]                                                              # 38
    colspec, rowspec = m[3].split '.'                                  # 39
    if !colspec.nil_or_empty? && TableCellHorzAlignments.key?(colspec) # 40
      spec['halign'] = TableCellHorzAlignments[colspec]                # 41
    end                                                                # 42
    if !rowspec.nil_or_empty? && TableCellVertAlignments.key?(rowspec) # 43
      spec['valign'] = TableCellVertAlignments[rowspec]                # 44
    end                                                                # 45
  end                                                                  # 46
                                                                       # 47
  if m[4] && TableCellStyles.key?(m[4])                                # 48
    spec['style'] = TableCellStyles[m[4]]                              # 49
  end                                                                  # 50
                                                                       # 51
  [spec, rest]                                                         # 52
end                                                                    # 53

7行目および16行目でマッチング処理をしている。使用している正規表現は下記。

rx.rb(抜粋&コメント一部省略&補足)

# Examples
#   2.3+<.>m
#                            m[1]                         m[2]    m[3]                                    m[4]
#                            <---------------------------><---->  <-------------------------------------> <----->
CellSpecStartRx = /^[ \t]*(?:(\d+(?:\.\d*)?|(?:\d*\.)?\d+)([*+]))?([<^>](?:\.[<^>]?)?|(?:[<^>]?\.)?[<^>])?([a-z])?$/
CellSpecEndRx   =  /[ \t]+(?:(\d+(?:\.\d*)?|(?:\d*\.)?\d+)([*+]))?([<^>](?:\.[<^>]?)?|(?:[<^>]?\.)?[<^>])?([a-z])?$/

CellSpecStartRxは行頭用、CellSpecEndRxはそれ以外用っぽい。

  • m[1]m[2]:整数 . 整数 + の場合・・・ 結合する列数(横方向)と結合する行数(縦方向)。
    .以降を省略可。もしくは、.の前を省略することもできる。
  • m[1]m[2]:整数 * の場合・・・ 指定した列数だけ同じセルを繰り返す(参考サイト1参照)。
  • m[3]:横方向(<or^or>) . 縦方向(<or^or>)・・・ アライメント 横(左寄せ、中央寄せ、右寄せ) と 縦(上寄せ、中央寄せ、下寄せ)。
    .以降を省略可。もしくは、.の前を省略することもできる。
  • m[4]:文字・・・書式指定

参考サイト

  1. Asciidoctor User Manual #cell
  2. AsciiDoc cheatsheet
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1