先日ブログサイトをRailsで自作したときに本文をMarkdownで書けるようにしました。併せてソースコードのシンタックスハイライトも実現したのですが、とても簡単だったので書いておきます。
使ったもの
- Rails (5.0.1)
- Redcarpet gem (3.4.0)
- Rouge gem (1.11.1)
普通にRedcarpetを使う場合
そもそものRedcarpetの使い方はこのような感じです。
renderer = Redcarpet::Render::HTML.new(options)
# バッククオート3つで囲むフォーマットに対応
markdown = Redcarpet::Markdown.new(renderer, fenced_code_blocks: true)
# markdownのテキストをHTMLに変換
html = markdown.render(content)
Rendererを継承してメソッドをオーバーライドしていくことで好みの設定に拡張していくことができます。
ちなみにRedcarpetのみの状態でfenced_code_blocks
を使ってRailsのソースコードを書いてみます。
```ruby
# app/controllers/api/api_controller.rb
class Api::ApiController < ApplicationController
before_action :doorkeeper_authorize!
helper_method :current_user
def current_user
User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
end
end
```
HTMLのソースはこのようになります。
<code class="ruby">
# app/controllers/api/api_controller.rb
class Api::ApiController < ApplicationController
before_action :doorkeeper_authorize!
helper_method :current_user
def current_user
User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
end
end
</code>
Rouge gemを使えるようにする
Redcarpetと連携すればRougeを少しのステップで使い始めることができます。
はじめにGemfileにgem 'rouge'
を加えてbundle
します。RougeのRedcarpet対応のプラグインをincludeしたRendererを用意し、このファイルをRailsのロードパスに置きます。
require 'rouge/plugins/redcarpet'
class HTML < Redcarpet::Render::HTML
include Rouge::Plugins::Redcarpet
end
最初に紹介したRedcarpetの使い方のコードのうち、Redcarpet::Render::HTML
のところを先程用意したクラスに置き換えることで、ソースコード部分がRougeで処理されるようになります。
renderer = HTML.new(options)
markdown = Redcarpet::Markdown.new(renderer, fenced_code_blocks: true)
html = markdown.render(content)
するとこのようにソースコードの箇所に細かくCSSのクラスが付きます。
<pre class="highlight ruby"><code>
<span class="c1"># app/controllers/api/api_controller.rb </span>
<span class="k">class</span> <span class="nc">Api</span><span class="o">::</span><span class="no">ApiController</span> <span class="o"><</span> <span class="no">ApplicationController</span>
<span class="n">before_action</span> <span class="ss">:doorkeeper_authorize!</span>
<span class="n">helper_method</span> <span class="ss">:current_user</span>
<span class="k">def</span> <span class="nf">current_user</span>
<span class="no">User</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="n">doorkeeper_token</span><span class="p">.</span><span class="nf">resource_owner_id</span><span class="p">)</span> <span class="k">if</span> <span class="n">doorkeeper_token</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
ですが、このままではハイライトされません。スタイルがないからです。
スタイルをあてる
Rougeではシンタックスハイライト用のCSSを生成できるようになっています。
いくつかのテーマと、ソースコード部分のDOMのトップにつけるクラスを指定できます。僕はSublime TextなどのMonokaiテーマを好んで使っているので↓のような感じですね。
Rouge::Themes::MonokaiSublime.render(scope: '.highlight')
生成されたCSSをファイルに保存してからアプリケーションに読み込んでもいいのですが、どうせプリコンパイルされるので僕はアセットパイプラインに入れてしまっています。
<%= Rouge::Themes::MonokaiSublime.render(scope: '.highlight') %>
すると、こんなふうになりました。
一部コメントや括弧の色のスタイルを調整していますが、それなりに見えていい感じじゃないでしょうか。
ちなみに、文中に使っているソースコードは自分の投稿から引用しました。