class RandomWords::TableCleanup
@api public
Table formatting, cleans up tables in content
def align(alignment, string, width)
# @return [String] aligned string
#
# @param width [Integer] The cell width
# @param string [String] The string to align
#
# Align content withing cell based on header alignments
#
def align(alignment, string, width) case alignment when :left string.ljust(width, ' ') when :right string.rjust(width, ' ') when :center string.center(width, ' ') end end
def build_table(table)
# @return [String] the formatted table
#
# @param table [Array
#
# Builds a formatted table
#
def build_table(table) @widths = [0] * table.first.size table.each do |row| next unless row row.each_with_index do |cell, col| if @widths[col] @widths[col] = cell.size if @widths[col] < cell.size else @widths[col] = cell.size end end end @string = String.new first_row = table.shift render_row first_row render_alignment table.each do |row| render_row row end @string end
def clean
# Clean tables within content
#
def clean table_rx = /^(?ix)(?<table> (?<header>\|?(?:.*?\|)+.*?)\s*\n ((?<align>\|?(?:[:-]+\|)+[:-]*)\s*\n)? (?<rows>(?:\|?(?:.*?\|)+.*?(?:\n|\Z))+))/ @content = @content.gsub(/(\|?(?:.+?\|)+)\n\|\n/) do m = Regexp.last_match cells = parse_cells(m[1]).count "#{m[1]}\n#{'|' * cells}\n" end tables = @content.to_enum(:scan, table_rx).map { Regexp.last_match } tables.each do |t| table = [] if t['align'].nil? cells = parse_cells(t['header']) align = "|#{([':---'] * cells.count).join('|')}|" else align = t['align'] end next unless parse_cells(align.ensure_pipes) @alignment = parse_cells(align.ensure_pipes).map do |cell| if cell[0, 1] == ':' && cell[-1, 1] == ':' :center elsif cell[-1, 1] == ':' :right else :left end end lines = t['table'].split("\n") lines.delete_if(&:alignment?) lines.each do |row| # Ensure leading and trailing pipes row = row.ensure_pipes cells = parse_cells(row) table << cells end @content.sub!(/#{Regexp.escape(t['table'])}/, "#{build_table(table)}\n") end @content end
def initialize(content = nil, options = nil)
# @param options [Hash] The options
# @param content [String] The content to clean
#
# Initialize a table cleaner
#
def initialize(content = nil, options = nil) @content = content || '' @max_cell_width = options && options[:max_cell_width] ? options[:max_cell_width] : 30 @max_table_width = options && options[:max_table_width] ? options[:max_table_width] : nil end
def parse_cells(row)
# @return [Array] array of cell strings
#
# @param row [String] The row string
#
# Split a row string on pipes
#
def parse_cells(row) row.split('|').map(&:strip)[1..-1] end
def render_alignment
# Render the alignment row
#
def render_alignment @string << '|' return unless @alignment @alignment.zip(@widths).each do |align, width| @string << ':' if align == :left width = @max_cell_width - 2 if width >= @max_cell_width @string << ('-' * (width + (align == :center ? 2 : 1))) @string << ':' if align == :right @string << '|' end @string << "\n" end
def render_row(row)
# @return [String] the formatted row
#
# @param row [Array] The row of cell contents
#
# Render a row
#
def render_row(row) idx = 0 @max_cell_width = @max_table_width / row.count if @max_table_width return unless row @string << '|' row.zip(@widths).each do |cell, width| width = @max_cell_width - 2 if width >= @max_cell_width if width.zero? @string << '|' else content = @alignment ? align(@alignment[idx], cell, width) : cell.ljust(width, ' ') @string << " #{content} |" end idx += 1 end @string << "\n" end