14

There are a bunch of tutorials floating around, but they seem to be incomplete or not fully current or don't fully work for me.

This is what I have done.

Gemfile:

gem 'rouge'
gem 'redcarpet'

Then I created a 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 this:

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 this:

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

But that literally does not work. It outputs my ruby code snippet like this:

unformatted-ruby-snippet

How do I get this snippet of code to be formatted like Github? Or even just the first step being to be formatted any at all, then how do I tweak the formatting?

I don't see a stylesheet included in the source of the page, so I don't know which styles to tweak for what I want.

Edit 1

Or even when I do this:

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

It renders like this:

another-ruby-snippet

Edit 2

I attempted BoraMa's suggestion and I got output that looks like this:

enter image description here

Edit 3

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

In my block_code method, I call highlight as follows:

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

Then in my view I do this:

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

Then that produces this:

enter image description here

Note I am referring to the code snippet at the bottom of the screenshot.

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

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

And it is rendered as is shown in the screenshot.

Edit 4

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

enter image description here

Aka....nothing is being rendered at all.

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

The view renders this:

enter image description here

Edit 5

Here is the content for 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\")"
4

1 回答 1

14

原始问题表明(在尝试的解决方案中)在突出显示的问题中将使用降价,但事实并非如此。所以这个答案分为两个不同的部分,一个用于突出显示没有降价的纯代码,另一个用于带有代码的降价文本。

A)你想突出显示纯代码(不涉及 Markdown)

在这种情况下,根据README,使用 Rouge 突出显示代码所需的只是一个 lexer一个 formatter。由于突出显示的文本将显示在网页上,因此您需要HTML 格式化程序。对于词法分析器,您需要事先了解代码所使用的语言(或者您可以尝试从源代码本身猜测它,但对于小代码片段似乎不太可靠)。

您可以为突出显示创建一个简单的辅助方法:

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

然后在模板中,只需使用要突出显示的文本和语言调用此助手:

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

这将呈现:

要获取 Rouge 支持的所有语言的列表以及应传递给rouge帮助程序的相应名称,您可以使用以下代码。代码从 Rouge 获取所有定义的词法分析器并显示它们的标签(即 Rouge 识别它们的名称):

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

在选择框中向用户显示可供选择的语言时,您可以(并且可能应该)使用此列表。请注意,每个词法分析器还定义了titledesc方法,这些方法将为您提供人类可读的名称和每个方法的简短描述。您可能也希望使用此信息向用户显示。

注意:您应该摆脱初始化程序、自定义 HTML 类和div包裹在 rouge 助手调用周围的东西(所有这些您在最初的尝试中都有)。除了上面的代码,您唯一需要的是 CSS 规则,您已经正确地包含在网页中。

B) 突出显示的文本是带有代码块的 Markdown 文本

您尝试使其工作的一些更改:

  1. 不需要初始化程序,我认为您可以将其删除(但如果您不想require稍后在帮助程序中删除所有文件,我想您可以保留它)。

  2. 从帮助类中删除该block_code方法,通过包含降价插件已经完成了相同的操作。

  3. 从模板中删除<div class="highlight">包装器 div 并使用其中的帮助器。Rouge 使用“highlight”类添加了自己的包装器,而另一个 div 似乎混淆了它。

试试下面的帮助代码。顺便说一句,我将代码从ApplicationHelper单独的RougeHelper(但这不是必需的更改):

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

然后,在模板中,我尝试突出显示测试 ruby​​ 代码:

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

请注意,我需要手动指定语言,这使我使用 3 个反引号来分隔代码而不是空格缩进。我不知道为什么代码语言自动检测在这里不起作用,也许它的代码太短了。

最后,这很好地为我呈现了颜色:

于 2016-06-09T09:09:54.110 回答