diff --git a/rocco.html b/rocco.html new file mode 100644 index 0000000..0e641d1 --- /dev/null +++ b/rocco.html @@ -0,0 +1,281 @@ + + +
+ +rocco.rb |
+ + |
---|---|
Rocco is a Ruby port of Docco, the quick-and-dirty, +hundred-line-long, literate-programming-style documentation generator. + +Rocco reads Ruby source files and produces annotated source documentation +in HTML format. Comments are formatted with Markdown and presented +alongside syntax highlighted code so as to give an annotation effect. +This page is the result of running Rocco against its own source file. + +Most of this was written while waiting for node.js to build (so I +could use Docco!). Docco’s gorgeous HTML and CSS are taken verbatim. +The main difference is that Rocco is written in Ruby instead of +CoffeeScript and may be a bit easier to obtain and install in +existing Ruby environments or where node doesn’t run yet. + +Rocco can be installed with rubygems: + +
+
+Once installed, the
+
+The HTML files are written to the current working directory. + |
+
+
+ |
+
+Prerequisites+ |
+
+
+ |
+
+ The rdiscount library is +required for Markdown processing. + |
+
+ require 'rdiscount'
+ |
+
+ We use {{ mustache }} for +templating. + |
+
+ require 'mustache'
+ |
+
+ Code is run through Pygments for syntax
+highlighting. Fail fast if we can’t find the |
+
+ if ! ENV['PATH'].split(':').any? { |dir| File.exist?("#{dir}/pygmentize") }
+ fail "Pygments is required for syntax highlighting"
+end
+ |
+
+Public Interface+ |
+
+
+ |
+
+
|
+
+ class Rocco
+ def initialize(filename, &block)
+ @file = filename
+ @data =
+ if block_given?
+ yield
+ else
+ File.read(filename)
+ end |
+
+ Parsing and highlighting + |
+
+ @sections = highlight(parse(@data))
+ end
+ |
+
+ The filename as given to |
+
+ attr_reader :file
+ |
+
+ A list of two-tuples representing each section of the source file. Each
+item in the list has the form: |
+
+ attr_reader :sections
+ |
+
+ Generate HTML output for the entire document. + |
+
+ require 'rocco/layout'
+ def to_html
+ Rocco::Layout.new(self).render
+ end
+ |
+
+Internal Parsing and Highlighting+ |
+
+
+ |
+
+ Parse the raw file data into a list of two-tuples. + |
+
+ def parse(data)
+ sections = []
+ docs, code = [], []
+ data.split("\n").each do |line|
+ case line
+ when /^\s*#/
+ if code.any?
+ sections << [docs, code]
+ docs, code = [], []
+ end
+ docs << line
+ when /^\s*$/
+ code << line
+ else
+ code << line
+ end
+ end
+ sections << [docs, code] if docs.any? || code.any?
+ sections
+ end
+ |
+
+ Take the raw section data and apply markdown formatting and syntax +highlighting. + |
+
+ def highlight(sections) |
+
+ Start by splitting the docs and codes blocks into two separate lists. + |
+
+ docs_blocks, code_blocks = [], []
+ sections.each do |docs,code|
+ docs_blocks << docs.map { |line| line.sub(/^\s*#\s?/, '') }.join("\n")
+ code_blocks << code.join("\n")
+ end
+ |
+
+ Combine all docs blocks into a single big markdown document and run +through RDiscount. Then split it back out into separate sections. + |
+
+ markdown = docs_blocks.join("\n##### DIVIDER\n")
+ docs_html = Markdown.new(markdown, :smart).
+ to_html.
+ split("\n<h5>DIVIDER</h5>\n")
+ |
+
+ Combine all code blocks into a single big stream and run through
+pygments. We |
+
+ code_html = nil
+ open("|pygmentize -l ruby -f html", 'r+') do |fd|
+ fork {
+ fd.close_read
+ fd.write code_blocks.join("\n# DIVIDER\n")
+ fd.close_write
+ exit!
+ }
+
+ fd.close_write
+ code_html = fd.read
+ fd.close_read
+ end
+ |
+
+ Do some post-processing on the pygments output to remove
+partial |
+
+ code_html = code_html.
+ split(/\n?<span class="c1"># DIVIDER<\/span>\n?/m).
+ map { |code| code.sub(/\n?<div class="highlight"><pre>/m, '') }.
+ map { |code| code.sub(/\n?<\/pre><\/div>\n/m, '') }
+ |
+
+ Combine the docs and code lists into the same sections style list we +started with. + |
+
+ docs_html.zip(code_html)
+ end
+end |
+