Railsアプリでのシンタックスハイライト付Markdown対応

先日ブログサイトをRailsで自作したときに本文をMarkdownで書けるようにしました。併せてソースコードのシンタックスハイライトも実現したのですが、とても簡単だったので書いておきます。

使ったもの

- Rails (5.0.1)
- [Redcarpet gem](https://github.com/vmg/redcarpet) (3.4.0)
- [Rouge gem](https://github.com/jneen/rouge) (1.11.1)

# 普通にRedcarpetを使う場合

そもそものRedcarpetの使い方はこのような感じです。

```ruby
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のソースはこのようになります。

```html
<code class="ruby">
# app/controllers/api/api_controller.rb 
class Api::ApiController &lt; 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のロードパスに置きます。

```ruby
require 'rouge/plugins/redcarpet'

class HTML < Redcarpet::Render::HTML
  include Rouge::Plugins::Redcarpet
end
```

最初に紹介したRedcarpetの使い方のコードのうち、`Redcarpet::Render::HTML`のところを先程用意したクラスに置き換えることで、ソースコード部分がRougeで処理されるようになります。

```ruby
renderer = HTML.new(options) 
markdown = Redcarpet::Markdown.new(renderer, fenced_code_blocks: true) 
html = markdown.render(content) 
```

するとこのようにソースコードの箇所に細かくCSSのクラスが付きます。

```html
<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">&lt;</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>
```

ですが、このままではハイライトされません。スタイルがないからです。

![](https://gyazo.com/045cea49687e0c0c689e8305be442d83.png)

# スタイルをあてる

Rougeではシンタックスハイライト用のCSSを生成できるようになっています。

いくつかのテーマと、ソースコード部分のDOMのトップにつけるクラスを指定できます。僕はSublime TextなどのMonokaiテーマを好んで使っているので↓のような感じですね。

```ruby
Rouge::Themes::MonokaiSublime.render(scope: '.highlight')
```

生成されたCSSをファイルに保存してからアプリケーションに読み込んでもいいのですが、どうせプリコンパイルされるので僕はアセットパイプラインに入れてしまっています。

```scss:rouge.scss.erb
<%= Rouge::Themes::MonokaiSublime.render(scope: '.highlight') %> 
```

すると、こんなふうになりました。

![](https://gyazo.com/f9b9851aadab51ffa681c7059912b13b.png)

一部コメントや括弧の色のスタイルを調整していますが、それなりに見えていい感じじゃないでしょうか。

ちなみに、文中に使っているソースコードは自分の投稿から引用しました。

[![](http://capture.heartrails.com/200x150/shadow/border?https://blog.piyo.tech/posts/2015-12-06-000000)](https://blog.piyo.tech/posts/2015-12-06-000000)
[RailsアプリにiOSクライアントをサッと作る #sgadvent | ぴよログ](https://blog.piyo.tech/posts/2015-12-06-000000)