How to use CodeRay to format code

3 minute read

When I decided I wanted to start my CodeBlog, I knew I would be showing a lot of code on my page and I wanted a way to make it nice and pretty looking. I looked at the Syntax gem, even tried it out, but I was unimpressed. I decided to go with CodeRay instead because of its easy setup, multiple language support and it is still being enhanced with more language support.
First you want to install the gem

        
sudo gem install coderay
Next, you want to add the css to your display.css file. There might be an easier way to get this but I found it by going into the gem directory and running a simple command:
1
2
cd /opt/local/lib/ruby/gems/1.8/gems/coderay-0.7.4.215/lib/
coderay_stylesheet
The gem directory might be different for you. Now you just have to take the text you want and format in the controller. I did this by sending text from a form into the controller with certain tags to mark the sections I want formatted. In the form I would type something like the following:
1
2
3
4
This text won't be formatted
[ code=ruby ] @this.text = (will_be) ? formatted_as : nil unless code=ruby [ /code ]
[ code=c ] printf("This text will be formatted as %s", c); [ /code ]
[ code=html ] <div>This text will be <b>formatted</b> as <i>html</i> [ /code ]
In the example above the [ code=xxx ] tags and the [ /code ] tags don't have spaces. I had to add those so my own controller wouldn't pick up the code and try to format it. Here is what it looks like formatted:
This text won't be formatted

        
@this.text = (will_be) ? formatted_as : nil unless code=ruby

        
printf("This text will be formatted as %s", c);

        
<div>This text will be <b>formatted</b> as <i>html</i>
Next, I have my controller method "preview" call a special function I have in application.rb and pass the text from the form.
1
2
3
def preview
  @post = format_post_content(Post.new(params[:post]))
end
Inside format_post_content I do a lot to manipulate the content
1
2
3
4
5
6
7
8
9
10
11
def format_post_content(post)
  html = post.content.blank? ? "" : post.content.clone
  while match = html.match(/\[code=(.+?)\](.+?)\[\/code\]/m)
    m2 = Regexp.escape(match[2])
    html.gsub!(/\[code=#{match[1].strip}\]#{m2}\[\/code\]/m,
               CodeRay.scan(match[2].chomp,
                            match[1].to_sym).html.numerize)
  end
  post.content_html = html
  return post
end
It looks complicated but it is actually pretty simple, let me explain:
  • Line 2: Get a clone of the content because I am going to store both the original content and the formatted
  • Line 3: Search for anything with a code tag, get the format and content between the tags
  • Line 4: Escape the code between the code tags because I might have [ ] ( ) | ? or any other symbol that might mess up the regexp
  • Line 5: Substitute the text (including the code tags) that I found in line 3 with...
  • Line 6: ... the CodeRay formated version, formatted in...
  • Line 7: ... the format specified by [ code=XXX ]. Then I get the html and number it.
Lines 4-7 are wrapped in a while loop that will format all instances of code tags. It took me a while to figure out that I also needed the "m" after each regular expression to keep track of which one we are working with, as well as the (.*?) which makes the searched text as short as possible (meaning it won't cross-over to the next code tag). It looks a little confusing on lines 5,6, and 7, so here is an example call of the ease of CodeRay on one line:

        
CodeRay.scan(@post.content, :ruby).html.numerize
That's it! After my special parsing, it only took 1 line to translate the code into a bunch of spans for the css! The way I implemented it in my function, I can use multiple code fields with multiple languages (like this post) in a simple and easy way. It is also a cinch to edit because I store both the content and the content_html, and editing the stuff in [ code=xxx ] tags is much easier than editing div's and span's. If you don't like the way the code looks out of the box, you can edit the css to be any color/style you wish making CodeRay totally customizable.
Now I just have to tweak the colors to more to my liking...

Updated:

Comments