101 lines
3.2 KiB
Ruby
Executable File
101 lines
3.2 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
#/ Usage: rocco [-l <lang>] [-c <chars>] [-o <dir>] <file>...
|
|
#/ Generate literate-programming-style documentation for Ruby source <file>s.
|
|
#/
|
|
#/ Options:
|
|
#/ -l, --language=<lang> The Pygments lexer to use to highlight code
|
|
#/ -c, --comment-chars=<chars>
|
|
#/ The string to recognize as a comment marker
|
|
#/ -o, --output=<dir> Directory where generated HTML files are written
|
|
#/ -t, --template=<path> The file to use as template when rendering HTML
|
|
#/ -d, --docblocks Parse Docblock @annotations in comments
|
|
#/ --help Show this help message
|
|
|
|
require 'optparse'
|
|
require 'fileutils'
|
|
|
|
# Write usage message to stdout and exit.
|
|
def usage(stream=$stderr, status=1)
|
|
stream.puts File.readlines(__FILE__).
|
|
grep(/^#\//).
|
|
map { |line| line.sub(/^#. ?/, '') }.
|
|
join
|
|
exit status
|
|
end
|
|
|
|
# Like `Kernel#abort` but writes a note encouraging the user to consult
|
|
# `rocco --help` for more information.
|
|
def abort_with_note(message=nil)
|
|
$stderr.puts message if message
|
|
abort "See `rocco --help' for usage information."
|
|
end
|
|
|
|
# Parse command line options, aborting if anything goes wrong.
|
|
output_dir = '.'
|
|
sources = []
|
|
options = {}
|
|
ARGV.options { |o|
|
|
o.program_name = File.basename($0)
|
|
o.on("-o", "--output=DIR") { |dir| output_dir = dir }
|
|
o.on("-l", "--language=LANG") { |lang| options[:language] = lang }
|
|
o.on("-c", "--comment-chars=CHARS") { |chars| options[:comment_chars] = Regexp.escape(chars) }
|
|
o.on("-t", "--template=TEMPLATE") { |template| options[:template_file] = template }
|
|
o.on("-d", "--docblocks") { options[:docblocks] = true }
|
|
o.on_tail("-h", "--help") { usage($stdout, 0) }
|
|
o.parse!
|
|
} or abort_with_note
|
|
|
|
# Use http://pygments.appspot.com in case `pygmentize(1)` isn't available.
|
|
if ! ENV['PATH'].split(':').any? { |dir| File.exist?("#{dir}/pygmentize") }
|
|
unless options[:webservice]
|
|
$stderr.puts "pygmentize not in PATH; using pygments.appspot.com instead"
|
|
options[:webservice] = true
|
|
end
|
|
end
|
|
|
|
# Eat sources from ARGV.
|
|
sources << ARGV.shift while ARGV.any?
|
|
|
|
# Make sure we have some files to work with.
|
|
if sources.empty?
|
|
abort_with_note "#{File.basename($0)}: no input <file>s given"
|
|
end
|
|
|
|
# What a fucking mess. Most of this is duplicated in rocco.rb too.
|
|
libdir = File.expand_path('../../lib', __FILE__).sub(/^#{Dir.pwd}\//, '')
|
|
begin
|
|
require 'rdiscount'
|
|
require 'rocco'
|
|
rescue LoadError
|
|
case $!.to_s
|
|
when /rdiscount/
|
|
if !defined?(Gem)
|
|
warn "warn: #$!. trying again with rubygems"
|
|
require 'rubygems'
|
|
retry
|
|
else
|
|
require 'bluecloth'
|
|
Markdown = BlueCloth
|
|
$LOADED_FEATURES << 'rdiscount.rb'
|
|
retry
|
|
end
|
|
when /rocco/
|
|
if !$:.include?(libdir)
|
|
warn "warn: #$!. trying again with #{libdir} on load path"
|
|
$:.unshift(libdir)
|
|
retry
|
|
end
|
|
end
|
|
raise
|
|
end
|
|
|
|
# Run each file through Rocco and write output.
|
|
sources.each do |filename|
|
|
rocco = Rocco.new(filename, sources, options)
|
|
dest = filename.sub(Regexp.new("#{File.extname(filename)}$"),".html")
|
|
dest = File.join(output_dir, dest) if output_dir != '.'
|
|
puts "rocco: #{filename} -> #{dest}"
|
|
FileUtils.mkdir_p File.dirname(dest)
|
|
File.open(dest, 'wb') { |fd| fd.write(rocco.to_html) }
|
|
end
|