如何扩展Redcarpet以支持自动链接用户提到?

7
在我的 rails3 应用程序中,我希望使用 redcarpet 来处理用户的文章和评论。因此,我想扩展 redcarpet,使其支持将 @username 转换为指向我的网站上用户的链接。我知道 redcarpet 是用 C 编写的,但是否有一种简便的方式可以在 Ruby 中扩展它?编写 C 代码会有多难?还是应该在 redcarpet 之外实现这个功能?
另外,我也对 redcarpet 的其他扩展很感兴趣,这些扩展可用于缩写链接到我应用程序中的其他模型。我还不确定语法,但我猜想它可能类似于 GitHub 处理链接问题的方式。
2个回答

23

我发现在我为我的Rails 3应用扩展redcarpet解析器时,这非常容易。这一点也不可怕。

首先,从Redcarpet的HTML渲染器中派生一个类,并覆盖预处理方法,如文档中推荐的那样操作。在Rails 3.2和Rails 4中,此文件可以放在任何位置,您不需要对其进行要求。我使用“服务”文件夹来保存这样的代码。

# app/services/my_flavored_markdown.rb
class MyFlavoredMarkdown < Redcarpet::Render::HTML
  def preprocess(text)
    text
  end
end

接下来的步骤是添加您想要进行文本替换的方法。在此,我使用正则表达式将类似于“@提到”的文本包装在具有CSS类“mention”的HTML span标记中。

# app/services/my_flavored_markdown.rb
class MyFlavoredMarkdown < Redcarpet::Render::HTML

  def preprocess(text)
    wrap_mentions(text)
  end

  def wrap_mentions(text)
    text.gsub! /(^|\s)(@\w+)/ do
      "#{$1}<span class='mention'>#{$2}</span>"
    end
    text
  end

end

你可以轻松查找用户的个人资料页面,并用锚标签包含@提到的内容。在我的情况下,我还创建了表情符号和主题标签的方法,它们以相同的方式工作,并将这些方法链接在一起。

最后一步是添加一个帮助程序,接受一些文本,创建一个基于Redcarpet的类实例,将文本传递给它进行处理,并返回HTML结果。

# app/helpers/application_helper.rb
def flavored_markdown_to_html(text)
  renderer = MyFlavoredMarkdown.new()
  # These options might be helpful but are not required
  options = {
    safe_links_only: true,
    no_intra_emphasis: true,
    autolink: true
  }
  Redcarpet::Markdown.new(renderer, options).render(text)
}

在您的视图中,您可以像这样调用它:

<%= flavored_markdown_to_html("这是值得提及的内容 @mentioning") %>

输出结果将为:

这是值得<span class='mention'>@mentioning</span>的内容


此外,如果渲染结果不会被缓存,您可能不希望在每次渲染时进行数据库查找。另一种选择是使用我这里的示例,然后使用JavaScript拦截span.mention元素上的点击事件,查找提及的URL并重定向用户。 - IAmNaN
2
对于那些不想在链接的href中出现@符号的人:/(^|\s)@(\w+)/"#{$1}<span class='mention'>@#{$2}</span>" - Dennis Hackethal

1

我曾经尝试过扩展redcarpet,但发现非常困难。如果没有其他依赖于redcarpet的情况,我建议您尝试rpeg-markdown,它是一个(有点过时的)Ruby gem,提供了对优秀的peg-markdown的绑定。

peg-markdown是一个作为正式语法编写的Markdown解释器。这意味着很容易用自己的语法扩展它。我已经成功地为自己的项目扩展了peg-markdown(请参见我的分支),我发现它比调整redcarpet的自定义解析器代码要简单得多。

我还发现peg-markdown有更少的错误。

通过更新git子模块可能需要使Ruby绑定程序保持最新状态。(我计划提交拉取请求以更新rpeg-markdown到最新版本的peg-markdown。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接