Rack::Codehighlighter middleware

Rack::Codehighlighter provides a thin wrapper over a bunch of code highlighters to make their usage as generic possible.

  • ultraviolet
  • coderay
  • syntax
  • prettify
  • censor (a fake highlighter used in example below)

Install the gem with:

sudo gem install wbzyl-rack-codehighlighter -s http://gems.github.com

The middleware looks for code blocks to be highlighted in HTML produced by application. For each block found it calls requested highlighter. Below we ask coderay to highlight all pre elements:

use Rack::Codehighlighter, :coderay, :element => "pre", :pattern => /\A:::(\w+)\s*\n/

The middleware uses the pattern to learn what language the code block contains, for example

<pre>:::ruby
puts "hello world"
</pre>

Plain description what the pattern says: If the element contents begins with three colons, the text following the colons, up to the end of line, identifies the language. The text matched by the pattern is removed from the code block before processing.

The above example could be shortened to:

use Rack::Codehighlighter, :coderay

because the default options values are used.

Normalization:

  • Highlighted code is always wrapped with pre element with attributes appropriate for codehighlighter used.
  • Language names are taken from Ultraviolet.

Using with Rack application

Rack::Codehighlighter can be used with any Rack application, for example with a Sinatra application. If your application includes a rackup file or uses Rack::Builder to construct the application pipeline, simply require and use as follows:

gem 'coderay' # get one of supported highlighters 
require 'coderay'

gem 'wbzyl-rack-codehighlighter'
require 'rack/codehighlighter'

use Rack::Codehighlighter, :coderay
run app

Remember to include in the layout an appropriate stylesheet (look into examples/public/stylesheets directory for sample stylesheets).

Using with Rails

In order to use include the following in a Rails application config/environment.rb file:

require 'coderay' # get one of supported highlighters 

require 'rack/codehighlighter'

Rails::Initializer.run do |config|  
  config.gem 'coderay'
  config.gem 'wbzyl-rack-codehighlighter'

  config.middleware.use Rack::Codehighlighter, :coderay
end  

Check the Rack configuration:

rake middleware

Remember to include in the layout an appropriate stylesheet (look into examples/public/stylesheets directory for sample stylesheets).

Configuration examples

Coderay:

use Rack::Codehighlighter, :coderay,
  :element => "pre", :pattern => /\A:::(\w+)\s*\n/, :logging => false

Ultraviolet:

use Rack::Codehighlighter, :ultraviolet, :theme => "dawn", :lines => false,
  :element => "pre", :pattern => /\A:::(\w+)\s*\n/, :logging => false

Prettify:

use Rack::Codehighlighter, :prettify,
  :element => "pre", :pattern => /\A:::(\w+)\s*\n/, :logging => false

Syntax:

use Rack::Codehighlighter, :syntax,
  :element => "pre", :pattern => /\A:::(\w+)\s*\n/, :logging => false

Censor:

use Rack::Codehighlighter, :censor, :reason => "[[--  ugly code removed  --]]",
  :element => "pre", :pattern => /\A:::(\w+)\s*\n/, :logging => false

In the above examples, the default value of each option is used.

All highlighters use pre element to wrap highlighted code. In Markdown, Maruku and RDiscount templates code is wrapped with pre>code. To remove an extra nesting the :markdown option should be used:

use Rack::Codehighlighter, :coderay, :markdown => true,
  :element => "pre>code", :pattern => /\A:::(\w+)\s*\n/, :logging => false

A simple example with inline template

# example.rb

require 'rubygems'

gem 'sinatra', '>=0.9.0'
require 'sinatra'

gem 'wbzyl-rack-codehighlighter', '>=0.2.0'
require 'rack/codehighlighter'

use Rack::Codehighlighter, :censor, :reason => '[[--difficult code removed--]]'

get "/" do
  erb :hello
end

__END__

Run the above example with:

ruby example.rb

The results are accessible from http://localhost:4567.

Why using middleware for code highlighting is awesome?

In each piece of code inserted into html we must change: < to &lt;. This is annoying thing. Each(? prettify, dp-) pure javascript highlighter has this defect.

In pre-Rack applications era possible approaches were:

  • gems; conection to methods responsible for code highlighting is obtrusive, i.e. via plugin + additional markup

Analyze packages mentioned at the The Ruby Toolbox page: Syntax Highlighting

Links:

http://carboni.ca/projects/harsh/  
  unless HAML is used
http://redclothcoderay.rubyforge.org/  
http://github.com/augustl/redcloth-with-coderay
  how to use with Rails
  does't degrade to html: new source tag
http://github.com/arya/tm_syntax_highlighting/
  how to connect to rails/sinatra?

Ruby tips from me, your idol: I can not tell you how much time I’ve wasted trying to add in some cool feature into rails. I would dig into the rails internals, override methods, do all kinds of tricky stuff. I thought I was awesome. A month later rails comes out with some cool new feature, I update rails and everything explodes.

Conclusion: highlighting via plugins is doomed to explode sooner or later.

Supported highlighters

These currently include: Syntax (fast), Coderay (very fast), Ultraviolet (slow, but highlights almost any language).

Syntax

Languages supported by Syntax:

  • xml
  • ruby

Coderay

Languages supported by Coderay:

  • C, CSS
  • Delphi, diff
  • HTML, RHTML (Rails), Nitro-XHTML
  • Java, JavaScript, JSON
  • Ruby
  • YAML

Google Code Prettify, pure Javascript

Languages supported by Prettify:

  • css, lisp, hs, lua, sql, vb, wiki,
  • bsh, c, cc, cpp, cs, csh, cyc, cv, htm, html,
  • java, js, m, mxml, perl, pl, pm, py, rb, sh,
  • xhtml, xml, xsl

Ultraviolet

The ultraviolet gem needs oniguruma regexp library.

On Fedora install the library with:

sudo yum install oniguruma

For installation instruction from sources, see Carbonica

Now, install the gem:

sudo gem install ultraviolet

See also Ultraviolet themes gallery

Ultraviolet supports almost any language:

  • actionscript, active4d, active4d_html, active4d_ini, active4d_library, ada, antlr, apache, applescript, asp, asp_vb.net
  • bibtex, blog_html, blog_markdown, blog_text, blog_textile, build, bulletin_board
  • c, c++, cake, camlp4, cm, coldusion, context_free, cs, css, css_experimental, csv
  • d, diff, dokuwiki, dot, doxygen, dylan
  • eiffel, erlang, f-script, fortran, fxscript
  • greasemonkey, gri, groovy, gtd, gtdalt
  • haml, haskell, html, html-asp, html_django, html_for_asp.net, html_mason, html_rails, html_tcl
  • icalendar, inform, ini, installer_distribution_script, io
  • java, javaproperties, javascript, javascript_+_prototype, javascript_+_prototype_bracketed, jquery_javascript, json
  • languagedefinition, latex, latex_beamer, latex_log, latex_memoir, lexflex, lighttpd, lilypond, lisp, literate_haskell, logo, logtalk, lua
  • m, macports_portfile, mail, makefile, man, markdown, mediawiki, mel, mips, mod_perl, modula-3, moinmoin, mootools, movable_type, multimarkdown
  • objective-c, objective-c++, ocaml, ocamllex, ocamlyacc, opengl
  • pascal, perl, php, plain_text, pmwiki, postscript, processing, prolog, property_list, python, python_django
  • qmake_project, qt_c++, quake3_config
  • r, r_console, ragel, rd_r_documentation, regexp, regular_expressions_oniguruma, regular_expressions_python, release_notes remind, restructuredtext, rez, ruby, ruby_experimental, ruby_on_rails
  • s5, scheme, scilab, setext, shell-unix-generic, slate, smarty, sql, sql_rails, ssh-config, standard_ml, strings_file, subversion_commit_message, sweave, swig
  • tcl, template_toolkit, tex, tex_math, textile, tsv, twiki, txt2tags
  • vectorscript
  • xhtml_1.0, xml, xml_strict, xsl
  • yaml, yui_javascript