Matt Coneybeare

MC

How to Use CodeRay to Format Code

| Comments

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…

Comments

My name is Matt Coneybeare, I design and develop for iOS (iPhone, iPad and iPod Touch), Mac OS X and the Web out of New York. In 2008 I started a software company called Urban Apps that has made some pretty popular apps such as Ambiance and Hourly News. My current Stack Overflow reputation is about 27k.

I was a Rockstar a decade ago, but then went back to school and collected a Bachelor's Degree in Computer Science from U.C. Berkeley. Now I am settled down with my beautiful wife Di and our two doggies Hamachi and Foxy. While coding, I walk several miles/day on my Treadmill Desk. When not at my desk, I love exploring New York City as a Yelp Elite, or training for marathons.

Contact information

Name
Matt Coneybeare
Email
Website
Twitter
Instagram
GitHub
LinkedIn
Google+