Module: Coradoc::AsciiDoc::Transformer::TableCellBuilder

Defined in:
lib/coradoc/asciidoc/transformer/table_cell_builder.rb

Overview

Pure functions for parsing the cell-format prefix (‘2+^.^a`) and building a Model::TableCell from raw parser values.

Extracted from the Transformer god class. The format spec can come in two shapes from the parser — a Hash of named captures or a raw String from a capture group — and the layout/alignment/style parsing for each used to be inline in Transformer#build_table_cell.

Class Method Summary collapse

Class Method Details

.build(format, content) ⇒ Model::TableCell

Parameters:

  • format (Hash, String, Object, nil)

    Cell format from parser

  • content (Object)

    Cell content

Returns:



19
20
21
22
23
24
25
26
27
# File 'lib/coradoc/asciidoc/transformer/table_cell_builder.rb', line 19

def build(format, content)
  cell_opts = {}
  style = parse_format(format, cell_opts)

  unescaped_content = content.to_s.gsub(/\\([|!,:;])/, '\1')
  cell_opts[:content] = parse_inline_content(unescaped_content, style)

  Model::TableCell.new(**cell_opts)
end

.normalize_cell(cell) ⇒ Model::TableCell

Coerce a raw parser cell value into a TableCell. Used by TableLayout.group_cells_into_rows when it encounters cells that the parser emitted as Hashes or plain strings.

Parameters:

Returns:



34
35
36
37
38
39
40
41
42
43
# File 'lib/coradoc/asciidoc/transformer/table_cell_builder.rb', line 34

def normalize_cell(cell)
  case cell
  when Model::TableCell then cell
  when Hash
    content = cell[:text] || cell[:content] || ''
    Model::TableCell.new(content: parse_inline_content(content))
  else
    Model::TableCell.new(content: parse_inline_content(cell))
  end
end

.parse_block_content(text) ⇒ Array

Parse block-level AsciiDoc content (for ‘a’ style cells).

Parameters:

  • text (String, nil)

Returns:

  • (Array)


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/coradoc/asciidoc/transformer/table_cell_builder.rb', line 69

def parse_block_content(text)
  return [Model::TextElement.new(content: '')] if text.nil? || text.to_s.strip.empty?

  parser = Coradoc::AsciiDoc::Parser::Base.new
  text_str = text.to_s

  if /^(\*+|-+|\d+\.)/m.match?(text_str)
    list_match = text_str.match(/\n(\*+|-+|\d+\.)(.*)$/m)
    if list_match
      list_text = list_match[1] + list_match[2]
      begin
        ast = parser.list.parse(list_text)
        transformed = Transformer.new.apply(ast)

        before_list = text_str[0, list_match.begin(1) - 1].strip
        before_elements = []
        unless before_list.empty?
          begin
            before_ast = parser.text_any.parse(before_list)
            before_transformed = Transformer.new.apply(before_ast)
            before_array = before_transformed.is_a?(Array) ? before_transformed : [before_transformed]
            before_elements = [Model::TextElement.new(content: before_array)]
          rescue Parslet::ParseFailed
            before_elements = [Model::TextElement.new(content: before_list)]
          end
        end

        return before_elements + [transformed]
      rescue Parslet::ParseFailed
        # fall through to inline parsing
      end
    end
  end

  begin
    ast = parser.text_any.parse(text_str)
    transformed = Transformer.new.apply(ast)
    content_array = transformed.is_a?(Array) ? transformed : [transformed]
    [Model::TextElement.new(content: content_array)]
  rescue Parslet::ParseFailed
    [Model::TextElement.new(content: text_str)]
  end
end

.parse_format(format, cell_opts) ⇒ String?

Parse the cell-format prefix and populate cell_opts.

Parameters:

  • format (Hash, String, Object, nil)
  • cell_opts (Hash)

    Mutated in place

Returns:

  • (String, nil)

    The parsed style character



117
118
119
120
121
122
123
# File 'lib/coradoc/asciidoc/transformer/table_cell_builder.rb', line 117

def parse_format(format, cell_opts)
  if format.is_a?(Hash)
    parse_format_hash(format, cell_opts)
  elsif format.is_a?(String)
    parse_format_string(format, cell_opts)
  end
end

.parse_format_hash(format, cell_opts) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/coradoc/asciidoc/transformer/table_cell_builder.rb', line 125

def parse_format_hash(format, cell_opts)
  cell_opts[:colspan] = format[:colspan].to_i if format[:colspan]

  if format[:rowspan]
    rowspan_str = format[:rowspan].to_s.sub(/^\./, '')
    cell_opts[:rowspan] = rowspan_str.to_i if rowspan_str.match?(/^\d+$/)
  end

  cell_opts[:halign] = format[:halign].to_s if format[:halign]

  if format[:valign]
    valign_str = format[:valign].to_s.sub(/^\./, '')
    cell_opts[:valign] = valign_str if %w[< ^ >].include?(valign_str)
  end

  style = format[:style].to_s if format[:style]
  cell_opts[:style] = style
  cell_opts[:repeat] = true if format[:repeat]
  style
end

.parse_format_string(format_str, cell_opts) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/coradoc/asciidoc/transformer/table_cell_builder.rb', line 146

def parse_format_string(format_str, cell_opts)
  cell_opts[:colspan] = Regexp.last_match(1).to_i if format_str =~ /^(\d+)\+/
  cell_opts[:rowspan] = Regexp.last_match(1).to_i if format_str =~ /\.(\d+)/
  cell_opts[:halign] = Regexp.last_match(0) if format_str =~ /[<>^]/
  cell_opts[:valign] = Regexp.last_match(0)[1] if format_str =~ /\.[.^<>]/

  style = Regexp.last_match(0) if format_str =~ /[dsemalhv]/
  cell_opts[:style] = style

  cell_opts[:repeat] = true if format_str.include?('*')
  style
end

.parse_inline_content(text, style = nil) ⇒ Array<Model::TextElement>

Parse inline content from raw text for a cell.

Parameters:

  • text (String, nil)
  • style (String, nil) (defaults to: nil)

    ‘a’ (AsciiDoc), ‘l’ (literal), or nil

Returns:



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/coradoc/asciidoc/transformer/table_cell_builder.rb', line 49

def parse_inline_content(text, style = nil)
  return [Model::TextElement.new(content: '')] if text.nil? || text.to_s.strip.empty?

  return parse_block_content(text) if style == 'a'
  return [Model::TextElement.new(content: text.to_s)] if style == 'l'

  parser = Coradoc::AsciiDoc::Parser::Base.new
  begin
    ast = parser.text_any.parse(text.to_s)
    transformed = Transformer.new.apply(ast)
    content_array = transformed.is_a?(Array) ? transformed : [transformed]
    [Model::TextElement.new(content: content_array)]
  rescue Parslet::ParseFailed
    [Model::TextElement.new(content: text.to_s)]
  end
end