#!/usr/bin/env ruby #/ Usage: ronn ... #/ ronn -m|--man ... #/ ronn -S|--server ... #/ ronn --pipe [...] #/ Convert ronn source s to roff or HTML manpage. In the first synopsis form, #/ build HTML and roff output files based on the input file names. #/ #/ Mode options alter the default file generating behavior: #/ --pipe write to standard output instead of generating files #/ -m, --man show manual like with man(1) #/ -S, --server serve s at http://localhost:1207/ #/ #/ Format options control which files are generated: #/ -r, --roff generate roff output #/ -5, --html generate entire HTML page with layout #/ -f, --fragment generate HTML fragment #/ #/ Document attributes: #/ --date=DATE published date in YYYY-MM-DD format (bottom-center) #/ --manual=NAME name of the manual (top-center) #/ --organization=NAME publishing group or individual (bottom-left) #/ #/ Misc options: #/ -w, --warnings show troff warnings on stderr #/ -W disable previously enabled troff warnings #/ --help show this help message #/ #/ A named example.1.ronn generates example.1.html (HTML manpage) #/ and example.1 (roff manpage) by default. require 'date' require 'optparse' def usage puts File.readlines(__FILE__). grep(/^#\/.*/). map { |line| line.chomp[3..-1] }. join("\n") end ## # Argument defaults build = true view = false server = false formats = nil options = {} styles = %w[man] groff = "groff -Wall -mtty-char -mandoc -Tascii" pager = ENV['MANPAGER'] || ENV['PAGER'] || 'more' ## # Environment variables %w[manual organization date].each do |attribute| value = ENV["RONN_#{attribute.upcase}"] next if value.nil? or value.empty? options[attribute] = value end ## # Argument parsing ARGV.options do |argv| # modes argv.on("--pipe") { build = server = false } argv.on("-b", "--build") { build = true; server = false } argv.on("-m", "--man") { build = server = false; view = true } argv.on("-S", "--server") { build = view = false; server = true } argv.on("-w", "--warnings") { groff += ' -ww' } argv.on("-W") { groff += ' -Ww' } # format options argv.on("-r", "--roff") { (formats ||= []) << 'roff' } argv.on("-5", "--html") { (formats ||= []) << 'html' } argv.on("-f", "--fragment") { (formats ||= []) << 'html_fragment' } # html output options argv.on("-s", "--style=V") { |val| styles += val.split(/[, \n]+/) } # manual attribute options %w[name section manual organization date].each do |attribute| argv.on("--#{attribute}=VALUE") { |val| options[attribute] = val } end argv.on_tail("--help") { usage ; exit 0 } argv.parse! end ## # Modes, Formats, Options case when ARGV.empty? && $stdin.tty? usage exit 2 when ARGV.empty? && !server ARGV.push '-' build = false formats ||= %w[roff] when view formats ||= %w[roff] when build formats ||= %w[roff html] end formats ||= [] formats.delete('html') if formats.include?('html_fragment') # turn the --date arg into a real date object options['date'] &&= Date.strptime(options['date'], '%Y-%m-%d') # pass the styles option options['styles'] = styles ## # Libraries and LOAD_PATH shenanigans begin require 'hpricot' require 'rdiscount' rescue LoadError if !defined?(Gem) warn "warn: #{$!.to_s}. trying again with rubygems." require 'rubygems' retry end end # load ronn libs, setting up the load path if something fails and # we're in a development environment. begin require 'ronn' rescue LoadError raise if $!.to_s !~ /ronn/ libdir = File.expand_path("../../lib", __FILE__).sub(/^#{Dir.pwd}/, '.') if !$:.include?(libdir) warn "warn: #{$!.to_s}. trying again with #{libdir} on load path." $:.unshift libdir retry end raise end ## # Server if server require 'ronn/server' Ronn::Server.run(ARGV, options) exit 0 end ## # Build Pipeline pid = nil wr = STDOUT ARGV.each do |file| doc = Ronn.new(file, options) { file == '-' ? STDIN.read : File.read(file) } # setup the man pipeline if the --man option was specified if view && !build rd, wr = IO.pipe if pid = fork rd.close else wr.close STDIN.reopen rd exec "#{groff} | #{pager}" end end # write output for each format formats.each do |format| if build path = doc.path_for(format) case format when 'html' warn "%5s: %-48s%15s" % [format, path, '+' + doc.styles.join(',')] when 'roff', 'html_fragment' warn "%5s: %-48s" % [format, path] end output = doc.convert(format) File.open(path, 'wb') { |f| f.puts(output) } if format == 'roff' if view system "man #{path}" else system "#{groff} <#{path} >/dev/null" end end else output = doc.convert(format) wr.puts(output) end end # wait for children to exit if pid wr.close Process.wait end end