How to implement Rouge syntax highlighting in Rails?

There are tons of tutorials floating around, but they seem to be incomplete or not completely current or not fully working for me.

This is what I did.

Gemfile:

gem 'rouge' gem 'redcarpet' 

Then I created config/initializer/rouge.rb :

 require 'rouge/plugins/redcarpet' 

Then I created a file called app/assets/stylesheets/rouge.css.erb

 <%= Rouge::Themes::Github.render(:scope => '.highlight') %> 

Then in my app/helpers/application_helper.rb I added the following:

 module ApplicationHelper class HTML < Redcarpet::Render::HTML include Rouge::Plugins::Redcarpet def block_code(code, language) Rouge.highlight(code, language || 'text', 'html') end end def markdown(text) render_options = { filter_html: true, hard_wrap: true, link_attributes: { rel: 'nofollow' } } renderer = HTML.new(render_options) extensions = { autolink: true, fenced_code_blocks: true, lax_spacing: true, no_intra_emphasis: true, strikethrough: true, superscript: true } Redcarpet::Markdown.new(renderer, extensions).render(text).html_safe end end 

Then in my show.html.erb I did the following:

 <%= markdown(@question.body) %> 

But it literally doesn't work. It outputs my ruby code snippet as follows:

unformatted-ruby-snippet

How to get this code snippet for formatting like github? Or even just the first step that you need to format in general, then how do I configure the formatting?

I don’t see the stylesheet contained in the page source, so I don’t know which styles to customize for what I want.

Change 1

Or even when I do this:

  <div class="highlight"> <%= @question.test_suite %> </div> 

It looks like this:

another-ruby-snippet

Edit 2

I tried to suggest BoraMa, and I got an output that looks like this:

enter image description here

Edit 3

I made a modification of BoraMa's answer as follows.

In my block_code method block_code I call the selection as follows:

 Rouge.highlight(code, 'ruby', 'html') 

Then, in my opinion, I do this:

 <%= raw rouge_markdown(<<-'EOF' def rouge_me puts "this is a #{'test'} for rouge" end EOF ) %> 

Then it produces:

enter image description here

Note. I mean the code snippet at the bottom of the screenshot.

However, the text at the top is generated using this:

  <pre class="highlight ruby"> <%= rouge_markdown(@question.body) %> </pre> 

And it is displayed as shown in the screenshot.

Change 4

After removing the <div class="highlight"> , I see the following:

enter image description here

Aka .... nothing is done at all.

As soon as I add raw to my view ... aka <%= raw rouge_markdown(@question.body) %>

The view displays the following:

enter image description here

Change 5

Here is the content for the various @question objects:

 [1] pry(#<#<Class:0x007fc041b97ce8>>)> @question.body => "5.times do\r\n puts \"Herro Rerl!\"\r\nend" [1] pry(#<#<Class:0x007fc041b97ce8>>)> @question.body => "puts \"Hello World version 9\"\r\nputs \"This comes after version 8.\"\r\nputs \"This comes after version 7.\"\r\nputs \"This comes after version 6.\"\r\nputs \"This comes after version 5.\"\r\nputs \"This comes after version 4.\"\r\nputs \"This comes after version 3.\"\r\nputs \"This comes after version 2.\"\r\nputs \"This definitely comes after version 1.\"" [1] pry(#<#<Class:0x007fc041b97ce8>>)> @question.body => "def convert_relation(invited_gender, relation)\r\n case invited_gender\r\n \twhen \"male\"\r\n \tcase relation\r\n when \"daughter\", \"son\" then \"dad\"\r\n when \"mom\", \"dad\" then \"son\"\r\n when \"grandfather\", \"grandmother\" then \"grandson\"\r\n when \"sister\", \"brother\" then \"brother\"\r\n when \"wife\" then \"husband\"\r\n when \"husband\" then \"husband\"\r\n end\r\n when \"female\"\r\n \tcase relation\r\n when \"daughter\", \"son\" then \"mom\"\r\n when \"mom\", \"dad\" then \"daughter\"\r\n when \"grandfather\", \"grandmother\" then \"granddaughter\"\r\n when \"sister\", \"brother\" then \"sister\"\r\n when \"wife\" then \"wife\"\r\n when \"husband\" then \"wife\"\r\n end\r\n end\r\nend\r\n\r\nputs convert_relation(\"male\", \"wife\")" 
+7
ruby-on-rails ruby-on-rails-5 syntax-highlighting pygments rouge
source share
1 answer

The initial question (in an attempt to resolve) indicated that the markdown would be used in the selected issues, but it turned out that this was not so. Thus, this answer is divided into two separate sections: one for highlighting clean code without markdowns, and the other for text with code with code.

A) You want to highlight clean code (Markdown is not used)

In this case, and according to README , all you need is to highlight the code using Rouge, lexer and formatting . Since the selected text will be displayed on the web page, you will need HTML formatting . For lexer, you need to know the language in which the code is in advance (or you can try to guess it from the source code itself, but it does not seem very reliable for small code fragments).

You can create a simple helper allocation method:

 module RougeHelper def rouge(text, language) formatter = Rouge::Formatters::HTML.new(css_class: 'highlight') lexer = Rouge::Lexer.find(language) formatter.format(lexer.lex(text)) end end 

Then in the template, just call this helper with the selected text and language:

 <%= raw rouge("def rouge_me\n puts 'hey!'\nend", "ruby") %> 

What will be displayed:

7TZMe.png

To get a list of all the languages ​​supported by Rouge and their names that should be passed to the rouge helper, you can use the following code. The code gets all the defined lexers from Rouge and shows their tags (i.e. Rouge Names recognize them):

 Rouge::Lexer.all.map(&:tag).sort # => ["actionscript", "apache", "apiblueprint", "applescript", ..., "xml", "yaml"] 

You can (and probably should) use this list by showing users the languages ​​to choose from in the selection window. Please note that each lexer also has certain title and desc methods that will give you a human-friendly name and a brief description of each of them. You might want to use this information for the user as well.

Note : you should get rid of the initializer, the custom HTML class, and the div wrapped in a call to the rouge helper (you have all of them in your initial attempt). The only thing you need, besides the code above, is the CSS rules that you have already correctly included in the web page.

B) The selected text is Markdown text with code blocks

A few changes from your attempt to make it work:

  • An initializer is not needed, you can delete it, I think (but if you don't want require all files later in the helper, I think you can leave it).

  • Remove the block_code method from the block_code class, the same has already been done by including the markdown plugin.

  • Remove the wrapper <div class="highlight"> div from your template and just use the helper in it. Rouge adds its own wrapper with the "highlight" class, and the other div seems to confuse it.

Try the following helper code. BTW, I moved the code from ApplicationHelper to a separate RougeHelper (but this is not a mandatory change):

 module RougeHelper require 'redcarpet' require 'rouge' require 'rouge/plugins/redcarpet' class HTML < Redcarpet::Render::HTML include Rouge::Plugins::Redcarpet end def rouge_markdown(text) render_options = { filter_html: true, hard_wrap: true, link_attributes: { rel: 'nofollow' } } renderer = HTML.new(render_options) extensions = { autolink: true, fenced_code_blocks: true, lax_spacing: true, no_intra_emphasis: true, strikethrough: true, superscript: true } markdown = Redcarpet::Markdown.new(renderer, extensions) markdown.render(text) end end 

Then in the template, I tried to highlight the ruby ​​test code:

 <%= raw rouge_markdown(<<-'EOF' ```ruby def rouge_me puts "this is a #{'test'} for rouge" end ``` EOF ) %> 

Note that I needed to specify the language manually, which forced me to use 3 return paths to demarcate the code, rather than backtrack in space. I don’t know why the self-determination of the code language does not work here, perhaps this is too short code.

In the end, it gave me color:

2aYOk.png

+7
source share

All Articles