2010-03-11 11:25:35 +00:00
<!DOCTYPE html>
< html >
< head >
< meta http-equiv = "content-type" content = "text/html;charset=utf-8" >
< title > rocco.rb< / title >
2011-03-05 12:55:05 +00:00
< link rel = "stylesheet" href = "http://github.com/jashkenas/docco/raw/0.3.0/resources/docco.css" >
2010-03-11 11:25:35 +00:00
< / head >
< body >
< div id = 'container' >
< div id = "background" > < / div >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< 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 >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-1" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< tr id = 'section-Prerequisites' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-Prerequisites" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / div >
< h3 > Prerequisites< / h3 >
< / td >
< td class = code >
< div class = 'highlight' > < pre > < / pre > < / div >
< / td >
< / tr >
< tr id = 'section-3' >
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-3" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< 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 >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-4" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< / div >
< p > Code is run through < a href = "http://pygments.org/" > Pygments< / a > for syntax
2011-03-05 12:55:05 +00:00
highlighting. If it’ s not installed, locally, use a webservice.< / p >
2010-03-11 11:25:35 +00:00
< / td >
< td class = code >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< span class = "k" > end< / span > < / pre > < / div >
< / td >
< / tr >
2011-03-05 12:55:05 +00:00
< tr id = 'section-Public_Interface' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-Public_Interface" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / div >
< h3 > Public Interface< / h3 >
< / td >
< td class = code >
< div class = 'highlight' > < pre > < / pre > < / div >
< / td >
< / tr >
2011-03-05 12:55:05 +00:00
< tr id = 'section-8' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-8" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / div >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< / td >
< td class = code >
< div class = 'highlight' > < pre > < span class = "k" > class< / span > < span class = "nc" > Rocco< / span >
2011-03-05 12:55:05 +00:00
< span class = "no" > VERSION< / span > < span class = "o" > =< / span > < span class = "s1" > ' 0.6' < / span >
2010-03-11 11:25:35 +00:00
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< 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 >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< span class = "k" > end< / span > < / pre > < / div >
< / td >
< / tr >
2011-03-05 12:55:05 +00:00
< tr id = 'section-16' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-16" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< tr id = 'section-17' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< tr id = 'section-19' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< span class = "k" > end< / span > < / pre > < / div >
< / td >
< / tr >
2011-03-05 12:55:05 +00:00
< tr id = 'section-Helper_Functions' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-Helper_Functions" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / div >
2011-03-05 12:55:05 +00:00
< h2 > Helper Functions< / h2 >
2010-03-11 11:25:35 +00:00
< / td >
< td class = code >
< div class = 'highlight' > < pre > < / pre > < / div >
< / td >
< / tr >
2011-03-05 12:55:05 +00:00
< 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' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< / 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
2011-03-05 12:55:05 +00:00
raw lines parsed from the input file, comment characters stripped.< / p >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< 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 >
2011-03-05 12:55:05 +00:00
< span class = "n" > normalize_leading_spaces< / span > < span class = "p" > (< / span > < span class = "n" > sections< / span > < span class = "p" > )< / span >
2010-03-11 11:25:35 +00:00
< span class = "k" > end< / span > < / pre > < / div >
< / td >
< / tr >
2011-03-05 12:55:05 +00:00
< tr id = 'section-31' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< 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 >
2011-03-05 12:55:05 +00:00
< tr id = 'section-33' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-33" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< tr id = 'section-34' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-34" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< tr id = 'section-35' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-35" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / div >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< / td >
< td class = code >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< / td >
< / tr >
2011-03-05 12:55:05 +00:00
< tr id = 'section-36' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-36" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< span class = "nb" > split< / span > < span class = "p" > (< / span > < span class = "n" > divider_output< / span > < span class = "p" > )< / span > < span class = "o" > .< / span >
2010-03-11 11:25:35 +00:00
< 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 >
2011-03-05 12:55:05 +00:00
< tr id = 'section-37' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-37" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / 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 >
2011-03-05 12:55:05 +00:00
< 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 >
2010-03-11 11:25:35 +00:00
< span class = "k" > end< / span >
< span class = "k" > end< / span > < / pre > < / div >
< / td >
< / tr >
2011-03-05 12:55:05 +00:00
< tr id = 'section-40' >
2010-03-11 11:25:35 +00:00
< td class = docs >
2011-03-05 12:55:05 +00:00
< div class = "pilwrap" >
< a class = "pilcrow" href = "#section-40" > ¶ < / a >
2010-03-11 11:25:35 +00:00
< / div >
< p > And that’ s it.< / p >
< / td >
< td class = code >
< div class = 'highlight' > < pre > < / pre > < / div >
< / td >
< / tr >
2011-03-05 12:55:05 +00:00
< / table >
2010-03-11 11:25:35 +00:00
< / div >
< / body >