2012年06月05日 | Chaos | rails klog markdown redcarpet
做博客程序肯定会需要富文本这么个玩意儿,否则博客文章就只能纯文本了
做富文本最出名的肯定是 CKEditor 之类的东西,不过那种东西调整格式太麻烦,而且总会有些乱七八糟的问题,我这种有洁癖的人极不喜欢
因此我果断选择了 Github 所采用的方案:Markdown 格式
Markdown 是一种轻量级的标记语言,它通过一些特殊标记来表达格式,并在最终渲染时通过 Markdown解析器 将 Markdown 文本转换为 HTML 格式
比如以下这段 Markdown 文本
# Header1## Header 2* List1* List2
经过转换后就变成以下的 HTML
<h1>Header1</h1><h2>Header2</h2><ul> <li>List1</li> <li>List2</li></ul>
关于 Markdown 语法请参考这里 Markdown 语法说明,基本语法非常简单
我在开发 Klog 时选择了 Redcarpet 这个使用者较多的 Markdown 解析器
Redcarpet 使用非常简单,只需要以下两行即可完成 Markdown 格式到 HTML 格式的转换
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML)html = markdown.render("This is *bongos*, indeed.")
首先新建一个 Markdown 的实例,然后调用实例的 render() 方法即可
在新建实例时,可以通过参数定制解析器的一些行为,比如
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :autolink => true, :space_after_headers => true)
参数中比较重要的有以下几个
:no_intra_emphasis 不解析单词中的下划线,比如 foo_bar_baz 不会被解析成带 的文本
:fenced_code_blocks 解析代码块,使用3个或3个以上 ~ 或者 ` 包围起来的文本会被解析为代码块
你可以在开头指定代码的语言类型,具体格式形如这样
autolink 自动检查文本中 http https ftp 等协议的链接文本,将之解析为链接
没有以 http:// 开头,而是直接以 www. 开头的同样会被检查到
:strikethrough 支持两个 ~ 包围的文本,解析为删除线
:space_after_headers #后面必须加空格,否则不会被解析为标题
我的博客程序采用的参数组合是 :autolink => true, :fenced_code_blocks => true, :no_intra_emphasis => true
注意创建实例时的第一个参数 Redcarpet::Render::HTML ,这个类会根据默认参数自动被实例化,当然你也可以通过参数来定制这个类的行为,比如
rndr = Redcarpet::Render::HTML.new(:no_links => true, :hard_wrap => true)markdown = Redcarpet::Markdown.new(rndr, :autolink => true, :space_after_headers => true)
关于 Render 类的参数,比较重要的有以下几个
除了通过参数定制 Render 之外,如果希望进行一些更高级功能的定制,可以通过自己编写 Render 类来实现,以下是一个简单的示例
class Render < Redcarpet::Render::HTML def header(text, header_level) return “<h3>#{text}</h3>” endendmarkdown = Redcarpet::Markdown.new(Render)
使用这个 markdown 对象去转换 ,会将 header 统一转换为 标签,而默认会根据层级生成 等等
这里我们是通过覆盖 header() 方法实现了这一功能,其他可以通过覆盖来实现渲染功能定制的方法还有很多,比如
paragraph(text)
...等等,详情可以参考这里https://github.com/tanoku/redcarpet#and-you-can-even-cook-your-own
考虑到效率问题,我给博客文章这张表增加了一个 html_content 的字段,然后通过 callback ,在每次保存前将 Markdown 文本转换为 HTML 写入这个字段
class Blog < ActiveRecord::Base before_save :fill_html_content #将markup的content转换为html并写入字段 def fill_html_content self.html_content = Klog::Markdown.render(self.content) endend
另外为了避免每次都要新建 Markdown 对象,我使用了单例模式,代码参考如下
module Klog class Markdown def self.render(text) return self.instance.render(text) end def self.instance @markdown ||= Redcarpet::Markdown.new(Klog::Render.new, :autolink => true, :fenced_code_blocks => true,no_intra_emphasis => true) end end class Render < Redcarpet::Render::HTML def initialize(extensions={}) super(extensions.merge(:xhtml => true, :no_styles => true, :filter_html => true, :hard_wrap => true)) end endend
联系客服