nanoc導入メモ 4/5 「Markdown独自拡張」編
nanocの醍醐味は、なんといってもRubyによるカスタマイズで記事の作成を効率化したり、挙動を細かく調整できることです。
ここでは番外編として、記事の作成に深く関わるMarkdown周辺のカスタマイズを紹介します。
日本語Markdown
Markdownの見出しは通常#の連続やアンダーラインで表しますが、当サイトでは日本語のテキストでよく使われる「■」と「●」で代用しています。
実装は「lib/default.rb」で文字列を置き換えるフィルタを定義し、「Rules」でMarkdownのフィルタより先に適用するだけです。
class JpMarkdownFilter < Nanoc::Filter
identifier :jp_markdown_filter
def run(content, params={})
mod_content = content.gsub(/^■/, '### ')
mod_content = mod_content.gsub(/^●/, '#### ')
end
end
ちなみに、「■」は「s」、「●」は「m」でIMEに辞書登録しておけば簡単に入力できます。
リンクを新規ウィンドウで開く
Redcarpetにはリンクを「target ="_blank"」で新しいウィンドウで開くための機能はありません。以下のようにして独自のレンダを用意することで常に新規ウィンドウで開くように変更できます。(参考:Issue #85: :auto_link => target=_blank ・ tanoku/redcarpet ・ GitHub)
require "redcarpet"
require "cgi"
class MyRedcarpetRenderer < Redcarpet::Render::XHTML
def link(link, title, alt_text)
"<a href=\"#{CGI::escapeHTML(link)}\" target=\"_blank\">#{alt_text}</a>"
end
end
Redcarpetのレンダは、フィルタ適用時の「:renderer」オプションで指定します。
compile '*' do
if item.binary?
# don't filter binary items
else
case item[:extension]
when 'mkd'
filter :jp_markdown_filter
filter :redcarpet, :options => {:fenced_code_blocks => true},
:renderer => MyRedcarpetRenderer
layout 'default'
# ~~~中略~~~
end
end
end
コードハイライトを行う
Redcarpetの独自レンダに以下を追加することでCodeRayを使った「:fenced_code_blocks」のコードハイライトが可能になります。(参考:Redcarpet のシンタックスハイライトに CodeRay を使う - すぱぶらの日記)
require "redcarpet"
require "coderay"
class MyRedcarpetRenderer < Redcarpet::Render::XHTML
# ~~~中略~~~
def block_code(code, language)
if language then
CodeRay.scan(code, language).div
else
"\n<pre><code>#{code}</code></pre>\n"
end
end
end
CodeRayはgemでインストールしておく必要があります。
> gem install coderay
画像のサイズを取得し、Highslide JSで表示する
Highslide JSは画像をスムーズに拡大表示することのできるJavaScirptライブラリです。当サイトでは記事本文に挿入する画像の縦横サイズを自動的に取得し、このHighslide JSで表示するようにしています。
Rmagickのインストール
まず、画像のサイズを取得するためにRmagickインストールをインストールします。Rmagickのインストールには、先にImageMagickのインストールが必要です。(参考:Ruby 1.9.2 how to install RMagick on Windows? - Stack Overflow)
ImageMagick: Install from Binary DistributionからWindows用のバイナリをダウンロードし、インストールオプションの「development headers and libraries」にチェックして空白を含まないパスにインストールします。
ユーザ環境変数に以下を追加します。
CPATH=C:\path\to\ImageMagick\include
LIBRARY_PATH=path\to\ImageMagick\lib
gemでrmagickをインストールします。
> gem install rmagick
私の環境では使用時に「CORE_RL_Magick_.dllが見つからない」旨のエラーが出ましたがvcredist_x86.exeをインストールして再起動したら使用可能になりました。(参考:RMagickをインストールした。 | aruy.net)
Highslide JSの導入
Highslide JSの使い方はダウンロードしたファイルに含まれるサンプルを見ればだいたい分かると思います。
「graphics」内の画像をnanocの「content/images/highslide」に、「highslide.js」を「content/javascripts」に、「highslide.css」と「highslide-ie6.css」を「content/stylesheets」にそれぞれコピーします。
なお、「loader.gif」の画像は使用しないため削除します。(削除しないと「loader.white.gif」と名前が被るためコンパイル時にエラーになります)
以下の内容で「layouts/partial_htmls/highslide.erb」を作成し、「layouts/default.haml」のhead内からrenderで読み込みます。
<script type="text/javascript" src="/javascripts/highslide.js"></script>
<link rel="stylesheet" type="text/css" href="/stylesheets/highslide.css" />
<script type="text/javascript">
hs.graphicsDir = '/images/highslide/';
hs.outlineType = 'rounded-white';
</script>
「Rules」のrouteとlayoutを以下の内容に変更します。
route '*' do
if item.binary?
item.identifier.chop + '.' + item[:extension]
else
case item[:extension]
when 'sass'
item.identifier.chop + '.css'
when 'css'
item.identifier.chop + '.css'
when 'js'
item.identifier.chop + '.js'
else
item.identifier + 'index.html'
end
end
end
layout '/partial_htmls/*/', :erb
layout '*', :haml, :ugly => true
画像タグ生成方法の変更
画像サイズの自動取得とタグの生成は、こちらもRedcarpetの独自レンダの中で実装します。以下の内容で、画像の横幅が300px以上の場合、自動的に300pxまで縮小した状態で表示されるようになります。
require 'rmagick'
class MyRedcarpetRenderer < Redcarpet::Render::XHTML
#~~~中略~~~
def image(link, title, alt_text)
img = Magick::Image.read(File.expand_path(File.join(File.dirname(__FILE__), '..')) + '/content' + link).first
max_width = 300.0
width = img.columns
height = img.rows
if width > max_width then
height = (height * (max_width / width)).round
width = max_width.round
end
s = <<"EOS"
<a href="#{link}" class="highslide" onclick="return hs.expand(this)">
<img src="#{link}" alt="#{alt_text}" title="Click to enlarge" width="#{width}" height="#{height}" />
</a>
<span class="highslide-caption">#{alt_text}</span>
EOS
end
end
なお、それほど大きな画像は使用しないと思われるので、クリック時のローディング時間短縮のためにもサムネイルの生成はしていません。
おわりに
サイト公開までに行ったnanocのカスタマイズについては、これで大体書き出すことができました。
次回「運用効率化バッチ」編では、繰り返し必要になるデプロイ作業などをバッチ化して簡単に実行する方法を紹介します。
連載一覧
- nanoc導入メモ 1/5 「Getting Started」編
- nanoc導入メモ 2/5 「Basic Concepts」編
- nanoc導入メモ 3/5 「カスタマイズ」編
- nanoc導入メモ 4/5 「Markdown独自拡張」編
- nanoc導入メモ 5/5 「運用効率化バッチ」編