I'm trying to add some syntax highlighting to my blog that currently uses RDiscount. I am converting the Markdown to HTML with RDiscount then parsing the HTML code blocks with CodeRay to add syntax highlighting. This is what I have so far:
class Post < ActiveRecord::Base
before_save :render_body
def render_body
self.rendered_body = coderay(markdown(self.body))
end
def markdown(text)
RDiscount.new(text).to_html
end
def coderay(text)
text.gsub(/\<code( lang="(.+?)")?\>(.+?)\<\/code\>/m) do
CodeRay.scan($3, $2).div(:css => :class)
end
end
end
And in my view:
<%= raw @post.rendered_body %>
Using this markdown:
<code lang="ruby">
def function(param1, param2)
puts param1
param2.each do |a|
a.hello :world
end
end
</code>
The result is that the code blocks are being wrapped twice.
<pre>
<div class="CodeRay">
<div class="code">
<pre>
def function(param1, param2)
puts param1
param2.each do |a|
a.hello :world
end
end
</pre>
</div>
</div>
</pre>
What should I do instead?
In your render_body
method call the coderay()
method before calling the markdown()
method. Using the markdown
method first was generating some extra html and this confused CodeRay
causing bad output.
My tests assumed you had the raw data that looked something like this in the markdown source
<code lang="ruby">
def function(param1, param2)
puts param1
param2.each do |a|
a.hello :world
end
end
</code>
Here's the complete class I used to test it. Note I didn't use :css => :class
option because I didn't have the css to test it.
class Post < ActiveRecord::Base
before_save :render_body
def render_body
self.rendered_body = markdown(coderay(self.body))
end
def markdown(text)
RDiscount.new(text).to_html
end
def coderay(text)
text.gsub(/\<code( lang="(.+?)")?\>(.+?)\<\/code\>/m) do
CodeRay.scan($3, $2).div
end
end
end
Your final output assuming the :css => :class
option should now look something like this
<div class="CodeRay">
<div class="code"><pre>
<span class="r">def</span> <span class="fu">function</span>(param1, param2)
puts param1
param2.each <span class="r">do</span> |a|
a.hello <span class="sy">:world</span>
<span class="r">end</span>
<span class="r">end</span>
</pre></div>
</div>