如何从Sinatra进行Github风格的Markdown渲染?

时间:2012-08-02 15:57:41

标签: ruby sinatra markdown tilt

TL; DR - 如何使用improved_markdown :some_file之类的东西进行自定义渲染,但仍然照常渲染布局?


通常情况下,要在Sinatra中渲染Markdown,您只需:

markdown :some_file

但我想添加“屏蔽”语法高亮显示功能,就像你可以在Github README文件中那样。

```ruby
class Foo
  # etc
end
```

我已经部分工作了。

首先,我安装了Redcarpet并添加了一个使用Pygments.rb进行语法突出显示的自定义呈现类:

# create a custom renderer that allows highlighting of code blocks
class HTMLwithPygments < Redcarpet::Render::HTML
  def block_code(code, language)
    Pygments.highlight(code, lexer: language)
  end
end

然后我在路线中使用它,像这样:

# Try to load any Markdown file specified in the URL
get '/*' do
  viewname = params[:splat].first

  if File.exist?("views/#{viewname}.md")

    # Uses my custom rendering class
    # The :fenced_code_blocks option means it will take, for example,
    # the word 'ruby' from ```ruby and pass that as the language
    # argument to my block_code method above  
    markdown_renderer = Redcarpet::Markdown.new(HTMLwithPygments, :fenced_code_blocks => true)

    file_contents = File.read("views/#{viewname}.md")
    markdown_renderer.render(file_contents)

  else
    "Nopers, I can't find it."
  end
end

几乎有效。 Markdown呈现为带有额外标记的HTML,用于突出显示。

唯一的问题是它不使用我的布局;毕竟,我只是读取一个文件并返回渲染的字符串。正常markdown :foo调用将涉及Tilt。

我是否必须创建自定义Tilt模板引擎才能使其正常工作,还是有更简单的方法?

3 个答案:

答案 0 :(得分:3)

您可以将任意选项传递给markdown方法(或任何其他渲染方法),它们将被传递给相关的Tilt模板。 Tilt的Redcarpet模板在创建渲染器时会查找任何提供的:renderer选项,允许您指定自定义渲染器。

您还可以通过将其作为第二个参数传递给markdown来指定应应用于所有set :markdown, :option => :value次调用的选项。

虽然不是那么简单,因为Tilt的当前(已发布)版本无法正确检测您是否安装了Redcarpet 2。你可以明确告诉它:

# first ensure we're using the right Redcarpet version
Tilt.register Tilt::RedcarpetTemplate::Redcarpet2, 'markdown', 'mkd', 'md'

# set the appropriate options for markdown
set :markdown, :renderer => HTMLwithPygments,
  :fenced_code_blocks => true, :layout_engine => :haml

现在,对markdown的任何调用都应使用自定义代码进行代码块,并使用layout.haml作为布局。

(免责声明:我无法让Pygments工作(这会导致Sinatra每次都崩溃),但其他所有内容都有效(我使用了一个简单的自定义block_code方法,只是添加了一条消息,所以我可以告诉它工作)。

答案 1 :(得分:0)

解决方法

我目前正在这样做:

if File.exist?("views/#{viewname}.md") 
  CustomMarkdown.render(File.read("views/#{viewname}.md"))

使用:

module CustomMarkdown
  def self.render(markdown_string)
    content = renderer.render(markdown_string)
    layout.render { content }
  end
  def self.renderer
    @markdown_renderer ||= Redcarpet::Markdown.new(HTMLwithPygments, :fenced_code_blocks => true)
  end
  def self.layout
    # Yes, this is hardcoded; in my simple app, I always use this layout.
    Tilt['haml'].new do
      File.read("views/layout.haml")
    end
  end
end

这很有效。我注意到没有关键字的围栏块,如下所示:

```
  code of unspecified type
```
# vs
```ruby
  explicitly ruby code
```

...导致我的Sinatra应用程序崩溃。我认为这意味着Python层中存在错误,因为我自己无法捕获任何引发的错误。

更新:崩溃发生在rackup config.ru,但不是在我使用Passenger时。

答案 2 :(得分:0)

您可以使用zzak的Glorify gem来完成这类工作。