Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2b5319377b | ||
|
7673d8104a | ||
|
7f4d68422f | ||
|
bb32ab6d27 |
822
index.html
Normal file
822
index.html
Normal file
@ -0,0 +1,822 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||||
<title>rocco.rb</title>
|
||||
<link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id='container'>
|
||||
<div id="background"></div>
|
||||
<div id="jump_to">
|
||||
Jump To …
|
||||
<div id="jump_wrapper">
|
||||
<div id="jump_page">
|
||||
<a class="source" href="rocco.html">rocco.rb</a>
|
||||
<a class="source" href="rocco/layout.html">layout.rb</a>
|
||||
<a class="source" href="rocco/tasks.html">tasks.rb</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table cellspacing=0 cellpadding=0>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class=docs><h1>rocco.rb</h1></th>
|
||||
<th class=code></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr id='section-1'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-1">¶</a>
|
||||
</div>
|
||||
<p><strong>Rocco</strong> is a Ruby port of <a href="http://jashkenas.github.com/docco/">Docco</a>, the quick-and-dirty,
|
||||
hundred-line-long, literate-programming-style documentation generator.</p>
|
||||
|
||||
<p>Rocco reads Ruby source files and produces annotated source documentation
|
||||
in HTML format. Comments are formatted with <a href="http://daringfireball.net/projects/markdown/">Markdown</a> and presented
|
||||
alongside syntax highlighted code so as to give an annotation effect.
|
||||
This page is the result of running Rocco against <a href="http://github.com/rtomayko/rocco/blob/master/lib/rocco.rb#commit">its own source file</a>.</p>
|
||||
|
||||
<p>Most of this was written while waiting for <a href="http://nodejs.org/">node.js</a> 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
|
||||
<a href="http://coffeescript.org/">CoffeeScript</a> and may be a bit easier to obtain and install in
|
||||
existing Ruby environments or where node doesn’t run yet.</p>
|
||||
|
||||
<p>Install Rocco with Rubygems:</p>
|
||||
|
||||
<pre><code>gem install rocco
|
||||
</code></pre>
|
||||
|
||||
<p>Once installed, the <code>rocco</code> command can be used to generate documentation
|
||||
for a set of Ruby source files:</p>
|
||||
|
||||
<pre><code>rocco lib/*.rb
|
||||
</code></pre>
|
||||
|
||||
<p>The HTML files are written to the current working directory.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-Prerequisites'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-Prerequisites">¶</a>
|
||||
</div>
|
||||
<h3>Prerequisites</h3>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-3'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
<p>We’ll need a Markdown library. <a href="http://github.com/rtomayko/rdiscount">RDiscount</a>, if we’re lucky. Otherwise,
|
||||
issue a warning and fall back on using BlueCloth.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="k">begin</span>
|
||||
<span class="nb">require</span> <span class="s1">'rdiscount'</span>
|
||||
<span class="k">rescue</span> <span class="no">LoadError</span> <span class="o">=></span> <span class="n">boom</span>
|
||||
<span class="nb">warn</span> <span class="s2">"WARNING: </span><span class="si">#{</span><span class="n">boom</span><span class="si">}</span><span class="s2">. Trying bluecloth."</span>
|
||||
<span class="nb">require</span> <span class="s1">'bluecloth'</span>
|
||||
<span class="no">Markdown</span> <span class="o">=</span> <span class="no">BlueCloth</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-4'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
<p>We use <a href="http://defunkt.github.com/mustache/">{{ mustache }}</a> for
|
||||
HTML templating.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="nb">require</span> <span class="s1">'mustache'</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-5'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
<p>We use <code>Net::HTTP</code> to highlight code via <a href="http://pygments.appspot.com">http://pygments.appspot.com</a></p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="nb">require</span> <span class="s1">'net/http'</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-6'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
<p>Code is run through <a href="http://pygments.org/">Pygments</a> for syntax
|
||||
highlighting. If it’s not installed, locally, use a webservice.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="kp">include</span> <span class="no">FileTest</span>
|
||||
<span class="k">if</span> <span class="o">!</span><span class="no">ENV</span><span class="o">[</span><span class="s1">'PATH'</span><span class="o">].</span><span class="n">split</span><span class="p">(</span><span class="s1">':'</span><span class="p">)</span><span class="o">.</span><span class="n">any?</span> <span class="p">{</span> <span class="o">|</span><span class="n">dir</span><span class="o">|</span> <span class="n">executable?</span><span class="p">(</span><span class="s2">"</span><span class="si">#{</span><span class="n">dir</span><span class="si">}</span><span class="s2">/pygmentize"</span><span class="p">)</span> <span class="p">}</span>
|
||||
<span class="nb">warn</span> <span class="s2">"WARNING: Pygments not found. Using webservice."</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-Public_Interface'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-Public_Interface">¶</a>
|
||||
</div>
|
||||
<h3>Public Interface</h3>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-8'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
<p><code>Rocco.new</code> takes a source <code>filename</code>, an optional list of source filenames
|
||||
for other documentation sources, an <code>options</code> hash, and an optional <code>block</code>.
|
||||
The <code>options</code> hash respects three members:</p>
|
||||
|
||||
<ul>
|
||||
<li><p><code>:language</code>: specifies which Pygments lexer to use if one can’t be
|
||||
auto-detected from the filename. <em>Defaults to <code>ruby</code></em>.</p></li>
|
||||
<li><p><code>:comment_chars</code>, which specifies the comment characters of the
|
||||
target language. <em>Defaults to <code>#</code></em>.</p></li>
|
||||
<li><p><code>:template_file</code>, which specifies a external template file to use
|
||||
when rendering the final, highlighted file via Mustache. <em>Defaults
|
||||
to <code>nil</code> (that is, Mustache will use <code>./lib/rocco/layout.mustache</code>)</em>.</p></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="k">class</span> <span class="nc">Rocco</span>
|
||||
<span class="no">VERSION</span> <span class="o">=</span> <span class="s1">'0.6'</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">sources</span><span class="o">=[]</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="p">{},</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
|
||||
<span class="vi">@file</span> <span class="o">=</span> <span class="n">filename</span>
|
||||
<span class="vi">@sources</span> <span class="o">=</span> <span class="n">sources</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-9'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
<p>When <code>block</code> is given, it must read the contents of the file using
|
||||
whatever means necessary and return it as a string. With no <code>block</code>,
|
||||
the file is read to retrieve data.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="vi">@data</span> <span class="o">=</span>
|
||||
<span class="k">if</span> <span class="nb">block_given?</span>
|
||||
<span class="k">yield</span>
|
||||
<span class="k">else</span>
|
||||
<span class="no">File</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
|
||||
<span class="k">end</span>
|
||||
|
||||
<span class="n">defaults</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="ss">:language</span> <span class="o">=></span> <span class="s1">'ruby'</span><span class="p">,</span>
|
||||
<span class="ss">:comment_chars</span> <span class="o">=></span> <span class="s1">'#'</span><span class="p">,</span>
|
||||
<span class="ss">:template_file</span> <span class="o">=></span> <span class="kp">nil</span>
|
||||
<span class="p">}</span>
|
||||
<span class="vi">@options</span> <span class="o">=</span> <span class="n">defaults</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">options</span><span class="p">)</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-10'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
<p>If we detect a language</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">if</span> <span class="n">detect_language</span><span class="p">()</span> <span class="o">!=</span> <span class="s2">"text"</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-11'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
<p>then assign the detected language to <code>:language</code>, and look for
|
||||
comment characters based on that language</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="vi">@options</span><span class="o">[</span><span class="ss">:language</span><span class="o">]</span> <span class="o">=</span> <span class="n">detect_language</span><span class="p">()</span>
|
||||
<span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">]</span> <span class="o">=</span> <span class="n">generate_comment_chars</span><span class="p">()</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-12'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
<p>If we didn’t detect a language, but the user provided one, use it
|
||||
to look around for comment characters to override the default.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">elsif</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:language</span><span class="o">]</span> <span class="o">!=</span> <span class="n">defaults</span><span class="o">[</span><span class="ss">:language</span><span class="o">]</span>
|
||||
<span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">]</span> <span class="o">=</span> <span class="n">generate_comment_chars</span><span class="p">()</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-13'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
<p>If neither is true, then convert the default comment character string
|
||||
into the comment_char syntax (we’ll discuss that syntax in detail when
|
||||
we get to <code>generate_comment_chars()</code> in a moment.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">else</span>
|
||||
<span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">]</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="ss">:single</span> <span class="o">=></span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">]</span><span class="p">,</span>
|
||||
<span class="ss">:multi</span> <span class="o">=></span> <span class="kp">nil</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-14'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
<p>Turn <code>:comment_chars</code> into a regex matching a series of spaces, the
|
||||
<code>:comment_chars</code> string, and the an optional space. We’ll use that
|
||||
to detect single-line comments.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="vi">@comment_pattern</span> <span class="o">=</span>
|
||||
<span class="no">Regexp</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">"^</span><span class="se">\\</span><span class="s2">s*</span><span class="si">#{</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:single</span><span class="o">]</span><span class="si">}</span><span class="se">\s</span><span class="s2">?"</span><span class="p">)</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-15'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
<p><code>parse()</code> the file contents stored in <code>@data</code>. Run the result through
|
||||
<code>split()</code> and that result through <code>highlight()</code> to generate the final
|
||||
section list.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="vi">@sections</span> <span class="o">=</span> <span class="n">highlight</span><span class="p">(</span><span class="nb">split</span><span class="p">(</span><span class="n">parse</span><span class="p">(</span><span class="vi">@data</span><span class="p">)))</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-16'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
<p>The filename as given to <code>Rocco.new</code>.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="kp">attr_reader</span> <span class="ss">:file</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-17'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
<p>The merged options array</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="kp">attr_reader</span> <span class="ss">:options</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-18'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
<p>A list of two-tuples representing each <em>section</em> of the source file. Each
|
||||
item in the list has the form: <code>[docs_html, code_html]</code>, where both
|
||||
elements are strings containing the documentation and source code HTML,
|
||||
respectively.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="kp">attr_reader</span> <span class="ss">:sections</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-19'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
<p>A list of all source filenames included in the documentation set. Useful
|
||||
for building an index of other files.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="kp">attr_reader</span> <span class="ss">:sources</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-20'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
</div>
|
||||
<p>Generate HTML output for the entire document.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="nb">require</span> <span class="s1">'rocco/layout'</span>
|
||||
<span class="k">def</span> <span class="nf">to_html</span>
|
||||
<span class="no">Rocco</span><span class="o">::</span><span class="no">Layout</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="nb">self</span><span class="p">,</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:template_file</span><span class="o">]</span><span class="p">)</span><span class="o">.</span><span class="n">render</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-Helper_Functions'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-Helper_Functions">¶</a>
|
||||
</div>
|
||||
<h2>Helper Functions</h2>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-22'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
</div>
|
||||
<p>Returns <code>true</code> if <code>pygmentize</code> is available locally, <code>false</code> otherwise.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">pygmentize?</span>
|
||||
<span class="vi">@_pygmentize</span> <span class="o">||=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">'PATH'</span><span class="o">].</span><span class="n">split</span><span class="p">(</span><span class="s1">':'</span><span class="p">)</span><span class="o">.</span>
|
||||
<span class="n">any?</span> <span class="p">{</span> <span class="o">|</span><span class="n">dir</span><span class="o">|</span> <span class="n">executable?</span><span class="p">(</span><span class="s2">"</span><span class="si">#{</span><span class="n">dir</span><span class="si">}</span><span class="s2">/pygmentize"</span><span class="p">)</span> <span class="p">}</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-23'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
</div>
|
||||
<p>If <code>pygmentize</code> is available, we can use it to autodetect a file’s
|
||||
language based on its filename. Filenames without extensions, or with
|
||||
extensions that <code>pygmentize</code> doesn’t understand will return <code>text</code>.
|
||||
We’ll also return <code>text</code> if <code>pygmentize</code> isn’t available.</p>
|
||||
|
||||
<p>We’ll memoize the result, as we’ll call this a few times.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">detect_language</span>
|
||||
<span class="vi">@_language</span> <span class="o">||=</span>
|
||||
<span class="k">if</span> <span class="n">pygmentize?</span>
|
||||
<span class="sx">%x[pygmentize -N </span><span class="si">#{</span><span class="vi">@file</span><span class="si">}</span><span class="sx">]</span><span class="o">.</span><span class="n">strip!</span>
|
||||
<span class="k">else</span>
|
||||
<span class="s2">"text"</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-24'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
</div>
|
||||
<p>Given a file’s language, we should be able to autopopulate the
|
||||
<code>comment_chars</code> variables for single-line comments. If we don’t
|
||||
have comment characters on record for a given language, we’ll
|
||||
use the user-provided <code>:comment_char</code> option (which defaults to
|
||||
<code>#</code>).</p>
|
||||
|
||||
<p>Comment characters are listed as:</p>
|
||||
|
||||
<pre><code>{ :single => "//",
|
||||
:multi_start => "/**",
|
||||
:multi_middle => "*",
|
||||
:multi_end => "*/" }
|
||||
</code></pre>
|
||||
|
||||
<p><code>:single</code> denotes the leading character of a single-line comment.
|
||||
<code>:multi_start</code> denotes the string that should appear alone on a
|
||||
line of code to begin a block of documentation. <code>:multi_middle</code>
|
||||
denotes the leading character of block comment content, and
|
||||
<code>:multi_end</code> is the string that ought appear alone on a line to
|
||||
close a block of documentation. That is:</p>
|
||||
|
||||
<pre><code>/** [:multi][:start]
|
||||
* [:multi][:middle]
|
||||
...
|
||||
* [:multi][:middle]
|
||||
*/ [:multi][:end]
|
||||
</code></pre>
|
||||
|
||||
<p>If a language only has one type of comment, the missing type
|
||||
should be assigned <code>nil</code>.</p>
|
||||
|
||||
<p>At the moment, we’re only returning <code>:single</code>. Consider this
|
||||
groundwork for block comment parsing.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="no">COMMENT_STYLES</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s2">"bash"</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:single</span> <span class="o">=></span> <span class="s2">"#"</span><span class="p">,</span> <span class="ss">:multi</span> <span class="o">=></span> <span class="kp">nil</span> <span class="p">},</span>
|
||||
<span class="s2">"c"</span> <span class="o">=></span> <span class="p">{</span>
|
||||
<span class="ss">:single</span> <span class="o">=></span> <span class="s2">"//"</span><span class="p">,</span>
|
||||
<span class="ss">:multi</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:start</span> <span class="o">=></span> <span class="s2">"/**"</span><span class="p">,</span> <span class="ss">:middle</span> <span class="o">=></span> <span class="s2">"*"</span><span class="p">,</span> <span class="ss">:end</span> <span class="o">=></span> <span class="s2">"*/"</span> <span class="p">}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="s2">"coffee-script"</span> <span class="o">=></span> <span class="p">{</span>
|
||||
<span class="ss">:single</span> <span class="o">=></span> <span class="s2">"#"</span><span class="p">,</span>
|
||||
<span class="ss">:multi</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:start</span> <span class="o">=></span> <span class="s2">"###"</span><span class="p">,</span> <span class="ss">:middle</span> <span class="o">=></span> <span class="kp">nil</span><span class="p">,</span> <span class="ss">:end</span> <span class="o">=></span> <span class="s2">"###"</span> <span class="p">}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="s2">"cpp"</span> <span class="o">=></span> <span class="p">{</span>
|
||||
<span class="ss">:single</span> <span class="o">=></span> <span class="s2">"//"</span><span class="p">,</span>
|
||||
<span class="ss">:multi</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:start</span> <span class="o">=></span> <span class="s2">"/**"</span><span class="p">,</span> <span class="ss">:middle</span> <span class="o">=></span> <span class="s2">"*"</span><span class="p">,</span> <span class="ss">:end</span> <span class="o">=></span> <span class="s2">"*/"</span> <span class="p">}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="s2">"css"</span> <span class="o">=></span> <span class="p">{</span>
|
||||
<span class="ss">:single</span> <span class="o">=></span> <span class="kp">nil</span><span class="p">,</span>
|
||||
<span class="ss">:multi</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:start</span> <span class="o">=></span> <span class="s2">"/**"</span><span class="p">,</span> <span class="ss">:middle</span> <span class="o">=></span> <span class="s2">"*"</span><span class="p">,</span> <span class="ss">:end</span> <span class="o">=></span> <span class="s2">"*/"</span> <span class="p">}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="s2">"java"</span> <span class="o">=></span> <span class="p">{</span>
|
||||
<span class="ss">:single</span> <span class="o">=></span> <span class="s2">"//"</span><span class="p">,</span>
|
||||
<span class="ss">:multi</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:start</span> <span class="o">=></span> <span class="s2">"/**"</span><span class="p">,</span> <span class="ss">:middle</span> <span class="o">=></span> <span class="s2">"*"</span><span class="p">,</span> <span class="ss">:end</span> <span class="o">=></span> <span class="s2">"*/"</span> <span class="p">}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="s2">"js"</span> <span class="o">=></span> <span class="p">{</span>
|
||||
<span class="ss">:single</span> <span class="o">=></span> <span class="s2">"//"</span><span class="p">,</span>
|
||||
<span class="ss">:multi</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:start</span> <span class="o">=></span> <span class="s2">"/**"</span><span class="p">,</span> <span class="ss">:middle</span> <span class="o">=></span> <span class="s2">"*"</span><span class="p">,</span> <span class="ss">:end</span> <span class="o">=></span> <span class="s2">"*/"</span> <span class="p">}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="s2">"lua"</span> <span class="o">=></span> <span class="p">{</span>
|
||||
<span class="ss">:single</span> <span class="o">=></span> <span class="s2">"--"</span><span class="p">,</span>
|
||||
<span class="ss">:multi</span> <span class="o">=></span> <span class="kp">nil</span>
|
||||
<span class="p">},</span>
|
||||
<span class="s2">"python"</span> <span class="o">=></span> <span class="p">{</span>
|
||||
<span class="ss">:single</span> <span class="o">=></span> <span class="s2">"#"</span><span class="p">,</span>
|
||||
<span class="ss">:multi</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:start</span> <span class="o">=></span> <span class="s1">'"""'</span><span class="p">,</span> <span class="ss">:middle</span> <span class="o">=></span> <span class="kp">nil</span><span class="p">,</span> <span class="ss">:end</span> <span class="o">=></span> <span class="s1">'"""'</span> <span class="p">}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="s2">"rb"</span> <span class="o">=></span> <span class="p">{</span>
|
||||
<span class="ss">:single</span> <span class="o">=></span> <span class="s2">"#"</span><span class="p">,</span>
|
||||
<span class="ss">:multi</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:start</span> <span class="o">=></span> <span class="s1">'=begin'</span><span class="p">,</span> <span class="ss">:middle</span> <span class="o">=></span> <span class="kp">nil</span><span class="p">,</span> <span class="ss">:end</span> <span class="o">=></span> <span class="s1">'=end'</span> <span class="p">}</span>
|
||||
<span class="p">},</span>
|
||||
<span class="s2">"scheme"</span> <span class="o">=></span> <span class="p">{</span> <span class="ss">:single</span> <span class="o">=></span> <span class="s2">";;"</span><span class="p">,</span> <span class="ss">:multi</span> <span class="o">=></span> <span class="kp">nil</span> <span class="p">},</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">generate_comment_chars</span>
|
||||
<span class="vi">@_commentchar</span> <span class="o">||=</span>
|
||||
<span class="k">if</span> <span class="no">COMMENT_STYLES</span><span class="o">[</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:language</span><span class="o">]]</span>
|
||||
<span class="no">COMMENT_STYLES</span><span class="o">[</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:language</span><span class="o">]]</span>
|
||||
<span class="k">else</span>
|
||||
<span class="p">{</span> <span class="ss">:single</span> <span class="o">=></span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">]</span><span class="p">,</span> <span class="ss">:multi</span> <span class="o">=></span> <span class="kp">nil</span> <span class="p">}</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-Internal_Parsing_and_Highlighting'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-Internal_Parsing_and_Highlighting">¶</a>
|
||||
</div>
|
||||
<h2>Internal Parsing and Highlighting</h2>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-26'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-26">¶</a>
|
||||
</div>
|
||||
<p>Parse the raw file data into a list of two-tuples. Each tuple has the
|
||||
form <code>[docs, code]</code> where both elements are arrays containing the
|
||||
raw lines parsed from the input file, comment characters stripped.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
|
||||
<span class="n">sections</span> <span class="o">=</span> <span class="o">[]</span>
|
||||
<span class="n">docs</span><span class="p">,</span> <span class="n">code</span> <span class="o">=</span> <span class="o">[]</span><span class="p">,</span> <span class="o">[]</span>
|
||||
<span class="n">lines</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-27'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-27">¶</a>
|
||||
</div>
|
||||
<p>The first line is ignored if it is a shebang line. We also ignore the
|
||||
PEP 263 encoding information in python sourcefiles, and the similar ruby
|
||||
1.9 syntax.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="n">lines</span><span class="o">.</span><span class="n">shift</span> <span class="k">if</span> <span class="n">lines</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">=~</span> <span class="sr">/^\#\!/</span>
|
||||
<span class="n">lines</span><span class="o">.</span><span class="n">shift</span> <span class="k">if</span> <span class="n">lines</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">=~</span> <span class="sr">/coding[:=]\s*[-\w.]+/</span> <span class="o">&&</span>
|
||||
<span class="o">[</span> <span class="s2">"python"</span><span class="p">,</span> <span class="s2">"rb"</span> <span class="o">].</span><span class="n">include?</span><span class="p">(</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:language</span><span class="o">]</span><span class="p">)</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-28'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-28">¶</a>
|
||||
</div>
|
||||
<p>To detect both block comments and single-line comments, we’ll set
|
||||
up a tiny state machine, and loop through each line of the file.
|
||||
This requires an <code>in_comment_block</code> boolean, and a few regular
|
||||
expressions for line tests.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="n">in_comment_block</span> <span class="o">=</span> <span class="kp">false</span>
|
||||
<span class="n">single_line_comment</span><span class="p">,</span> <span class="n">block_comment_start</span><span class="p">,</span> <span class="n">block_comment_mid</span><span class="p">,</span> <span class="n">block_comment_end</span> <span class="o">=</span>
|
||||
<span class="kp">nil</span><span class="p">,</span> <span class="kp">nil</span><span class="p">,</span> <span class="kp">nil</span><span class="p">,</span> <span class="kp">nil</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:single</span><span class="o">].</span><span class="n">nil?</span>
|
||||
<span class="n">single_line_comment</span> <span class="o">=</span> <span class="no">Regexp</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">"^</span><span class="se">\\</span><span class="s2">s*</span><span class="si">#{</span><span class="no">Regexp</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:single</span><span class="o">]</span><span class="p">)</span><span class="si">}</span><span class="se">\\</span><span class="s2">s?"</span><span class="p">)</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:multi</span><span class="o">].</span><span class="n">nil?</span>
|
||||
<span class="n">block_comment_start</span> <span class="o">=</span> <span class="no">Regexp</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">"^</span><span class="se">\\</span><span class="s2">s*</span><span class="si">#{</span><span class="no">Regexp</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:multi</span><span class="o">][</span><span class="ss">:start</span><span class="o">]</span><span class="p">)</span><span class="si">}</span><span class="se">\\</span><span class="s2">s*$"</span><span class="p">)</span>
|
||||
<span class="n">block_comment_end</span> <span class="o">=</span> <span class="no">Regexp</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">"^</span><span class="se">\\</span><span class="s2">s*</span><span class="si">#{</span><span class="no">Regexp</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:multi</span><span class="o">][</span><span class="ss">:end</span><span class="o">]</span><span class="p">)</span><span class="si">}</span><span class="se">\\</span><span class="s2">s*$"</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:multi</span><span class="o">][</span><span class="ss">:middle</span><span class="o">]</span>
|
||||
<span class="n">block_comment_mid</span> <span class="o">=</span> <span class="no">Regexp</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">"^</span><span class="se">\\</span><span class="s2">s*</span><span class="si">#{</span><span class="no">Regexp</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:multi</span><span class="o">][</span><span class="ss">:middle</span><span class="o">]</span><span class="p">)</span><span class="si">}</span><span class="se">\\</span><span class="s2">s?"</span><span class="p">)</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span>
|
||||
<span class="n">lines</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">line</span><span class="o">|</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-29'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-29">¶</a>
|
||||
</div>
|
||||
<p>If we’re currently in a comment block, check whether the line matches
|
||||
the <em>end</em> of a comment block.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">if</span> <span class="n">in_comment_block</span>
|
||||
<span class="k">if</span> <span class="n">block_comment_end</span> <span class="o">&&</span> <span class="n">line</span><span class="o">.</span><span class="n">match</span><span class="p">(</span> <span class="n">block_comment_end</span> <span class="p">)</span>
|
||||
<span class="n">in_comment_block</span> <span class="o">=</span> <span class="kp">false</span>
|
||||
<span class="k">else</span>
|
||||
<span class="n">docs</span> <span class="o"><<</span> <span class="n">line</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span> <span class="n">block_comment_mid</span> <span class="o">||</span> <span class="s1">''</span><span class="p">,</span> <span class="s1">''</span> <span class="p">)</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-30'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-30">¶</a>
|
||||
</div>
|
||||
<p>Otherwise, check whether the line matches the beginning of a block, or
|
||||
a single-line comment all on it’s lonesome. In either case, if there’s
|
||||
code, start a new section</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">else</span>
|
||||
<span class="k">if</span> <span class="n">block_comment_start</span> <span class="o">&&</span> <span class="n">line</span><span class="o">.</span><span class="n">match</span><span class="p">(</span> <span class="n">block_comment_start</span> <span class="p">)</span>
|
||||
<span class="n">in_comment_block</span> <span class="o">=</span> <span class="kp">true</span>
|
||||
<span class="k">if</span> <span class="n">code</span><span class="o">.</span><span class="n">any?</span>
|
||||
<span class="n">sections</span> <span class="o"><<</span> <span class="o">[</span><span class="n">docs</span><span class="p">,</span> <span class="n">code</span><span class="o">]</span>
|
||||
<span class="n">docs</span><span class="p">,</span> <span class="n">code</span> <span class="o">=</span> <span class="o">[]</span><span class="p">,</span> <span class="o">[]</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">elsif</span> <span class="n">single_line_comment</span> <span class="o">&&</span> <span class="n">line</span><span class="o">.</span><span class="n">match</span><span class="p">(</span> <span class="n">single_line_comment</span> <span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">code</span><span class="o">.</span><span class="n">any?</span>
|
||||
<span class="n">sections</span> <span class="o"><<</span> <span class="o">[</span><span class="n">docs</span><span class="p">,</span> <span class="n">code</span><span class="o">]</span>
|
||||
<span class="n">docs</span><span class="p">,</span> <span class="n">code</span> <span class="o">=</span> <span class="o">[]</span><span class="p">,</span> <span class="o">[]</span>
|
||||
<span class="k">end</span>
|
||||
<span class="n">docs</span> <span class="o"><<</span> <span class="n">line</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span> <span class="n">single_line_comment</span> <span class="o">||</span> <span class="s1">''</span><span class="p">,</span> <span class="s1">''</span> <span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="n">code</span> <span class="o"><<</span> <span class="n">line</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span>
|
||||
<span class="n">sections</span> <span class="o"><<</span> <span class="o">[</span><span class="n">docs</span><span class="p">,</span> <span class="n">code</span><span class="o">]</span> <span class="k">if</span> <span class="n">docs</span><span class="o">.</span><span class="n">any?</span> <span class="o">||</span> <span class="n">code</span><span class="o">.</span><span class="n">any?</span>
|
||||
<span class="n">normalize_leading_spaces</span><span class="p">(</span> <span class="n">sections</span> <span class="p">)</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-31'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-31">¶</a>
|
||||
</div>
|
||||
<p>Normalizes documentation whitespace by checking for leading whitespace,
|
||||
removing it, and then removing the same amount of whitespace from each
|
||||
succeeding line. That is:</p>
|
||||
|
||||
<pre><code>def func():
|
||||
"""
|
||||
Comment 1
|
||||
Comment 2
|
||||
"""
|
||||
print "omg!"
|
||||
</code></pre>
|
||||
|
||||
<p>should yield a comment block of <code>Comment 1\nComment 2</code> and code of
|
||||
<code>def func():\n print "omg!"</code></p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">normalize_leading_spaces</span><span class="p">(</span> <span class="n">sections</span> <span class="p">)</span>
|
||||
<span class="n">sections</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">section</span><span class="o">|</span>
|
||||
<span class="k">if</span> <span class="n">section</span><span class="o">.</span><span class="n">any?</span> <span class="o">&&</span> <span class="n">section</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="n">any?</span>
|
||||
<span class="n">leading_space</span> <span class="o">=</span> <span class="n">section</span><span class="o">[</span><span class="mi">0</span><span class="o">][</span><span class="mi">0</span><span class="o">].</span><span class="n">match</span><span class="p">(</span> <span class="s2">"^</span><span class="se">\s</span><span class="s2">+"</span> <span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">leading_space</span>
|
||||
<span class="n">section</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">=</span>
|
||||
<span class="n">section</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="n">map</span><span class="p">{</span> <span class="o">|</span><span class="n">line</span><span class="o">|</span> <span class="n">line</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sr"> /^</span><span class="si">#{</span><span class="n">leading_space</span><span class="o">.</span><span class="n">to_s</span><span class="si">}</span><span class="sr">/</span><span class="p">,</span> <span class="s1">''</span> <span class="p">)</span> <span class="p">}</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span>
|
||||
<span class="n">section</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-32'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-32">¶</a>
|
||||
</div>
|
||||
<p>Take the list of paired <em>sections</em> two-tuples and split into two
|
||||
separate lists: one holding the comments with leaders removed and
|
||||
one with the code blocks.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">split</span><span class="p">(</span><span class="n">sections</span><span class="p">)</span>
|
||||
<span class="n">docs_blocks</span><span class="p">,</span> <span class="n">code_blocks</span> <span class="o">=</span> <span class="o">[]</span><span class="p">,</span> <span class="o">[]</span>
|
||||
<span class="n">sections</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">docs</span><span class="p">,</span><span class="n">code</span><span class="o">|</span>
|
||||
<span class="n">docs_blocks</span> <span class="o"><<</span> <span class="n">docs</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">code_blocks</span> <span class="o"><<</span> <span class="n">code</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">line</span><span class="o">|</span>
|
||||
<span class="n">tabs</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sr">/^(\t+)/</span><span class="p">)</span>
|
||||
<span class="n">tabs</span> <span class="p">?</span> <span class="n">line</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sr">/^\t+/</span><span class="p">,</span> <span class="s1">' '</span> <span class="o">*</span> <span class="n">tabs</span><span class="o">.</span><span class="n">captures</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="n">length</span><span class="p">)</span> <span class="p">:</span> <span class="n">line</span>
|
||||
<span class="k">end</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="k">end</span>
|
||||
<span class="o">[</span><span class="n">docs_blocks</span><span class="p">,</span> <span class="n">code_blocks</span><span class="o">]</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-33'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-33">¶</a>
|
||||
</div>
|
||||
<p>Take the result of <code>split</code> and apply Markdown formatting to comments and
|
||||
syntax highlighting to source code.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">highlight</span><span class="p">(</span><span class="n">blocks</span><span class="p">)</span>
|
||||
<span class="n">docs_blocks</span><span class="p">,</span> <span class="n">code_blocks</span> <span class="o">=</span> <span class="n">blocks</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-34'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-34">¶</a>
|
||||
</div>
|
||||
<p>Combine all docs blocks into a single big markdown document with section
|
||||
dividers and run through the Markdown processor. Then split it back out
|
||||
into separate sections.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="n">markdown</span> <span class="o">=</span> <span class="n">docs_blocks</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n\n</span><span class="s2">##### DIVIDER</span><span class="se">\n\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">docs_html</span> <span class="o">=</span> <span class="no">Markdown</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">markdown</span><span class="p">,</span> <span class="ss">:smart</span><span class="p">)</span><span class="o">.</span>
|
||||
<span class="n">to_html</span><span class="o">.</span>
|
||||
<span class="nb">split</span><span class="p">(</span><span class="sr">/\n*<h5>DIVIDER<\/h5>\n*/m</span><span class="p">)</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-35'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-35">¶</a>
|
||||
</div>
|
||||
<p>Combine all code blocks into a single big stream with section dividers and
|
||||
run through either <code>pygmentize(1)</code> or <a href="http://pygments.appspot.com">http://pygments.appspot.com</a></p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="n">span</span><span class="p">,</span> <span class="n">espan</span> <span class="o">=</span> <span class="s1">'<span class="c.?">'</span><span class="p">,</span> <span class="s1">'</span>'</span>
|
||||
<span class="k">if</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:single</span><span class="o">]</span>
|
||||
<span class="n">front</span> <span class="o">=</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:single</span><span class="o">]</span>
|
||||
<span class="n">divider_input</span> <span class="o">=</span> <span class="s2">"</span><span class="se">\n\n</span><span class="si">#{</span><span class="n">front</span><span class="si">}</span><span class="s2"> DIVIDER</span><span class="se">\n\n</span><span class="s2">"</span>
|
||||
<span class="n">divider_output</span> <span class="o">=</span> <span class="no">Regexp</span><span class="o">.</span><span class="n">new</span><span class="p">(</span>
|
||||
<span class="o">[</span> <span class="s2">"</span><span class="se">\\</span><span class="s2">n*"</span><span class="p">,</span>
|
||||
<span class="n">span</span><span class="p">,</span>
|
||||
<span class="no">Regexp</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="n">front</span><span class="p">),</span>
|
||||
<span class="s1">' DIVIDER'</span><span class="p">,</span>
|
||||
<span class="n">espan</span><span class="p">,</span>
|
||||
<span class="s2">"</span><span class="se">\\</span><span class="s2">n*"</span>
|
||||
<span class="o">].</span><span class="n">join</span><span class="p">,</span> <span class="no">Regexp</span><span class="o">::</span><span class="no">MULTILINE</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="n">front</span> <span class="o">=</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:multi</span><span class="o">][</span><span class="ss">:start</span><span class="o">]</span>
|
||||
<span class="n">back</span> <span class="o">=</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">][</span><span class="ss">:multi</span><span class="o">][</span><span class="ss">:end</span><span class="o">]</span>
|
||||
<span class="n">divider_input</span> <span class="o">=</span> <span class="s2">"</span><span class="se">\n\n</span><span class="si">#{</span><span class="n">front</span><span class="si">}</span><span class="se">\n</span><span class="s2">DIVIDER</span><span class="se">\n</span><span class="si">#{</span><span class="n">back</span><span class="si">}</span><span class="se">\n\n</span><span class="s2">"</span>
|
||||
<span class="n">divider_output</span> <span class="o">=</span> <span class="no">Regexp</span><span class="o">.</span><span class="n">new</span><span class="p">(</span>
|
||||
<span class="o">[</span> <span class="s2">"</span><span class="se">\\</span><span class="s2">n*"</span><span class="p">,</span>
|
||||
<span class="n">span</span><span class="p">,</span> <span class="no">Regexp</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="n">front</span><span class="p">),</span> <span class="n">espan</span><span class="p">,</span>
|
||||
<span class="s2">"</span><span class="se">\\</span><span class="s2">n"</span><span class="p">,</span>
|
||||
<span class="n">span</span><span class="p">,</span> <span class="s2">"DIVIDER"</span><span class="p">,</span> <span class="n">espan</span><span class="p">,</span>
|
||||
<span class="s2">"</span><span class="se">\\</span><span class="s2">n"</span><span class="p">,</span>
|
||||
<span class="n">span</span><span class="p">,</span> <span class="no">Regexp</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="n">back</span><span class="p">),</span> <span class="n">espan</span><span class="p">,</span>
|
||||
<span class="s2">"</span><span class="se">\\</span><span class="s2">n*"</span>
|
||||
<span class="o">].</span><span class="n">join</span><span class="p">,</span> <span class="no">Regexp</span><span class="o">::</span><span class="no">MULTILINE</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">end</span>
|
||||
|
||||
<span class="n">code_stream</span> <span class="o">=</span> <span class="n">code_blocks</span><span class="o">.</span><span class="n">join</span><span class="p">(</span> <span class="n">divider_input</span> <span class="p">)</span>
|
||||
|
||||
<span class="n">code_html</span> <span class="o">=</span>
|
||||
<span class="k">if</span> <span class="n">pygmentize?</span>
|
||||
<span class="n">highlight_pygmentize</span><span class="p">(</span><span class="n">code_stream</span><span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="n">highlight_webservice</span><span class="p">(</span><span class="n">code_stream</span><span class="p">)</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-36'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-36">¶</a>
|
||||
</div>
|
||||
<p>Do some post-processing on the pygments output to split things back
|
||||
into sections and remove partial <code><pre></code> blocks.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="n">code_html</span> <span class="o">=</span> <span class="n">code_html</span><span class="o">.</span>
|
||||
<span class="nb">split</span><span class="p">(</span><span class="n">divider_output</span><span class="p">)</span><span class="o">.</span>
|
||||
<span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">code</span><span class="o">|</span> <span class="n">code</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sr">/\n?<div class="highlight"><pre>/m</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span> <span class="p">}</span><span class="o">.</span>
|
||||
<span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">code</span><span class="o">|</span> <span class="n">code</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sr">/\n?<\/pre><\/div>\n/m</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span> <span class="p">}</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-37'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-37">¶</a>
|
||||
</div>
|
||||
<p>Lastly, combine the docs and code lists back into a list of two-tuples.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="n">docs_html</span><span class="o">.</span><span class="n">zip</span><span class="p">(</span><span class="n">code_html</span><span class="p">)</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-38'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-38">¶</a>
|
||||
</div>
|
||||
<p>We <code>popen</code> a read/write pygmentize process in the parent and
|
||||
then fork off a child process to write the input.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">highlight_pygmentize</span><span class="p">(</span><span class="n">code</span><span class="p">)</span>
|
||||
<span class="n">code_html</span> <span class="o">=</span> <span class="kp">nil</span>
|
||||
<span class="nb">open</span><span class="p">(</span><span class="s2">"|pygmentize -l </span><span class="si">#{</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:language</span><span class="o">]</span><span class="si">}</span><span class="s2"> -O encoding=utf-8 -f html"</span><span class="p">,</span> <span class="s1">'r+'</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">fd</span><span class="o">|</span>
|
||||
<span class="n">pid</span> <span class="o">=</span>
|
||||
<span class="nb">fork</span> <span class="p">{</span>
|
||||
<span class="n">fd</span><span class="o">.</span><span class="n">close_read</span>
|
||||
<span class="n">fd</span><span class="o">.</span><span class="n">write</span> <span class="n">code</span>
|
||||
<span class="n">fd</span><span class="o">.</span><span class="n">close_write</span>
|
||||
<span class="nb">exit!</span>
|
||||
<span class="p">}</span>
|
||||
<span class="n">fd</span><span class="o">.</span><span class="n">close_write</span>
|
||||
<span class="n">code_html</span> <span class="o">=</span> <span class="n">fd</span><span class="o">.</span><span class="n">read</span>
|
||||
<span class="n">fd</span><span class="o">.</span><span class="n">close_read</span>
|
||||
<span class="no">Process</span><span class="o">.</span><span class="n">wait</span><span class="p">(</span><span class="n">pid</span><span class="p">)</span>
|
||||
<span class="k">end</span>
|
||||
|
||||
<span class="n">code_html</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-39'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-39">¶</a>
|
||||
</div>
|
||||
<p>Pygments is not one of those things that’s trivial for a ruby user to install,
|
||||
so we’ll fall back on a webservice to highlight the code if it isn’t available.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">highlight_webservice</span><span class="p">(</span><span class="n">code</span><span class="p">)</span>
|
||||
<span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">.</span><span class="n">post_form</span><span class="p">(</span>
|
||||
<span class="no">URI</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s1">'http://pygments.appspot.com/'</span><span class="p">),</span>
|
||||
<span class="p">{</span><span class="s1">'lang'</span> <span class="o">=></span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:language</span><span class="o">]</span><span class="p">,</span> <span class="s1">'code'</span> <span class="o">=></span> <span class="n">code</span><span class="p">}</span>
|
||||
<span class="p">)</span><span class="o">.</span><span class="n">body</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-40'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-40">¶</a>
|
||||
</div>
|
||||
<p>And that’s it.</p>
|
||||
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
89
layout.html
Normal file
89
layout.html
Normal file
@ -0,0 +1,89 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||||
<title>layout.rb</title>
|
||||
<link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id='container'>
|
||||
<div id="background"></div>
|
||||
<div id="jump_to">
|
||||
Jump To …
|
||||
<div id="jump_wrapper">
|
||||
<div id="jump_page">
|
||||
<a class="source" href="rocco.html">rocco.rb</a>
|
||||
<a class="source" href="layout.html">layout.rb</a>
|
||||
<a class="source" href="tasks.html">tasks.rb</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table cellspacing=0 cellpadding=0>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class=docs><h1>layout.rb</h1></th>
|
||||
<th class=code></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr id='section-1'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-1">¶</a>
|
||||
</div>
|
||||
|
||||
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="nb">require</span> <span class="s1">'mustache'</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Rocco</span><span class="o">::</span><span class="no">Layout</span> <span class="o"><</span> <span class="no">Mustache</span>
|
||||
<span class="nb">self</span><span class="o">.</span><span class="n">template_path</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">doc</span><span class="p">,</span> <span class="n">file</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span>
|
||||
<span class="vi">@doc</span> <span class="o">=</span> <span class="n">doc</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">file</span><span class="o">.</span><span class="n">nil?</span>
|
||||
<span class="no">Rocco</span><span class="o">::</span><span class="no">Layout</span><span class="o">.</span><span class="n">template_file</span> <span class="o">=</span> <span class="n">file</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">title</span>
|
||||
<span class="no">File</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="vi">@doc</span><span class="o">.</span><span class="n">file</span><span class="p">)</span>
|
||||
<span class="k">end</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">sections</span>
|
||||
<span class="n">num</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
<span class="vi">@doc</span><span class="o">.</span><span class="n">sections</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">docs</span><span class="p">,</span><span class="n">code</span><span class="o">|</span>
|
||||
<span class="p">{</span>
|
||||
<span class="ss">:docs</span> <span class="o">=></span> <span class="n">docs</span><span class="p">,</span>
|
||||
<span class="ss">:docs?</span> <span class="o">=></span> <span class="o">!</span><span class="n">docs</span><span class="o">.</span><span class="n">empty?</span><span class="p">,</span>
|
||||
<span class="ss">:header?</span> <span class="o">=></span> <span class="sr">/^<h.>.+<\/h.>$/</span><span class="o">.</span><span class="n">match</span><span class="p">(</span> <span class="n">docs</span> <span class="p">),</span>
|
||||
|
||||
<span class="ss">:code</span> <span class="o">=></span> <span class="n">code</span><span class="p">,</span>
|
||||
<span class="ss">:code?</span> <span class="o">=></span> <span class="o">!</span><span class="n">code</span><span class="o">.</span><span class="n">empty?</span><span class="p">,</span>
|
||||
|
||||
<span class="ss">:empty?</span> <span class="o">=></span> <span class="p">(</span> <span class="n">code</span><span class="o">.</span><span class="n">empty?</span> <span class="o">&&</span> <span class="n">docs</span><span class="o">.</span><span class="n">empty?</span> <span class="p">),</span>
|
||||
<span class="ss">:num</span> <span class="o">=></span> <span class="p">(</span><span class="n">num</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">sources?</span>
|
||||
<span class="vi">@doc</span><span class="o">.</span><span class="n">sources</span><span class="o">.</span><span class="n">length</span> <span class="o">></span> <span class="mi">1</span>
|
||||
<span class="k">end</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">sources</span>
|
||||
<span class="vi">@doc</span><span class="o">.</span><span class="n">sources</span><span class="o">.</span><span class="n">sort</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">source</span><span class="o">|</span>
|
||||
<span class="p">{</span>
|
||||
<span class="ss">:path</span> <span class="o">=></span> <span class="n">source</span><span class="p">,</span>
|
||||
<span class="ss">:basename</span> <span class="o">=></span> <span class="no">File</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">source</span><span class="p">),</span>
|
||||
<span class="ss">:url</span> <span class="o">=></span> <span class="no">File</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">source</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'.'</span><span class="p">)</span><span class="o">[</span><span class="mi">0</span><span class="o">.</span><span class="n">.</span><span class="o">-</span><span class="mi">2</span><span class="o">].</span><span class="n">join</span><span class="p">(</span><span class="s1">'.'</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'.html'</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
449
rocco.html
Normal file
449
rocco.html
Normal file
@ -0,0 +1,449 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||||
<title>rocco.rb</title>
|
||||
<link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id='container'>
|
||||
<div id="background"></div>
|
||||
<div id="jump_to">
|
||||
Jump To …
|
||||
<div id="jump_wrapper">
|
||||
<div id="jump_page">
|
||||
<a class="source" href="rocco.html">rocco.rb</a>
|
||||
<a class="source" href="layout.html">layout.rb</a>
|
||||
<a class="source" href="tasks.html">tasks.rb</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table cellspacing=0 cellpadding=0>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class=docs><h1>rocco.rb</h1></th>
|
||||
<th class=code></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr id='section-1'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-1">¶</a>
|
||||
</div>
|
||||
<p><strong>Rocco</strong> is a Ruby port of <a href="http://jashkenas.github.com/docco/">Docco</a>, the quick-and-dirty,
|
||||
hundred-line-long, literate-programming-style documentation generator.</p>
|
||||
|
||||
<p>Rocco reads Ruby source files and produces annotated source documentation
|
||||
in HTML format. Comments are formatted with <a href="http://daringfireball.net/projects/markdown/">Markdown</a> and presented
|
||||
alongside syntax highlighted code so as to give an annotation effect.
|
||||
This page is the result of running Rocco against <a href="http://github.com/rtomayko/rocco/blob/master/lib/rocco.rb#commit">its own source file</a>.</p>
|
||||
|
||||
<p>Most of this was written while waiting for <a href="http://nodejs.org/">node.js</a> 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
|
||||
<a href="http://coffeescript.org/">CoffeeScript</a> and may be a bit easier to obtain and install in
|
||||
existing Ruby environments or where node doesn’t run yet.</p>
|
||||
|
||||
<p>Install Rocco with Rubygems:</p>
|
||||
|
||||
<pre><code>gem install rocco
|
||||
</code></pre>
|
||||
|
||||
<p>Once installed, the <code>rocco</code> command can be used to generate documentation
|
||||
for a set of Ruby source files:</p>
|
||||
|
||||
<pre><code>rocco lib/*.rb
|
||||
</code></pre>
|
||||
|
||||
<p>The HTML files are written to the current working directory.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-2'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
<h3>Prerequisites</h3>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-3'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
<p>We’ll need a Markdown library. <a href="http://github.com/rtomayko/rdiscount">RDiscount</a>, if we’re lucky. Otherwise,
|
||||
issue a warning and fall back on using BlueCloth.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="k">begin</span>
|
||||
<span class="nb">require</span> <span class="s1">'rdiscount'</span>
|
||||
<span class="k">rescue</span> <span class="no">LoadError</span> <span class="o">=></span> <span class="n">boom</span>
|
||||
<span class="nb">warn</span> <span class="s2">"WARNING: </span><span class="si">#{</span><span class="n">boom</span><span class="si">}</span><span class="s2">. Trying bluecloth."</span>
|
||||
<span class="nb">require</span> <span class="s1">'bluecloth'</span>
|
||||
<span class="no">Markdown</span> <span class="o">=</span> <span class="no">BlueCloth</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-4'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
<p>We use <a href="http://defunkt.github.com/mustache/">{{ mustache }}</a> for
|
||||
HTML templating.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="nb">require</span> <span class="s1">'mustache'</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-5'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
<p>We use <code>Net::HTTP</code> to highlight code via <a href="http://pygments.appspot.com">http://pygments.appspot.com</a></p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="nb">require</span> <span class="s1">'net/http'</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-6'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
<p>Code is run through <a href="http://pygments.org/">Pygments</a> for syntax
|
||||
highlighting. If it’s not installed, locally, use a webservice.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="kp">include</span> <span class="no">FileTest</span>
|
||||
<span class="k">if</span> <span class="o">!</span><span class="no">ENV</span><span class="o">[</span><span class="s1">'PATH'</span><span class="o">].</span><span class="n">split</span><span class="p">(</span><span class="s1">':'</span><span class="p">)</span><span class="o">.</span><span class="n">any?</span> <span class="p">{</span> <span class="o">|</span><span class="n">dir</span><span class="o">|</span> <span class="n">executable?</span><span class="p">(</span><span class="s2">"</span><span class="si">#{</span><span class="n">dir</span><span class="si">}</span><span class="s2">/pygmentize"</span><span class="p">)</span> <span class="p">}</span>
|
||||
<span class="nb">warn</span> <span class="s2">"WARNING: Pygments not found. Using webservice."</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-7'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
<h3>Public Interface</h3>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-8'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
<p><code>Rocco.new</code> takes a source <code>filename</code>, an optional list of source filenames
|
||||
for other documentation sources, an <code>options</code> hash, and an optional <code>block</code>.
|
||||
The <code>options</code> hash respects two members: <code>:language</code>, which specifies which
|
||||
Pygments lexer to use; and <code>:comment_chars</code>, which specifies the comment
|
||||
characters of the target language. The options default to <code>'ruby'</code> and <code>'#'</code>,
|
||||
respectively.
|
||||
When <code>block</code> is given, it must read the contents of the file using whatever
|
||||
means necessary and return it as a string. With no <code>block</code>, the file is read
|
||||
to retrieve data.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="k">class</span> <span class="nc">Rocco</span>
|
||||
<span class="no">VERSION</span> <span class="o">=</span> <span class="s1">'0.5'</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">sources</span><span class="o">=[]</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="p">{},</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
|
||||
<span class="vi">@file</span> <span class="o">=</span> <span class="n">filename</span>
|
||||
<span class="vi">@data</span> <span class="o">=</span>
|
||||
<span class="k">if</span> <span class="nb">block_given?</span>
|
||||
<span class="k">yield</span>
|
||||
<span class="k">else</span>
|
||||
<span class="no">File</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
|
||||
<span class="k">end</span>
|
||||
<span class="n">defaults</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="ss">:language</span> <span class="o">=></span> <span class="s1">'ruby'</span><span class="p">,</span>
|
||||
<span class="ss">:comment_chars</span> <span class="o">=></span> <span class="s1">'#'</span><span class="p">,</span>
|
||||
<span class="ss">:template_file</span> <span class="o">=></span> <span class="kp">nil</span>
|
||||
<span class="p">}</span>
|
||||
<span class="vi">@options</span> <span class="o">=</span> <span class="n">defaults</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
|
||||
<span class="vi">@sources</span> <span class="o">=</span> <span class="n">sources</span>
|
||||
<span class="vi">@comment_pattern</span> <span class="o">=</span> <span class="no">Regexp</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">"^</span><span class="se">\\</span><span class="s2">s*</span><span class="si">#{</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">]</span><span class="si">}</span><span class="se">\s</span><span class="s2">?"</span><span class="p">)</span>
|
||||
<span class="vi">@template_file</span> <span class="o">=</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:template_file</span><span class="o">]</span>
|
||||
<span class="vi">@sections</span> <span class="o">=</span> <span class="n">highlight</span><span class="p">(</span><span class="nb">split</span><span class="p">(</span><span class="n">parse</span><span class="p">(</span><span class="vi">@data</span><span class="p">)))</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-9'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
<p>The filename as given to <code>Rocco.new</code>.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="kp">attr_reader</span> <span class="ss">:file</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-10'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
<p>A list of two-tuples representing each <em>section</em> of the source file. Each
|
||||
item in the list has the form: <code>[docs_html, code_html]</code>, where both
|
||||
elements are strings containing the documentation and source code HTML,
|
||||
respectively.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="kp">attr_reader</span> <span class="ss">:sections</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-11'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-11">¶</a>
|
||||
</div>
|
||||
<p>A list of all source filenames included in the documentation set. Useful
|
||||
for building an index of other files.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="kp">attr_reader</span> <span class="ss">:sources</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-12'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-12">¶</a>
|
||||
</div>
|
||||
<p>An absolute path to a file that ought be used as a template for the
|
||||
HTML-rendered documentation.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="kp">attr_reader</span> <span class="ss">:template_file</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-13'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-13">¶</a>
|
||||
</div>
|
||||
<p>Generate HTML output for the entire document.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="nb">require</span> <span class="s1">'rocco/layout'</span>
|
||||
<span class="k">def</span> <span class="nf">to_html</span>
|
||||
<span class="no">Rocco</span><span class="o">::</span><span class="no">Layout</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="nb">self</span><span class="p">,</span> <span class="vi">@template_file</span><span class="p">)</span><span class="o">.</span><span class="n">render</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-14'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-14">¶</a>
|
||||
</div>
|
||||
<h3>Internal Parsing and Highlighting</h3>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-15'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-15">¶</a>
|
||||
</div>
|
||||
<p>Parse the raw file data into a list of two-tuples. Each tuple has the
|
||||
form <code>[docs, code]</code> where both elements are arrays containing the
|
||||
raw lines parsed from the input file. The first line is ignored if it
|
||||
is a shebang line.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
|
||||
<span class="n">sections</span> <span class="o">=</span> <span class="o">[]</span>
|
||||
<span class="n">docs</span><span class="p">,</span> <span class="n">code</span> <span class="o">=</span> <span class="o">[]</span><span class="p">,</span> <span class="o">[]</span>
|
||||
<span class="n">lines</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">lines</span><span class="o">.</span><span class="n">shift</span> <span class="k">if</span> <span class="n">lines</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">=~</span> <span class="sr">/^\#\!/</span>
|
||||
<span class="n">lines</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">line</span><span class="o">|</span>
|
||||
<span class="k">case</span> <span class="n">line</span>
|
||||
<span class="k">when</span> <span class="vi">@comment_pattern</span>
|
||||
<span class="k">if</span> <span class="n">code</span><span class="o">.</span><span class="n">any?</span>
|
||||
<span class="n">sections</span> <span class="o"><<</span> <span class="o">[</span><span class="n">docs</span><span class="p">,</span> <span class="n">code</span><span class="o">]</span>
|
||||
<span class="n">docs</span><span class="p">,</span> <span class="n">code</span> <span class="o">=</span> <span class="o">[]</span><span class="p">,</span> <span class="o">[]</span>
|
||||
<span class="k">end</span>
|
||||
<span class="n">docs</span> <span class="o"><<</span> <span class="n">line</span>
|
||||
<span class="k">else</span>
|
||||
<span class="n">code</span> <span class="o"><<</span> <span class="n">line</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span>
|
||||
<span class="n">sections</span> <span class="o"><<</span> <span class="o">[</span><span class="n">docs</span><span class="p">,</span> <span class="n">code</span><span class="o">]</span> <span class="k">if</span> <span class="n">docs</span><span class="o">.</span><span class="n">any?</span> <span class="o">||</span> <span class="n">code</span><span class="o">.</span><span class="n">any?</span>
|
||||
<span class="n">sections</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-16'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-16">¶</a>
|
||||
</div>
|
||||
<p>Take the list of paired <em>sections</em> two-tuples and split into two
|
||||
separate lists: one holding the comments with leaders removed and
|
||||
one with the code blocks.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">split</span><span class="p">(</span><span class="n">sections</span><span class="p">)</span>
|
||||
<span class="n">docs_blocks</span><span class="p">,</span> <span class="n">code_blocks</span> <span class="o">=</span> <span class="o">[]</span><span class="p">,</span> <span class="o">[]</span>
|
||||
<span class="n">sections</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">docs</span><span class="p">,</span><span class="n">code</span><span class="o">|</span>
|
||||
<span class="n">docs_blocks</span> <span class="o"><<</span> <span class="n">docs</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">line</span><span class="o">|</span> <span class="n">line</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="vi">@comment_pattern</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span> <span class="p">}</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">code_blocks</span> <span class="o"><<</span> <span class="n">code</span><span class="o">.</span><span class="n">map</span> <span class="k">do</span> <span class="o">|</span><span class="n">line</span><span class="o">|</span>
|
||||
<span class="n">tabs</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sr">/^(\t+)/</span><span class="p">)</span>
|
||||
<span class="n">tabs</span> <span class="p">?</span> <span class="n">line</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sr">/^\t+/</span><span class="p">,</span> <span class="s1">' '</span> <span class="o">*</span> <span class="n">tabs</span><span class="o">.</span><span class="n">captures</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="n">length</span><span class="p">)</span> <span class="p">:</span> <span class="n">line</span>
|
||||
<span class="k">end</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="k">end</span>
|
||||
<span class="o">[</span><span class="n">docs_blocks</span><span class="p">,</span> <span class="n">code_blocks</span><span class="o">]</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-17'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-17">¶</a>
|
||||
</div>
|
||||
<p>Take the result of <code>split</code> and apply Markdown formatting to comments and
|
||||
syntax highlighting to source code.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">highlight</span><span class="p">(</span><span class="n">blocks</span><span class="p">)</span>
|
||||
<span class="n">docs_blocks</span><span class="p">,</span> <span class="n">code_blocks</span> <span class="o">=</span> <span class="n">blocks</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-18'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-18">¶</a>
|
||||
</div>
|
||||
<p>Combine all docs blocks into a single big markdown document with section
|
||||
dividers and run through the Markdown processor. Then split it back out
|
||||
into separate sections.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="n">markdown</span> <span class="o">=</span> <span class="n">docs_blocks</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n\n</span><span class="s2">##### DIVIDER</span><span class="se">\n\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">docs_html</span> <span class="o">=</span> <span class="no">Markdown</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">markdown</span><span class="p">,</span> <span class="ss">:smart</span><span class="p">)</span><span class="o">.</span>
|
||||
<span class="n">to_html</span><span class="o">.</span>
|
||||
<span class="nb">split</span><span class="p">(</span><span class="sr">/\n*<h5>DIVIDER<\/h5>\n*/m</span><span class="p">)</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-19'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-19">¶</a>
|
||||
</div>
|
||||
<p>Combine all code blocks into a single big stream and run through either
|
||||
<code>pygmentize(1)</code> or <a href="http://pygments.appspot.com">http://pygments.appspot.com</a></p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="n">code_stream</span> <span class="o">=</span> <span class="n">code_blocks</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n\n</span><span class="si">#{</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">]</span><span class="si">}</span><span class="s2"> DIVIDER</span><span class="se">\n\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">'PATH'</span><span class="o">].</span><span class="n">split</span><span class="p">(</span><span class="s1">':'</span><span class="p">)</span><span class="o">.</span><span class="n">any?</span> <span class="p">{</span> <span class="o">|</span><span class="n">dir</span><span class="o">|</span> <span class="n">executable?</span><span class="p">(</span><span class="s2">"</span><span class="si">#{</span><span class="n">dir</span><span class="si">}</span><span class="s2">/pygmentize"</span><span class="p">)</span> <span class="p">}</span>
|
||||
<span class="n">code_html</span> <span class="o">=</span> <span class="n">highlight_pygmentize</span><span class="p">(</span><span class="n">code_stream</span><span class="p">)</span>
|
||||
<span class="k">else</span>
|
||||
<span class="n">code_html</span> <span class="o">=</span> <span class="n">highlight_webservice</span><span class="p">(</span><span class="n">code_stream</span><span class="p">)</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-20'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-20">¶</a>
|
||||
</div>
|
||||
<p>Do some post-processing on the pygments output to split things back
|
||||
into sections and remove partial <code><pre></code> blocks.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="n">code_html</span> <span class="o">=</span> <span class="n">code_html</span><span class="o">.</span>
|
||||
<span class="nb">split</span><span class="p">(</span><span class="sr">/\n*<span class="c.?"></span><span class="si">#{</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:comment_chars</span><span class="o">]</span><span class="si">}</span><span class="sr"> DIVIDER<\/span>\n*/m</span><span class="p">)</span><span class="o">.</span>
|
||||
<span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">code</span><span class="o">|</span> <span class="n">code</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sr">/\n?<div class="highlight"><pre>/m</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span> <span class="p">}</span><span class="o">.</span>
|
||||
<span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">code</span><span class="o">|</span> <span class="n">code</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sr">/\n?<\/pre><\/div>\n/m</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span> <span class="p">}</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-21'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-21">¶</a>
|
||||
</div>
|
||||
<p>Lastly, combine the docs and code lists back into a list of two-tuples.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="n">docs_html</span><span class="o">.</span><span class="n">zip</span><span class="p">(</span><span class="n">code_html</span><span class="p">)</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-22'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-22">¶</a>
|
||||
</div>
|
||||
<p>We <code>popen</code> a read/write pygmentize process in the parent and
|
||||
then fork off a child process to write the input.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">highlight_pygmentize</span><span class="p">(</span><span class="n">code</span><span class="p">)</span>
|
||||
<span class="n">code_html</span> <span class="o">=</span> <span class="kp">nil</span>
|
||||
<span class="nb">open</span><span class="p">(</span><span class="s2">"|pygmentize -l </span><span class="si">#{</span><span class="vi">@options</span><span class="o">[</span><span class="ss">:language</span><span class="o">]</span><span class="si">}</span><span class="s2"> -O encoding=utf-8 -f html"</span><span class="p">,</span> <span class="s1">'r+'</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">fd</span><span class="o">|</span>
|
||||
<span class="n">pid</span> <span class="o">=</span>
|
||||
<span class="nb">fork</span> <span class="p">{</span>
|
||||
<span class="n">fd</span><span class="o">.</span><span class="n">close_read</span>
|
||||
<span class="n">fd</span><span class="o">.</span><span class="n">write</span> <span class="n">code</span>
|
||||
<span class="n">fd</span><span class="o">.</span><span class="n">close_write</span>
|
||||
<span class="nb">exit!</span>
|
||||
<span class="p">}</span>
|
||||
<span class="n">fd</span><span class="o">.</span><span class="n">close_write</span>
|
||||
<span class="n">code_html</span> <span class="o">=</span> <span class="n">fd</span><span class="o">.</span><span class="n">read</span>
|
||||
<span class="n">fd</span><span class="o">.</span><span class="n">close_read</span>
|
||||
<span class="no">Process</span><span class="o">.</span><span class="n">wait</span><span class="p">(</span><span class="n">pid</span><span class="p">)</span>
|
||||
<span class="k">end</span>
|
||||
|
||||
<span class="n">code_html</span>
|
||||
<span class="k">end</span>
|
||||
</pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-23'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-23">¶</a>
|
||||
</div>
|
||||
<p>Pygments is not one of those things that’s trivial for a ruby user to install,
|
||||
so we’ll fall back on a webservice to highlight the code if it isn’t available.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">highlight_webservice</span><span class="p">(</span><span class="n">code</span><span class="p">)</span>
|
||||
<span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">.</span><span class="n">post_form</span><span class="p">(</span>
|
||||
<span class="no">URI</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s1">'http://pygments.appspot.com/'</span><span class="p">),</span>
|
||||
<span class="p">{</span><span class="s1">'lang'</span> <span class="o">=></span> <span class="vi">@options</span><span class="o">[</span><span class="s1">'language'</span><span class="o">]</span><span class="p">,</span> <span class="s1">'code'</span> <span class="o">=></span> <span class="n">code</span><span class="p">}</span>
|
||||
<span class="p">)</span><span class="o">.</span><span class="n">body</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-24'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-24">¶</a>
|
||||
</div>
|
||||
<p>And that’s it.</p>
|
||||
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
242
tasks.html
Normal file
242
tasks.html
Normal file
@ -0,0 +1,242 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||||
<title>tasks.rb</title>
|
||||
<link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id='container'>
|
||||
<div id="background"></div>
|
||||
<div id="jump_to">
|
||||
Jump To …
|
||||
<div id="jump_wrapper">
|
||||
<div id="jump_page">
|
||||
<a class="source" href="rocco.html">rocco.rb</a>
|
||||
<a class="source" href="layout.html">layout.rb</a>
|
||||
<a class="source" href="tasks.html">tasks.rb</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table cellspacing=0 cellpadding=0>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class=docs><h1>tasks.rb</h1></th>
|
||||
<th class=code></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr id='section-1'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-1">¶</a>
|
||||
</div>
|
||||
<h3>Rocco Rake Tasks</h3>
|
||||
|
||||
<p>To use the Rocco Rake tasks, require <code>rocco/tasks</code> in your <code>Rakefile</code>
|
||||
and define a Rake task with <code>rocco_task</code>. In its simplest form, <code>rocco_task</code>
|
||||
takes the path to a destination directory where HTML docs should be built:</p>
|
||||
|
||||
<pre><code>require 'rocco/tasks'
|
||||
|
||||
desc "Build Rocco Docs"
|
||||
Rocco::make 'docs/'
|
||||
</code></pre>
|
||||
|
||||
<p>This creates a <code>:rocco</code> rake task, which can then be run with:</p>
|
||||
|
||||
<pre><code>rake rocco
|
||||
</code></pre>
|
||||
|
||||
<p>It’s a good idea to guard against Rocco not being available, since your
|
||||
Rakefile will fail to load otherwise. Consider doing something like this,
|
||||
so that your Rakefile will still work</p>
|
||||
|
||||
<pre><code>begin
|
||||
require 'rocco/tasks'
|
||||
Rocco::make 'docs/'
|
||||
rescue LoadError
|
||||
warn "#$! -- rocco tasks not loaded."
|
||||
task :rocco
|
||||
end
|
||||
</code></pre>
|
||||
|
||||
<p>It’s also possible to pass a glob pattern:</p>
|
||||
|
||||
<pre><code>Rocco::make 'html/', 'lib/thing/**/*.rb'
|
||||
</code></pre>
|
||||
|
||||
<p>Or a list of glob patterns:</p>
|
||||
|
||||
<pre><code>Rocco::make 'html/', ['lib/thing.rb', 'lib/thing/*.rb']
|
||||
</code></pre>
|
||||
|
||||
<p>Finally, it is also possible to specify which Pygments language you would
|
||||
like to use to highlight the code, as well as the comment characters for the
|
||||
language in the <code>options</code> hash:</p>
|
||||
|
||||
<p> Rocco::make ‘html/’, ‘lib/thing/<em>*/</em>.rb’, {</p>
|
||||
|
||||
<pre><code> :language => 'io',
|
||||
:comment_chars => '#'
|
||||
</code></pre>
|
||||
|
||||
<p> }</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-2'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-2">¶</a>
|
||||
</div>
|
||||
<p>Might be nice to defer this until we actually need to build docs but this
|
||||
will have to do for now.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="nb">require</span> <span class="s1">'rocco'</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-3'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-3">¶</a>
|
||||
</div>
|
||||
<p>Reopen the Rocco class and add a <code>make</code> class method. This is a simple bit
|
||||
of sugar over <code>Rocco::Task.new</code>. If you want your Rake task to be named
|
||||
something other than <code>:rocco</code>, you can use <code>Rocco::Task</code> directly.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre><span class="k">class</span> <span class="nc">Rocco</span>
|
||||
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">make</span><span class="p">(</span><span class="n">dest</span><span class="o">=</span><span class="s1">'docs/'</span><span class="p">,</span> <span class="n">source_files</span><span class="o">=</span><span class="s1">'lib/**/*.rb'</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="p">{})</span>
|
||||
<span class="no">Task</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">:rocco</span><span class="p">,</span> <span class="n">dest</span><span class="p">,</span> <span class="n">source_files</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-4'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-4">¶</a>
|
||||
</div>
|
||||
<p><code>Rocco::Task.new</code> takes a task name, the destination directory docs
|
||||
should be built under, and a source file pattern or file list.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">class</span> <span class="nc">Task</span>
|
||||
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">task_name</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s1">'docs/'</span><span class="p">,</span> <span class="n">sources</span><span class="o">=</span><span class="s1">'lib/**/*.rb'</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="p">{})</span>
|
||||
<span class="vi">@name</span> <span class="o">=</span> <span class="n">task_name</span>
|
||||
<span class="vi">@dest</span> <span class="o">=</span> <span class="n">dest</span><span class="o">[-</span><span class="mi">1</span><span class="o">]</span> <span class="o">==</span> <span class="sc">?/</span> <span class="p">?</span> <span class="n">dest</span> <span class="p">:</span> <span class="s2">"</span><span class="si">#{</span><span class="n">dest</span><span class="si">}</span><span class="s2">/"</span>
|
||||
<span class="vi">@sources</span> <span class="o">=</span> <span class="no">FileList</span><span class="o">[</span><span class="n">sources</span><span class="o">]</span>
|
||||
<span class="vi">@options</span> <span class="o">=</span> <span class="n">options</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-5'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-5">¶</a>
|
||||
</div>
|
||||
<p>Make sure there’s a <code>directory</code> task defined for our destination.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="n">define_directory_task</span> <span class="vi">@dest</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-6'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-6">¶</a>
|
||||
</div>
|
||||
<p>Run over the source file list, constructing destination filenames
|
||||
and defining file tasks.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="vi">@sources</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">source_file</span><span class="o">|</span>
|
||||
<span class="n">dest_file</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">source_file</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'.'</span><span class="p">)</span><span class="o">[</span><span class="mi">0</span><span class="o">.</span><span class="n">.</span><span class="o">-</span><span class="mi">2</span><span class="o">].</span><span class="n">join</span><span class="p">(</span><span class="s1">'.'</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'.html'</span>
|
||||
<span class="n">define_file_task</span> <span class="n">source_file</span><span class="p">,</span> <span class="s2">"</span><span class="si">#{</span><span class="vi">@dest</span><span class="si">}#{</span><span class="n">dest_file</span><span class="si">}</span><span class="s2">"</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-7'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-7">¶</a>
|
||||
</div>
|
||||
<p>If <code>rake/clean</code> was required, add the generated files to the list.
|
||||
That way all Rocco generated are removed when running <code>rake clean</code>.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="no">CLEAN</span><span class="o">.</span><span class="n">include</span> <span class="s2">"</span><span class="si">#{</span><span class="vi">@dest</span><span class="si">}#{</span><span class="n">dest_file</span><span class="si">}</span><span class="s2">"</span> <span class="k">if</span> <span class="n">defined?</span> <span class="no">CLEAN</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-8'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-8">¶</a>
|
||||
</div>
|
||||
<p>Define the destination directory task and make the <code>:rocco</code> task depend
|
||||
on it. This causes the destination directory to be created if it doesn’t
|
||||
already exist.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">define_directory_task</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
|
||||
<span class="n">directory</span> <span class="n">path</span>
|
||||
<span class="n">task</span> <span class="vi">@name</span> <span class="o">=></span> <span class="n">path</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-9'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-9">¶</a>
|
||||
</div>
|
||||
<p>Setup a <code>file</code> task for a single Rocco output file (<code>dest_file</code>). It
|
||||
depends on the source file, the destination directory, and all of Rocco’s
|
||||
internal source code, so that the destination file is rebuilt when any of
|
||||
those changes.</p>
|
||||
|
||||
<p>You can run these tasks directly with Rake:</p>
|
||||
|
||||
<pre><code>rake docs/foo.html docs/bar.html
|
||||
</code></pre>
|
||||
|
||||
<p>… would generate the <code>foo.html</code> and <code>bar.html</code> files but only if they
|
||||
don’t already exist or one of their dependencies was changed.</p>
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">define_file_task</span><span class="p">(</span><span class="n">source_file</span><span class="p">,</span> <span class="n">dest_file</span><span class="p">)</span>
|
||||
<span class="n">prerequisites</span> <span class="o">=</span> <span class="o">[</span><span class="vi">@dest</span><span class="p">,</span> <span class="n">source_file</span><span class="o">]</span> <span class="o">+</span> <span class="n">rocco_source_files</span>
|
||||
<span class="n">file</span> <span class="n">dest_file</span> <span class="o">=></span> <span class="n">prerequisites</span> <span class="k">do</span> <span class="o">|</span><span class="n">f</span><span class="o">|</span>
|
||||
<span class="n">verbose</span> <span class="p">{</span> <span class="nb">puts</span> <span class="s2">"rocco: </span><span class="si">#{</span><span class="n">source_file</span><span class="si">}</span><span class="s2"> -> </span><span class="si">#{</span><span class="n">dest_file</span><span class="si">}</span><span class="s2">"</span> <span class="p">}</span>
|
||||
<span class="n">rocco</span> <span class="o">=</span> <span class="no">Rocco</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">source_file</span><span class="p">,</span> <span class="vi">@sources</span><span class="o">.</span><span class="n">to_a</span><span class="p">,</span> <span class="vi">@options</span><span class="p">)</span>
|
||||
<span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">dest_file</span><span class="p">,</span> <span class="s1">'wb'</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">fd</span><span class="o">|</span> <span class="n">fd</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">rocco</span><span class="o">.</span><span class="n">to_html</span><span class="p">)</span> <span class="p">}</span>
|
||||
<span class="k">end</span>
|
||||
<span class="n">task</span> <span class="vi">@name</span> <span class="o">=></span> <span class="n">dest_file</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id='section-10'>
|
||||
<td class=docs>
|
||||
<div class="pilwrap">
|
||||
<a class="pilcrow" href="#section-10">¶</a>
|
||||
</div>
|
||||
<p>Return a <code>FileList</code> that includes all of Roccos source files. This causes
|
||||
output files to be regenerated properly when someone upgrades the Rocco
|
||||
library.</p>
|
||||
|
||||
</td>
|
||||
<td class=code>
|
||||
<div class='highlight'><pre> <span class="k">def</span> <span class="nf">rocco_source_files</span>
|
||||
<span class="n">libdir</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">expand_path</span><span class="p">(</span><span class="s1">'../..'</span><span class="p">,</span> <span class="bp">__FILE__</span><span class="p">)</span>
|
||||
<span class="no">FileList</span><span class="o">[</span><span class="s2">"</span><span class="si">#{</span><span class="n">libdir</span><span class="si">}</span><span class="s2">/rocco.rb"</span><span class="p">,</span> <span class="s2">"</span><span class="si">#{</span><span class="n">libdir</span><span class="si">}</span><span class="s2">/rocco/**"</span><span class="o">]</span>
|
||||
<span class="k">end</span>
|
||||
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span></pre></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
Loading…
Reference in New Issue
Block a user