Implementing Coderay with Redcloth and Haml
I wanted to implement code highlighting for our Arctic Kiwi website just to make the posts a little easier on the eye. \r\nI first tried out the redcloth-with-coderay gem which you can find on \github\. I had mixed results with this gem and I didn’t need all the functionality it provided. I would recommend taking a look though if the implementation below isn’t to your taste. I ended up taking the approach Ryan Bates uses for his railscasts website.\r\n\r\nTo start make sure you have the required config.gem lines in your environment.rb.\r\n@@@ ruby\r\nRails::Initializer.run do |config|\r\n config.gem \“RedCloth\”\r\n config.gem \“haml\”\r\n config.gem \“coderay\”\r\n …\r\nend\r\n@@@\r\nNow create a file in you lib directory called textilizer.rb and insert the following code.\r\n@@@ ruby\r\nclass Textilizer\r\n def initialize(text)\r\n hello worldtext = text\r\n end\r\n \r\n def to_html\r\n RedCloth.new(formatted_text).to_html\r\n end\r\n \r\n def formatted_text\r\n @text.gsub(/^
@ ?(\\w*)\\r?\\n(.+?)\\r?\\n
@\\r?$/m) do |match|\r\n lang = $1.empty? ? nil : $1\r\n \"\\n<notextile>\" + CodeRay.scan($2, lang).div(:css => :class) + \"</notextile>\"\r\n end\r\n end\r\nend\r\n
@\r\nThe code is fairly straight forward, it stores the text provided in an instance variable when a new textilizer instance is created. When to_html is called on the instance it calls Redcloth's to_html method after parsing the text through the regular expression in the formatted text method.\r\nThe formatted text method finds blocks of code wrapped in @
@ and passes it to coderay for syntax highlighting. It then wraps each of these blocks in no-textile tags so Redcloth will ignore the contents.\r\n\r\nIn your application_helper.rb file add the following code which will allow you to use a textilize method call in your views.\r\n@@@ ruby\r\nmodule ApplicationHelper\r\n def textilize(text)\r\n Textilizer.new(text).to_html unless text.blank?\r\n end\r\nend\r\n@@@\r\nNow in your views you can call the textilize method as follows.\r\n@@@ ruby\r\n~ textilize object.content #haml\r\n
@\r\n
@ rhtml\r\n<%= textilize @object.content %> #erb\r\n
@\r\nNotice when using haml that the ~ sign is used. This is important as it tells haml to preserve the whitespace and ommitting the ~ will cause the output to be formatted incorrectly. If you don't like the ~ (tilde) syntax you can use (as described \"here\":http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#tilde): \r\n
@ ruby\r\n= find_and_preserve(textilize @object.content)\r\n
@\r\nFinally to incorporate the code highlighting in your text just wrap the code block as shown below.\r\n
@\r\n @
@ @
\r\n@@@\r\nThe @
in a code block\” do\r\n textilize(\“@
\\nfoo\\n@@@\”).strip.should == CodeRay.scan(‘foo’, nil).div(:css => :class).strip\r\n end\r\n \r\n it \“should not process textile in code block\” do\r\n textilize(\“@
\\nfoo bar\\n@@@\”).strip.should == CodeRay.scan(‘foo bar’, nil).div(:css => :class).strip\r\n end\r\n \r\n it \“allow language for code block\” do\r\n textilize(\“@
ruby\\n@foo\\n@@@\”).strip.should == CodeRay.scan(‘@foo’, ‘ruby’).div(:css => :class).strip\r\n end\r\n \r\n it \“allow code block in the middle\” do\r\n textilize(\“foo\\n@@@\\ntest\\n@@@\\nbar\”).should include(CodeRay.scan(‘test’, ‘ruby’).div(:css => :class).strip)\r\n end\r\n \r\n it \“should handle \\\\r in code block\” do\r\n textilize(\“\\r\\n@@@\\r\\nfoo\\r\\n@@@\\r\\n\”).strip.should == CodeRay.scan(‘foo’, nil).div(:css => :class).strip\r\n end\r\n \r\n it \“should allow multiple code blocks\” do\r\n textilize(\“@
\\nfoo\\n@@@\\n\\n@@@\\nbar\\n@@@\”).strip.should == CodeRay.scan(‘foo’, nil).div(:css => :class).strip + \“\\n\” +CodeRay.scan(‘bar’, nil).div(:css => :class).strip\r\n end\r\nend\r\n@@@