2012年06月05日 | Chaos | rails klog markdown redcarpet
做博客程序肯定會需要富文本這么個玩意兒,否則博客文章就只能純文本了
做富文本最出名的肯定是 CKEditor 之類的東西,不過那種東西調(diào)整格式太麻煩,而且總會有些亂七八糟的問題,我這種有潔癖的人極不喜歡
因此我果斷選擇了 Github 所采用的方案:Markdown 格式
Markdown 是一種輕量級的標(biāo)記語言,它通過一些特殊標(biāo)記來表達(dá)格式,并在最終渲染時通過 Markdown解析器 將 Markdown 文本轉(zhuǎn)換為 HTML 格式
比如以下這段 Markdown 文本
# Header1## Header 2* List1* List2
經(jīng)過轉(zhuǎn)換后就變成以下的 HTML
<h1>Header1</h1><h2>Header2</h2><ul> <li>List1</li> <li>List2</li></ul>
關(guān)于 Markdown 語法請參考這里 Markdown 語法說明,基本語法非常簡單
我在開發(fā) Klog 時選擇了 Redcarpet 這個使用者較多的 Markdown 解析器
Redcarpet 使用非常簡單,只需要以下兩行即可完成 Markdown 格式到 HTML 格式的轉(zhuǎn)換
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML)html = markdown.render("This is *bongos*, indeed.")
首先新建一個 Markdown 的實例,然后調(diào)用實例的 render() 方法即可
在新建實例時,可以通過參數(shù)定制解析器的一些行為,比如
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :autolink => true, :space_after_headers => true)
參數(shù)中比較重要的有以下幾個
:no_intra_emphasis 不解析單詞中的下劃線,比如 foo_bar_baz 不會被解析成帶 的文本
:fenced_code_blocks 解析代碼塊,使用3個或3個以上 ~ 或者 ` 包圍起來的文本會被解析為代碼塊
你可以在開頭指定代碼的語言類型,具體格式形如這樣
autolink 自動檢查文本中 http https ftp 等協(xié)議的鏈接文本,將之解析為鏈接
沒有以 http:// 開頭,而是直接以 www. 開頭的同樣會被檢查到
:strikethrough 支持兩個 ~ 包圍的文本,解析為刪除線
:space_after_headers #后面必須加空格,否則不會被解析為標(biāo)題
我的博客程序采用的參數(shù)組合是 :autolink => true, :fenced_code_blocks => true, :no_intra_emphasis => true
注意創(chuàng)建實例時的第一個參數(shù) Redcarpet::Render::HTML ,這個類會根據(jù)默認(rèn)參數(shù)自動被實例化,當(dāng)然你也可以通過參數(shù)來定制這個類的行為,比如
rndr = Redcarpet::Render::HTML.new(:no_links => true, :hard_wrap => true)markdown = Redcarpet::Markdown.new(rndr, :autolink => true, :space_after_headers => true)
關(guān)于 Render 類的參數(shù),比較重要的有以下幾個
除了通過參數(shù)定制 Render 之外,如果希望進(jìn)行一些更高級功能的定制,可以通過自己編寫 Render 類來實現(xiàn),以下是一個簡單的示例
class Render < Redcarpet::Render::HTML def header(text, header_level) return “<h3>#{text}</h3>” endendmarkdown = Redcarpet::Markdown.new(Render)
使用這個 markdown 對象去轉(zhuǎn)換 ,會將 header 統(tǒng)一轉(zhuǎn)換為 標(biāo)簽,而默認(rèn)會根據(jù)層級生成 等等
這里我們是通過覆蓋 header() 方法實現(xiàn)了這一功能,其他可以通過覆蓋來實現(xiàn)渲染功能定制的方法還有很多,比如
paragraph(text)
...等等,詳情可以參考這里https://github.com/tanoku/redcarpet#and-you-can-even-cook-your-own
考慮到效率問題,我給博客文章這張表增加了一個 html_content 的字段,然后通過 callback ,在每次保存前將 Markdown 文本轉(zhuǎn)換為 HTML 寫入這個字段
class Blog < ActiveRecord::Base before_save :fill_html_content #將markup的content轉(zhuǎn)換為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
聯(lián)系客服