人間とウェブの未来

「ウェブの歴史は人類の歴史の繰り返し」という観点から色々勉強しています。

ApacheやnginxのMarkdownファイル変換モジュールをmrubyで簡単に書いてみよう

今回は、.mdファイルにMarkdown形式で文章を書いておき、それをApache httpdやnginxでホストし、ブラウザからアクセスするとHTMLに変換されて表示されるMarkdownコンバータモジュールをmrubyで書く方法を紹介したいと思います。

Markdownのテキスト形式で保存しているファイルを適当にApache上で配信すれば、ブラウザ上でHTMLで綺麗に閲覧できるといったよくあるアレをWebサーバを拡張して実装してみようという話です。自分の開発環境やローカル環境のメモ置き場にも良いかもしれません。

Apacheモジュールやnginxモジュールで幾つかそういった機能を提供するモジュールはあると思うのですが、もう少し独自で改良したかったり、C言語で実装せずにもっと簡単に自分で書いてみたい、といった要求に本エントリを読むと答えられると思います。

もちろんそれらの機能の実装は、僕が開発しているApacheはmod_mrubyを、nginxはngx_mrubyを使って実装してみましょう。

ApacheでMarkdownコンバータモジュールをmrubyで実装

では早速実装してみましょう。

まずは、httpd.confconf.d/markdown.confのような設定ファイルに以下のようにApacheモジュール代わりにフックするRubyスクリプトのパスを書きます。

<FilesMatch "^.*\.md$">
    AddType text/html .md
    SetOutputFilter mruby
    mrubyOutputFilter /path/to/filter.rb
</FilesMatch>

続いて、そのRubyスクリプト/path/to/filter.rbに以下のようにMarkdown変換処理を書きます。

# このスクリプトが動くミドルウェアのチェック
if server_name == "NGINX"
  Server = Nginx
elsif server_name == "Apache"
  Server = Apache
end

f = Server::Filter.new

# Markdown変換の準備、スタイルの読込等
css = "https://gist.github.com/andyferra/2554919/raw/2e66cabdafe1c9a7f354aa2ebf5bc38265e638e5/github.css"
title = "markdown"
md = Discount.new css, title

# MarkdownからHTMLに変換したデータをレスポンスデータに上書き
f.body = md.md2html f.body

コードの内容は説明するまでもないでしょう。これだけで、Markdownコンバータモジュールが作成できました。例えば、以下のようなMarkdownファイルにアクセスすると、

# Section
## aaa

- hoge
- foo

## bbb

__code__

    a = 1
    b = a + 1

以下のように表示されます。

f:id:matsumoto_r:20140822220110p:plain

簡単ですね。C言語で書く場合と比べるとコードの量も大幅に少ない事がわかります。

nginxでもMarkdownコンバータモジュールをmrubyで実装してみる

続いてnginxでも同様の機能を実装してみましょう。

nginxでは、mod_mrubyのかわりにngx_mrubyを使いましょう。インストール方法等はGitHubのWikiを御覧ください。また、Dockerfileを使った簡単なインストール方法もWikiに書いているので、ざっと試すにはそれらを使うのが良いかもしれません。

まずは、以下のような設定をnginx.confに書きます。

location ~ \.md$ {
    mruby_output_filter /path/to/filter.rb;
}

続いて、mod_mrubyと同様に/path/to/filter.rbにコンバートの処理を実装します。

# このスクリプトが動くミドルウェアのチェック
if server_name == "NGINX"
  Server = Nginx
elsif server_name == "Apache"
  Server = Apache
end

f = Server::Filter.new

# Markdown変換の準備、スタイルの読込等
css = "https://gist.github.com/andyferra/2554919/raw/2e66cabdafe1c9a7f354aa2ebf5bc38265e638e5/github.css"
title = "markdown"
md = Discount.new css, title

# MarkdownからHTMLに変換したデータをレスポンスデータに上書き
f.body = md.md2html f.body

おや?mod_mrubyの時のmrubyの実装と全く同じですね。

そうなんです。このように、mod_mrubyngx_mrubyはある程度クラスやメソッドの実装の互換性を持たせつつ並行して開発していますので、こういった実装が可能になります。このように開発していくことで、mod_mrubyで学んだメソッドや実装のコツといった資産は、もう一方のngx_mrubyでもある程度活かせる、という特徴があります。

当然、この.mdファイルにアクセスすると、以下のように表示されます。

f:id:matsumoto_r:20140822220110p:plain

mod_mrubyの時と同様ですね。

ApacheモジュールやnginxモジュールをC言語で書く事なくこんなに簡単にかけました。

まとめ

以上のように、今回はApacheとnginxのMarkdownコンバータモジュールをC言語で実装するのではなく、mod_mrubyngx_mrubyを使ってmrubyで実装してみました。

C言語でそれぞれを実装した事がある人は、この実装の簡単さにびっくりしたのではないでしょうか。

このように、mod_mrubyngx_mrubyを使えば、Apacheやnginxのモジュールという敷居の高かった開発が、非常に簡単にできるようになります。また、mod_mrubyngx_mrubyは、mrubyの軽量な特徴をいかして、スクリプト言語による実装にも関わらずかなり高速に動作するように実装しているので、生産性と性能のバランスが取りやすいのではないでしょうか。

非常に簡単にWebサーバの拡張が書けますので、まずは自身のローカルサーバや検証環境等で、自分用の便利なApache(nginx)モジュールをmrubyで開発して遊んでみると、色々捗るのではないかと思います!

例えば今回のMarkdownコンバータの実装に、追加で実装して遊んでみるのも楽しいと思います。休みの日とかサーバ弄って遊んでみよっかなーみたいな日に是非是非色々遊んでみてください!

言い忘れていましたが、mod_mrubyやngx_mrubyのビルドの際に、build_config.rb上でmruby-discountをリンクする設定をコメントで書いているのでそのコメントを外してビルドして下さいね!