Skip to content

Instantly share code, notes, and snippets.

@RISCfuture
Created May 29, 2014 01:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RISCfuture/428db6fc2967fb6d5dc6 to your computer and use it in GitHub Desktop.
Save RISCfuture/428db6fc2967fb6d5dc6 to your computer and use it in GitHub Desktop.
mdtable: Clean up Markdown tables in code comments and Markdown files
#!/usr/bin/env ruby
require 'find'
def parse_cells(row)
row.split('|').map(&:strip)[1..-1]
end
def header?(cells)
cells.all? { |cell| cell =~ /^:?\-+:?$/ }
end
def build_table(table, commented, indent, header)
widths = [0]*table.first.size
table.each do |row|
row.each_with_index do |cell, col|
widths[col] = cell.size if widths[col] < cell.size
end
end
string = ""
first_row = header ? table.shift : ['']*table.first.size
render_preamble string, indent, commented
render_row first_row, string, widths
render_preamble string, indent, commented
render_header header, string, widths
table.each do |row|
render_preamble string, indent, commented
render_row row, string, widths
end
string
end
def render_preamble(string, indent, commented)
string << ' '*indent
string << '# ' if commented
string << '|'
end
def render_row(row, string, widths)
row.zip(widths).each do |(cell, width)|
string << ' ' << cell.ljust(width, ' ') << ' ' << '|'
end
string << "\n"
end
def render_header(header, string, widths)
header ||= [:left]*widths.size
header.zip(widths).each do |(align, width)|
string << ':' if align == :left
string << '-'*(width + (align == :center ? 2 : 1))
string << ':' if align == :right
string << '|'
end
string << "\n"
end
def process_file(file, comments_only=nil)
output = ""
table = nil
commented = nil
indent = nil
header = nil
output = String.new
file.each_line do |line|
rx = if comments_only
/^(\s*)# (\|(.+?\|)+)\s*$/
elsif comments_only == false
/^(\s*)(\|(.+?\|)+)\s*$/
elsif comments_only.nil?
/^(\s*)(?:# )?(\|(.+?\|)+)\s*$/
end
if line =~ rx
table ||= []
commented = line.strip[0, 1] == '#'
indent ||= $1.size
cells = parse_cells($2)
if header?(cells)
header ||= cells.map do |cell|
if cell[0, 1] == ':' then :left
elsif cell[-1, 1] == ':' then :right
else :center end
end
else
table << cells
end
elsif table
output << build_table(table, commented, indent, header) << line
table = commented = indent = header = nil
else
output << line
end
end
output
end
if ARGV.all? { |v| File.directory? v }
ARGV.each do |dir|
Find.find(File.join(Dir.getwd, dir)) do |path|
if File.directory?(path) && path[0, 1] == '.' && path != '.'
Find.prune
elsif %w( .rb .md ).include?(File.extname(path)) && !File.symlink?(path)
content = File.read(path)
File.open(path, 'w') { |f| f.puts process_file(content, File.extname(path) == '.rb') }
end
end
end
elsif ARGV.none? { |v| File.directory? v }
puts process_file(ARGF)
else
raise "Must provide a list of files or a list of directories"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment