#!/System/Library/Frameworks/Ruby.framework/Versions/Current/usr/bin/ruby # == Synopsis # # gen_html: generates HTML file from markdown and optional template(s) # # == Usage # # gen_html [OPTION] ... [FILE] # # --help: # show help # # -t/--title «title» # make «title» available to template (as `page_name`) # # -h/--header «file» # prepend «file» as header (erb) # # -f/--footer «file» # append «file» as footer (erb) # # FILE: The markdown document to read (defaults to stdin) $KCODE = 'U' if RUBY_VERSION < "1.9" require 'optparse' require 'erb' def expand_tpl(str, binding) ERB.new(str, 0, '%-').result(binding) end def expand_tpl_file(path, binding) expand_tpl(File.read(path), binding) end def find_exe(cmd) dir = ENV['PATH'].split(':').find { |dir| File.executable? File.join(dir, cmd) } dir ? "#{dir}/#{cmd}" : nil end def wrap_key_equivalents(src) src.gsub(/ `([^`]+⇥)` | \( ([⌃⌥⇧⌘↓↑←→]+) \) | ( [⎋⇥↩⌅⌫⌦] | [⌃⌥⇧⌘]+ ( (?=[ ]|-\w+) | F\d+ | . ) ) /x) do if $1 "#$1" elsif $2 "(#$2)" else "#$&" end end end def wrap_authors(src) src.gsub(/ \*\[ (.+?) \]\* /x) do "#$1" end end def wrap_in_article(html) html.gsub(/.*<\/h2>(?m:.*?)(?=\s*\n#$&\n\n" end end title, header, footer, warn = 'untitled', nil, nil, false OptionParser.new do |opts| opts.banner = "Usage: gen_html [options] [file]" opts.separator "Synopsis:" opts.separator "gen_html: generates HTML file from markdown and optional template(s)" opts.separator "Options:" opts.on("-?", "--help", "show help.") do |v| puts opts exit end opts.on("-h","--header FILE", "prepend «file» as header (erb)") do |arg| header = arg end opts.on("-f","--footer FILE", "append «file» as footer (erb)") do |arg| footer = arg end opts.on("-t","--title TITLE", "make «title» available to template (as `page_name`)") do |arg| title = arg end opts.on("-w","--warn", "enable warnings") do |arg| warn = true end end.parse! MARKDOWN_COMPILERS = %w[ multimarkdown ] filter = MARKDOWN_COMPILERS.find { |exe| find_exe exe } abort "Unable to find a markdown compiler" if filter.nil? filters = "|#{filter} --nosmart" document = ARGF.read document = wrap_authors(wrap_key_equivalents(document)) head, body = document.scan(/\A((?:^\w+:\s+.*$\n)*)\n?((?m:.*))\z/).flatten tmp = head.scan(/^(\w+):\s+(.*)$/).collect { |pair| [pair[0].downcase, pair[1].strip] } headers = Hash[*tmp.flatten] page_title = headers['title'] || title css_files = headers['css'].to_s.split(/,\s*/) js_files = headers['js'].to_s.split(/,\s*/) meta_data = Hash[*headers['meta'].to_s.scan(/(.*?)="(.*?)"(?:,\s*)?/).flatten] STDOUT << expand_tpl_file(header, binding) unless header.nil? STDOUT << open(filters, 'r+') { |io| io << body; io.close_write; wrap_in_article(expand_tpl(io.read, binding)) } STDOUT << expand_tpl_file(footer, binding) unless footer.nil?