For those of you out there with your own blog who want to style your snippets of code to look like your favourite text editor, here is a simplified version of the method I’ve used here on Handy Rails Tips.
To do this we need to employ CodeRay, a really cool gem for syntax highlighting by Kornelius Kalnbach. To try it out, add the following to your environment.rb file:
config.gem "coderay", version: ">=0.8.312", lib: false, source: 'http://gems.github.com'
and then
rake gems:install
For the purposes of this demo, lets assume you have a model called Post with an attribute body.
When writing a new post, any time you want to add some snippets of code simply wrap the snippets in xml tags specific to the language.
i.e. <ruby>some ruby here</ruby>
, <rhtml>some rhtml here</rhtml>
and <css>some css here</css>
.
These xml tags will be removed later but are necessary for the helper method which we’ll call in the view:
<%= post_body(@post.body) %>
Now we need to create this helper method. The helper takes the post’s body as a parameter and should return the body with the code snippets replaced with CodeRay output.
In posts_helper.rb add the following:
module PostsHelper
require 'coderay'
CODERAY_LANGUAGES = %w( ruby rhtml css )
CODE_RAY_SETTINGS = {
:tab_width => 2, # convert tabs to n spaces (default is 8)
:css => :class, # style with css classes or inline style attributes (default is class)
:wrap => :div, # wraps the code in :span, :div, :page or nil (default is nil)
:level => :xhtml, # reserved for future use
:line_numbers => nil, # display line numbers as table, list, inline or nil (default is nil)
:line_number_start => 1, # sets which number to start line numbers on (default 1)
:bold_every => 10, # make the line numbers bold every nth number (default 10)
:hint => false # shows some info about the tag using title attributes [:info, :long_info, :debug or false] (default false)
}
def post_body(body)
CODERAY_LANGUAGES.each {|language| code_ray_this(body, language)}
body
end
protected
def code_ray_this(body, language)
body.gsub!(reg_expression_for(language)) { CodeRay.scan($1, language).div(CODE_RAY_SETTINGS) }
end
def reg_expression_for(language)
Regexp.new("<#{language}>([\\w\\s[:punct:]]*)</#{language}>", true)
end
end
The method post_body is the method that we’re calling from the view and CODERAY_LANGUAGES
is an array of the languages you want to support. Other options you could add to this array are: C, Delphi, diff, HTML, Nitro-XHTML, Java, JavaScript, JSON and YAML.
reg_expression_for
returns a regular expression to scan for code inside the ruby, rhtml and css xml tags. This regular expression has a capture in the middle marked by braces to pick out the actual code content from the xml.
The method code_ray_this
is the method that adds the coderay html tags. This method scans for any code using our regular expression and replaces the code with CodeRay content.
I’ve set the CODERAY_SETTINGS
as a constant here simply to show the options that are available. You can read a little more about these here.
Now all you have to do is add your own stylesheet to match your favourite text-editor. I use TextMate with Ryan Bates’ Railscast theme.
Below is a list of the css classes CodeRay will assign and what they represent.
span.af{/* attribute name fat */}
span.an{/* attribute name */}
span.av{/* attribute value */}
span.aw{/* attribute value fat */}
span.bi{/* bin */}
span.c{/* comment */}
span.ch{/* char */}
span.cl{/* class*/}
span.cr{/* colour */}
span.co{/* constant */}
span.cv{/* class variable */}
span.df{/* definition */}
span.di{/* directive */}
span.dl{/* delimeter */}
span.do{/* doc */}
span.ds{/* doc string */}
span.e{/* escape */}
span.er{/* error */}
span.ex{/* exception */}
span.fl{/* float */}
span.fu{/* function */}
span.gv{/* global variable */}
span.hx{/* hex */}
span.i{/* integer */}
span.ic{/* include */}
span.id{/* ident */}
span.il{/* inline */}
span.in{/* interpreted */}
span.iv{/* instance variable */}
span.k{/* content */}
span.ke{/* css attribute */}
span.kw{/* css selector */}
span.la{/* label */}
span.lv{/* local variable */}
span.mod{/* modifier */}
span.oc{/* oct */}
span.on{/* operator name */}
span.op{/* operator */}
span.pc{/* pre constant */}
span.pt{/* pre type */}
span.pd{/* predefined */}
span.pp{/* preprocessor */}
span.rx{/* reg exp */}
span.r{/* reserved */}
span.s{/* string */}
span.sh{/* shell */}
span.sp{/* space */}
span.sy{/* symbol */}
span.ta{/* tag */}
span.tf{/* tag fat */}
span.ts{/* tag special */}
span.ty{/* type */}
span.v{/* variable */}
span.vl{/* css value */}
span.xt{/* xml text */}
You can read the full documentation for CodeRay here.