class Mdextab::Mdextab

MarkDownテーブル拡張クラス

Public Class Methods

new(opt, fname, o_fname, mes=nil) click to toggle source

初期化

@param opt [Hash] オプション @option opt [Symbol] :debug Messagexクラスのインスタンスに与えるデバッグモード @param fname [String] 入力Markdownファイル名 @param o_fname [String] 出力Markdownファイル名 @param mes [Messagex] Messagexクラスのインスタンス

# File lib/mdextab.rb, line 37
def initialize(opt, fname, o_fname, mes=nil)
  @fname = fname
  @o_fname = o_fname

  @mes = mes
  unless @mes
    @mes = Messagex::Messagex.new("EXIT_CODE_NORMAL_EXIT", 0, opt[:debug])
    @mes.register_exc
  end

  @mes.add_exitcode("EXIT_CODE_NEXT_STATE")
  @mes.add_exitcode("EXIT_CODE_NIL")
  @mes.add_exitcode("EXIT_CODE_EXCEPTION")
  @mes.add_exitcode("EXIT_CODE_UNKNOWN")

  Filex::Filex.setup(@mes)

  unless File.exist?(fname)
    @mes.output_fatal("Can't find #{fname}")
    exit(@mes.ec("EXIT_CODE_CANNOT_FIND_FILE"))
  end

  dir = File.dirname(o_fname)
  if dir != "."
    @mes.exc_make_directory(dir) { FileUtils.mkdir_p(dir) }
  end
  @mes.exc_file_write(o_fname) { @output = File.open(o_fname, "w") }

  @token_op = Token.new(@mes)
  @layer = Layer.new(@mes, @output)

  set_state
end

Public Instance Methods

get_next_state(token, line, lineno) click to toggle source

テーブル拡張向け構文解析での次の状態を得る

@param token [Token] 読み込んだトークン @param line [String] トークン出現行 @param lineno [String] トークン出現行の行番号 @return [Symbol] テーブル拡張向け構文解析での次の状態

# File lib/mdextab.rb, line 139
def get_next_state(token, line, lineno)
  kind = token.kind
  @mes.output_debug("#{__LINE__}|@layer.cur_state=#{@layer.cur_state} #{@layer.cur_state.class}")
  state_level1 = @states[@layer.cur_state]
  if state_level1.nil?
    @mes.output_error(%Q(token.kind=#{kind} | cur_state=#{@layer.cur_state}))
    @mes.output_error("=== state_level1 == nil")
    @mes.output_fatal("Next State is nil")
    @mes.output_fatal("@fname=#{@fname} | lineno=#{lineno}")
    exit(@mes.ec("EXIT_CODE_NIL"))
  else
    @mes.output_debug("state_level1=#{state_level1}")
  end
  @mes.output_debug("#{__LINE__}|kind=#{kind}")

  begin
    next_state = state_level1[kind]
    @mes.output_debug("#{__LINE__}|next_state=#{next_state}")
  rescue StandardError
    @mes.output_fatal("@layer.cur_state=#{@layer.cur_state}")
    @mes.output_fatal("kind=#{kind}")
    @mes.output_fatal("next_state=#{next_state}")
    exit(@mes.ec("EXIT_CODE_EXCEPTION"))
  end
  @mes.output_debug("#{__LINE__}|next_state=#{next_state}")
  next_state
end
output_in_else(str) click to toggle source

トークンELSEに対応する行の出力

@param str [String] トークンELSEに対応する行 @return [void]

# File lib/mdextab.rb, line 172
def output_in_else(str)
  if @layer.star
    if str.match?(/^\s*$/)
      @mes.output_debug("InElse do nothing")
    else
      @mes.exc_file_write(@o_fname) { @output.puts(str) }
    end
  else
    @mes.exc_file_write(@o_fname) { @output.puts(str) }
  end
end
parse(hash) click to toggle source

テーブル拡張向け構文解析

@param hash [Hash] eRubyスクリプト向け置換用ハッシュ @return [void]

# File lib/mdextab.rb, line 93
def parse(hash)
  lineno = 0
  @layer.add_layer(@fname, lineno)
  Filex::Filex.check_and_expand_file_lines(@fname, hash, @mes).each do |line|
    lineno += 1
    token = @token_op.get_token(line, lineno)
    kind = token.kind

    @mes.output_debug("layer.size=#{@layer.size}")
    @mes.output_debug("token.kind=#{kind}")
    @mes.output_debug(%Q!(source)#{lineno}:#{line}!)
    if @layer.cur_state.nil?
      @mes.output_error("(script)#{__LINE__}| @layer.cur_state=nil")
    else
      @mes.output_debug("(script)#{__LINE__}| @layer.cur_state=#{@layer.cur_state}")
    end

    @layer.cur_state = process_one_line(@layer.cur_state, token, line, lineno)
    unless @layer.cur_state
      @mes.output_fatal("process_one_line returns nil")
      exit(@mes.ec("EXIT_CODE_NEXT_STATE"))
    end

    @mes.output_debug("NEXT kind=#{kind} @layer.cur_state=#{@layer.cur_state}")
    @mes.output_debug("-----")
  end
  @layer.check_layers(@fname)
end
parse2(yamlfname) click to toggle source

テーブル拡張向け構文解析

@param yamlfname [String] eRubyスクリプト向け置換用データファイル名(YAML形式) @return [void]

# File lib/mdextab.rb, line 127
def parse2(yamlfname)
  hs = Filex::Filex.check_and_load_yamlfile(yamlfname, @mes)
  parse(hs)
end
post_process() click to toggle source
# File lib/mdextab.rb, line 529
def post_process
  @output&.close
  @output = nil
end
process_one_line(current_state, token, line, lineno) click to toggle source

現在の状態に対するトークンとトークン出現行の処理

@param [Symbol] current_state 現在の状態 @param [Token] token 読み込んだトークン @param [String] line トークン出現行 @param [String] lineno トークン出現行の行番号 @return [void] テーブル拡張向け構文解析での次の状態

# File lib/mdextab.rb, line 493
def process_one_line(current_state, token, line, lineno)
  @layer.return_from_nested_layer = false

  case current_state
  when :START
    process_one_line_for_start(token, line, lineno)
  when :OUT_OF_TABLE
    process_one_line_for_out_of_table(token, line, lineno)
  when :IN_TABLE
    process_one_line_for_in_table(token, line, lineno)
  when :IN_TABLE_BODY
    process_one_line_for_in_table_body(token, line, lineno)
  when :IN_TH
    process_one_line_for_in_th(token, line, lineno)
  when :IN_TH_NO_TBODY
    process_one_line_for_in_th_no_tbody(token, line, lineno)
  when :IN_TD
    process_one_line_for_in_td(token, line, lineno)
  when :IN_TD_NO_TBODY
    process_one_line_for_in_td_no_tbody(token, line, lineno)
  else
    @mes.output_fatal("In Unknown state(#{current_state}) in process_one_line")
    @mes.output_fatal("@fname=#{@fname} | lineno=#{lineno}")
    exit(@mes.ec("EXIT_CODE_UNKNOWN"))
  end

  if @layer.return_from_nested_layer
    next_state = @layer.cur_state
  else
    next_state = get_next_state(token, line, lineno)

    @mes.output_debug("#{__LINE__}|next_state=#{next_state}")
  end
  next_state
end
process_one_line_for_in_table(token, line, lineno) click to toggle source

IN_TABLE状態でのトークンとトークン出現行の処理

@param token [Token] 読み込んだトークン @param line [String] トークン出現行 @param lineno [String] トークン出現行の行番号 @return [void]

# File lib/mdextab.rb, line 294
def process_one_line_for_in_table(token, line, lineno)
  case token.kind
  when :TBODY_START
    @layer.table.add_tbody(lineno)
  when :TABLE_END
    process_one_line_for_table_end(token)
  when :ELSE
    output_in_else(token.opt[:content])
  when :TD
    @mes.output_debug(token)
    @layer.table.add_tbody(lineno)
    @layer.table.add_td(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :TH
    @layer.table.add_tbody(lineno)
    @layer.table.add_th(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :TABLE_START
    @layer.process_nested_table_start(token, lineno, @fname)
  when :STAR_START
    @layer.star = true
    output_in_else("*" + token.opt[:content])
  when :STAR_END
    @layer.star = false
    output_in_else("*" + token.opt[:content])
  else
    @mes.output_fatal("In :IN_TABLE unknown tag=(#{token.kind}) in process_one_line_for_in_table")
    @mes.output_fatal("@fname=#{@fname} | lineno=#{lineno}")
    exit(@mes.ec("EXIT_CODE_UNKNOWN"))
  end
end
process_one_line_for_in_table_body(token, line, lineno) click to toggle source

IN_TABLE_BODY状態でのトークンとトークン出現行の処理

@param token [Token] 読み込んだトークン @param line [String] トークン出現行 @param lineno [String] トークン出現行の行番号 @return [void]

# File lib/mdextab.rb, line 331
def process_one_line_for_in_table_body(token, line, lineno)
  case token.kind
  when :TH
    @layer.table.add_th(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :TD
    @mes.output_debug(token)
    @layer.table.add_td(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :ELSE
    output_in_else(token.opt[:content])
  when :TABLE_START
    @layer.process_nested_table_start(token, lineno, @fname)
  when :TBODY_END
    true #  don't call process_table_end(token)
  when :TABLE_END
    process_one_line_for_table_end(token)
  when :STAR_START
    @layer.star = true
    output_in_else("*" + token.opt[:content])
  when :STAR_END
    @layer.star = false
    output_in_else("*" + token.opt[:content])
  else
    @mes.output_fatal("In :IN_TABLE_BODY unknown tag=(#{token.kind}) in process_one_line_for_in_table_body")
    @mes.output_fatal("@fname=#{@fname} | lineno=#{lineno}")
    exit(@mes.ec("EXIT_CODE_UNKNOWN"))
  end
end
process_one_line_for_in_td(token, line, lineno) click to toggle source

IN_TD状態でのトークンとトークン出現行の処理

@param token [Token] 読み込んだトークン @param line [String] トークン出現行 @param lineno [String] トークン出現行の行番号 @return [void]

# File lib/mdextab.rb, line 426
def process_one_line_for_in_td(token, line, lineno)
  case token.kind
  when :ELSE
    table_td_append_in_else(token.opt[:content])
  when :TH
    @layer.table.add_th(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :TD
    @layer.table.add_td(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :TBODY_END
    @layer.table.tbody_end
  when :TABLE_START
    @layer.process_nested_table_start(token, lineno, @fname)
  when :STAR_START
    @layer.star = true
    table_td_append_in_else("*" + token.opt[:content])
  when :STAR_END
    @layer.star = false
    table_td_append_in_else("*" + token.opt[:content])
  else
    @mes.output_fatal("In :IN_TD unknown tag=(#{token.kind}) in process_one_line_for_in_td")
    @mes.output_fatal("@fname=#{@fname} | lineno=#{lineno}")
    exit(@mes.ec("EXIT_CODE_UNKNOWN"))
  end
end
process_one_line_for_in_td_no_tbody(token, line, lineno) click to toggle source

IN_TD_NO_TBODY状態でのトークンとトークン出現行の処理

@param token [Token] 読み込んだトークン @param line [String] トークン出現行 @param lineno [String] トークン出現行の行番号 @return [void]

# File lib/mdextab.rb, line 458
def process_one_line_for_in_td_no_tbody(token, line, lineno)
  case token.kind
  when :ELSE
    table_td_append_in_else(token.opt[:content])
  when :TH
    @layer.table.add_th(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :TD
    @layer.table.add_td(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :TABLE_START
    @layer.process_nested_table_start(token, lineno, @fname)
  when :TABLE_END
    process_one_line_for_table_end(token)
  when :TBODY_END
    @layer.table.tbody_end
  when :STAR_START
    @layer.star = true
    table_td_append_in_else("*" + token.opt[:content])
  when :STAR_END
    @layer.star = false
    table_td_append_in_else("*" + token.opt[:content])
  else
    @mes.output_fatal("In :IN_TD_NO_TBODY unknown tag=(#{token.kind}) in process_one_line_for_in_td_no_tbody")
    @mes.output_fatal("@fname=#{@fname} | lineno=#{lineno}")
    exit(@mes.ec("EXIT_CODE_UNKNOWN"))
  end
end
process_one_line_for_in_th(token, line, lineno) click to toggle source

IN_TH状態でのトークンとトークン出現行の処理

@param token [Token] 読み込んだトークン @param line [String] トークン出現行 @param lineno [String] トークン出現行の行番号 @return [void]

# File lib/mdextab.rb, line 366
def process_one_line_for_in_th(token, line, lineno)
  case token.kind
  when :ELSE
    table_th_append_in_else(token.opt[:content])
  when :TH
    @layer.table.add_th(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :TD
    @layer.table.add_td(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :TABLE_START
    @layer.process_nested_table_start(token, lineno, @fname)
  when :STAR_START
    @layer.star = true
    table_th_append_in_else("*" + token.opt[:content])
  when :STAR_END
    @layer.star = false
    table_th_append_in_else("*" + token.opt[:content])
  else
    @mes.output_fatal("In :IN_TH unknown tag=(#{token.kind}) in process_one_line_for_in_th")
    @mes.output_fatal("@fname=#{@fname} | lineno=#{lineno}")
    exit(@mes.ec("EXIT_CODE_UNKNOWN"))
  end
end
process_one_line_for_in_th_no_tbody(token, line, lineno) click to toggle source

IN_TH_NO_TBODY状態でのトークンとトークン出現行の処理

@param token [Token] 読み込んだトークン @param line [String] トークン出現行 @param lineno [String] トークン出現行の行番号 @return [void]

# File lib/mdextab.rb, line 396
def process_one_line_for_in_th_no_tbody(token, line, lineno)
  case token.kind
  when :ELSE
    table_th_append_in_else(token.opt[:content])
  when :TH
    @layer.table.add_th(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :TD
    @layer.table.add_td(lineno, token.opt[:content], token.opt[:nth], token.opt[:attr], @layer.star)
  when :TABLE_START
    @layer.process_nested_table_start(token, lineno, @fname)
  when :STAR_START
    @layer.star = true
    table_th_append_in_else("*" + token.opt[:content])
  when :STAR_END
    @layer.star = false
    table_th_append_in_else("*" + token.opt[:content])
  else
    @mes.output_fatal("In :IN_TH_NO_TBODY unknown tag=(#{token.kind}) in process_one_line_for_in_th_no_tbody")
    @mes.output_fatal("@fname=#{@fname} | lineno=#{lineno}")
    exit(@mes.ec("EXIT_CODE_UNKNOWN"))
  end
end
process_one_line_for_out_of_table(token, line, lineno) click to toggle source

OUT_OF_TABLE状態でのトークンとトークン出現行の処理

@param token [Token] 読み込んだトークン @param line [String] トークン出現行 @param lineno [String] トークン出現行の行番号 @return [void]

# File lib/mdextab.rb, line 252
def process_one_line_for_out_of_table(token, line, lineno)
  case token.kind
  when :TABLE_START
    @layer.table = Table.new(lineno, @mes, token.opt[:attr])
  when :ELSE
    output_in_else(token.opt[:content])
  when :STAR_START
    @layer.star = true
    output_in_else("*" + token.opt[:content])
  when :STAR_END
    @layer.star = false
    output_in_else(token.opt[:content])
  when :TD
    # treat as :ELSE
    output_in_else(":" + token.opt[:content])
  else
    @mes.output_fatal("In :OUT_OF_TABLE unknown tag=(#{token.kind}) in process_one_line_for_out_of_table")
    @mes.output_fatal("@fname=#{@fname} | lineno=#{lineno}")
    @layer.check_layers(@fname)
  end
end
process_one_line_for_start(token, line, lineno) click to toggle source

START状態でのトークンとトークン出現行の処理

@param token [Token] 読み込んだトークン @param line [String] トークン出現行 @param lineno [String] トークン出現行の行番号 @return [void]

# File lib/mdextab.rb, line 225
def process_one_line_for_start(token, line, lineno)
  case token.kind
  when :TABLE_START
    @layer.table = Table.new(lineno, @mes, token.opt[:attr])
  when :ELSE
    # threw
    output_in_else(token.opt[:content])
  when :STAR_START
    @layer.star = true
    output_in_else("*" + token.opt[:content])
  when :STAR_END
    @layer.star = false
    output_in_else("*" + token.opt[:content])
  else
    @mes.output_fatal("In :START unknown tag=(#{token.kind}) in process_one_line_for_start")
    @mes.output_fatal("@fname=#{@fname} | lineno=#{lineno}")
    exit(@mes.ec("EXIT_CODE_UNKNOWN"))
  end
end
process_one_line_for_table_end(token) click to toggle source

TABLE_END状態でのトークン処理

@param token [Token] 読み込んだトークン @return [void]

# File lib/mdextab.rb, line 279
def process_one_line_for_table_end(token)
  @layer.process_table_end(token)
  return if @layer.return_from_nested_layer

  @mes.output_debug("1 - process_one_line_table_end cur_state=#{@layer.cur_state} @return_from_nested_layer~#{@layer.return_from_nested_layer}")
  @mes.exc_file_write(@o_fname) { @output.puts(@layer.table.table_end) }
end
set_state() click to toggle source

テーブル拡張向け構文解析用状態遷移テーブルの設定

@return [void]

# File lib/mdextab.rb, line 75
def set_state
  @states = {
    START: { TABLE_START: :IN_TABLE, ELSE: :OUT_OF_TABLE, STAR_START: :START, STAR_END: :START },
    OUT_OF_TABLE: { TABLE_START: :IN_TABLE, ELSE: :OUT_OF_TABLE, STAR_START: :OUT_OF_TABLE, STAR_END: :OUT_OF_TABLE, TD: :OUT_OF_TABLE },
    IN_TABLE: { TBODY_START: :IN_TABLE_BODY, TABLE_END: :OUT_OF_TABLE, ELSE: :IN_TABLE, TD: :IN_TD_NO_TBODY, TH: :IN_TH_NO_TBODY, TABLE_START: :IN_TABLE, STAR_START: :IN_TABLE, STAR_END: :IN_TABLE },
    IN_TABLE_BODY: { TH: :IN_TH, TD: :IN_TD, ELSE: :IN_TABLE_BODY, TABLE_START: :IN_TABLE_BODY, TBODY_END: :IN_TABLE, TABLE_END: :OUT_OF_TABLE, STAR_START: :IN_TABLE_BODY, STAR_END: :IN_TABLE_BODY },
    IN_TH: { ELSE: :IN_TH, TH: :IN_TH, TD: :IN_TD, TABLE_START: :IN_TH, STAR_START: :IN_TH, STAR_END: :IN_TH },
    IN_TH_NO_TBODY: { ELSE: :IN_TH_NO_TBODY, TH: :IN_TH_NO_TBODY, TD: :IN_TD_NO_TBODY, TABLE_START: :IN_TH_NO_TBODY, STAR_START: :IN_TH_NO_TBODY, STAR_END: :IN_TH_NO_TBODY },
    IN_TD: { ELSE: :IN_TD, TH: :IN_TH, TD: :IN_TD, TBODY_END: :IN_TABLE, TABLE_START: :IN_TD, STAR_START: :IN_TD, START_END: :IN_TD },
    IN_TD_NO_TBODY: { ELSE: :IN_TD_NO_TBODY, TH: :IN_TH_NO_TBODY, TD: :IN_TD_NO_TBODY, TABLE_START: :IN_TD_NO_TBODY, TABLE_END: :OUT_OF_TABLE, TBODY_END: :IN_TABLE, STAR_START: :IN_TD_NO_TBODY, STAR_END: :IN_TD_NO_TBODY },
  }
end
table_td_append_in_else(str) click to toggle source

テーブルのTDタグの一部として、トークンELSEに対応する行を追加

@param str [String] トークンELSEに対応する行 @return [void]

# File lib/mdextab.rb, line 206
def table_td_append_in_else(str)
  if @layer.star
    if str.match?(/^\s*$/)
      @mes.output_debug("TdAppend InElse")
    else
      @layer.table.td_append(str, @layer.star)
    end
  else
    @layer.table.td_append(str, @layer.star)
  end
end
table_th_append_in_else(str) click to toggle source

テーブルのTHタグの一部として、トークンELSEに対応する行を追加

@param str [String] トークンELSEに対応する行 @return [void]

# File lib/mdextab.rb, line 189
def table_th_append_in_else(str)
  if @layer.star
    if str.match?(/^\s*$/)
      @mes.output_debug("ThAppend InElse")
    else
      @layer.table.th_append(str, @layer.star)
    end
  else
    @layer.table.th_append(str, @layer.star)
  end
end