Skip to content

Markdown Table Generator — Ruby source

Turn pipe, CSV, tab, semicolon, or space-separated data into a clean GitHub-Flavored Markdown table. Auto-detects the delimiter, pads columns, escapes pipes, and supports per-column alignment - all in your browser.

This is the Ruby implementation — the same logic the interactive tool runs, in a shareable, citable form.

# markdown-table — Ruby port: split delimiter-separated rows and render a padded GFM table, ported from src/lib/markdown-table.ts.

module MarkdownTable
  # splitLine: literal-delimiter split (',', '\t', ';'), each cell trimmed.
  def self.split_line(line, delim) = line.split(delim, -1).map(&:strip)

  # parseTable: non-empty lines, each split by the delimiter.
  def self.parse_table(input, delim)
    input.split(/\r?\n/, -1).map(&:strip).reject(&:empty?).map { |l| split_line(l, delim) }
  end

  # escapeCell: newlines collapse to spaces, a literal '|' renders as '\|'.
  def self.escape_cell(cell) = cell.gsub(/\r?\n/, ' ').gsub('|') { '\|' }

  # pad: fill to width honoring right/center/left alignment.
  def self.pad(cell, width, align)
    case align
    when :right  then cell.rjust(width)
    when :center then cell.center(width)
    else cell.ljust(width) # :left / :none -> left-aligned
    end
  end

  # sepCell: ---, :--, --:, :-: — the alignment separator, min width 3.
  def self.sep_cell(align, width)
    w = [width, 3].max
    { center: ':' + '-' * (w - 2) + ':', right: '-' * (w - 1) + ':',
      left: ':' + '-' * (w - 1) }.fetch(align, '-' * w)
  end

  # toMarkdown: pad every column to its widest (escaped) cell and lay rows out
  # as '| a | b |', with the separator row under the header row.
  def self.to_markdown(rows, header: true, align: [])
    return '' if rows.empty?

    grid = rows.map { |row| row.map { |c| escape_cell(c) } }
    cols = grid.map(&:length).max
    grid.each { |row| row.concat(Array.new(cols - row.length, '')) }
    aligns = (0...cols).map { |i| align[i] || :none }
    widths = (0...cols).map { |c| [3, grid.map { |r| r[c].length }.max].max }

    line = ->(cells) { '| ' + cells.each_with_index.map { |c, i| pad(c, widths[i], aligns[i]) }.join(' | ') + ' |' }
    separator = '| ' + aligns.each_with_index.map { |a, i| sep_cell(a, widths[i]) }.join(' | ') + ' |'

    head = header ? grid.first : Array.new(cols, '')
    data = header ? grid.drop(1) : grid
    ([line.call(head), separator] + data.map { |row| line.call(row) }).join("\n")
  end
end

# Demo: a CSV-ish grid with a literal pipe in one cell (escaped on output).
input = "Name,Price,Qty\nWire | cable,2 m,1\nLED,3 mm,25"
puts MarkdownTable.to_markdown(MarkdownTable.parse_table(input, ','),
                               align: %i[none right center])

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →