「情報革命」とは何でしょうか。それはネットを介した大量情報の流入による社会生活の変化の連続のことです。情報革命の初期に始まる一つの変化は「見る変化」です。情報を最も効率的に処理できる人間の入力デバイスは「目」であり、そのための環境作りがまず構築されるでしょう。

スマートフォンが携帯電話を駆逐したのは、iPhoneのデザインが素晴らしかったからではありません。人々が大量の情報を処理するためには、非効率な「耳」デバイスを置いて、より効率的な「目」デバイスを活用する必要があったからです。

7インチタブレットの新製品投入が相次いでいます。これは何を意味し、何を駆逐するのでしょうか。そのフォルムを見れば答えは明らかでしょう。それはまさに「書籍」なのです。7インチタブレットは「アトムの読書」を「ビットの読書」にすべて置き換えようとしています。

スマートフォンは、話し言葉を文字化して見るためのデバイスとして登場しました。そして7インチタブレットは、文章を読むのに最適化されたデバイスとして今ここに登場したのです。

「見る変化」第二幕の始まりです…


スマホもタブレットも持ってない僕が、偉そうに言うことじゃありませんでしたね!(えっ?)

ブログを電子書籍化する

さて、そうなると僕はこのブログの行く末が心配です。ブログというメディアはもっぱら大型モニタ用に作られたメディアですから、7インチタブレットにおける快適な読書体験に適しているかというと疑問が残ります。苦労して書いた記事を誰も読まない日が来るとしたら悲しいです。承認欲求が満たされません。ブコメやツイートでの「面白い」「へぇ〜」とかの言葉を食べて今日まで生きてきたのに。


そんなわけで…


Jekyllを使ったこのブログ記事を電子書籍化するツール「Maliq」をRubyで作りました!

rubygems: Maliq   github: melborne/maliq

つまりMaliqは、Liquid拡張されたMarkdown形式のコンテンツからEPUBパッケージを作るツールです。Liquidにより実現されているコードのsyntax highlightingやAmazonリンク付きのコンテンツを、そのまま電子書籍化できます。「Markdown」と「Liquid」の頭を取って「Maliq」です。Mr. マリック(Maric)とは何の関係もありません。

Maliqは、maliqmaliq_gepubという2つのコマンドを持っていて、これらのコマンドで簡単にEPUBパッケージが作れるようになっています。maliq はMarkdownをXHTMLに変換し、maliq_gepubはXHTMLファイルからEPUBパッケージを生成します。

maliq_gepubは、小嶋智さんによる「Gepub」というEPUB3に対応した、Ruby製EPUBジェネレータの単なるラッパーです。Maliqにおける変換の仕事の大半はこのGepubで実現されています。素晴らしい!

Maliqの使い方

以下ではMaliqの使い方を説明しています。MaliqはGem化されているので、gem install maliqで入手できます。gepubも同時にインストールされます。

コマンドの使い方

以下の手順に従います。

1. Markdownで書かれたコンテンツファイルを準備する(ex. chapter01.md)。

2. EPUB生成に必要とされるメタ情報をYAMLフォーマットでファイル(複数ある場合は最初のファイル)先頭に記述する(Yaml Front Matter)。

3. ファイル内にチャプター区切りを示す特別のマーカーを書くことで、1つのMarkdownファイルを分割して複数のXHTMLファイルを生成できる。デフォルトでのマーカーの書式は`<<<--- <filename> --->>>`(ex. `<<<--- chapter02 --->>>`)。

4. CSSおよび画像ファイルがあるなら、カレントディレクトリまたはそのサブディレクトリに配置する。

5. コンテンツに特別なLiquid Tagが含まれている場合、対応Pluginを`plugins`サブディレクトリに置く。

6. `maliq`コマンドにMarkdownファイル名を渡して実行する(maliq chapter01.md)。これにより、1または複数のXHTMLファイルがカレントディレクトリに生成される。

7. `maliq_gepub`を実行する。これにより、EPUBファイルがカレントディレクトリ生成される。

Yaml Front Matterのサンプル

YFMのサンプルを示します。

---
language: 'en'
unique_identifier:
 - 'http:/example.jp/bookid_in_url'
 - 'BookID'
 - 'URL'
title: 'Book of Charlie'
subtitle: 'Where Charlie goes to'
creator: 'melborne'
date: '2012-01-01'
---

トリプルダッシュの行の間に、EPUB生成で必要とされるメタ情報をYAMLフォーマットで記述します。メタ項目については以下が参考になります。

Epub Format Construction Guide - HXA7241 - 2007

Liquid plugins

ネット上には各種Liquid pluginがありますが、Maliqでそれらを利用するためには少し修正が要ります。例えば、ネット上のデータにアクセスする必要のあるpluginではそれをローカル保存するような修正が必要になるでしょう。gistにJekyll向けliquid pluginを修正した僕のpluginが少し置いてあるので利用して下さい。

Liquid filters for Maliq gem to generate xhtml — Gist

コードでの使い方

上記コマンドでは定型的なことしかできません。より柔軟に変換を行いたい場合にはRubyでコードを書く必要があります。

Maliq::Converter.newにMarkdownテキストを渡して#runメソッドを実行します。

puts Maliq::Converter.new("#header1\nline1\n\nline2").run

これにより以下が得られます。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xml:lang="ja">
  <head>
    <title></title>
    
  </head>
  <body>
    <h1>header1</h1>

    <p>line1</p>

    <p>line2</p>
  </body>
</html>

pluginでliquid tagをパースするためには、pluginのフォルダを指定する必要があります。これはYaml Front Matterまたは#set_metaメソッドで行います。フォルダのデフォルトはpluginsになっているので、その場合は指定は不要です。

Maliq::Converter.new(<<-EOS).run(false)
---
liquid: 'filters'
---
# header1
{% calc 2 + 3 %}
EOS

これによりfiltersというフォルダ名にあるcalc pluginが使えるようになります。出力です。

<h1>header1</h1>

<p>2 + 3 = 5</p>

#runにfalseを渡すとbody要素のみを返します。

簡単なチュートリアル

次に、順を追って電子書籍を実際に作ってみます。

コンテンツを準備する

まずはMarkdownによるコンテンツを用意します。作業ディレクトリをmy_first_ebook、ファイル名をchapter01.mdとします。

このコンテンツにおけるポイントは次の3点です。

1. コンテンツは"Syntax Highlighting", "Gist", "Amazon Link"用のLiquid Tagを含んでいる。
2. ファイル先頭のYaml Front Matterにおいてメタ情報を定義している。
3. 各章の前にチャプター区切りマーカーを配置している。

Syntax HighlightingにはPygmentsとそのRubyラッパーpygments.rbを使うので、事前にそのインストールが必要になります。以下を参考にしてください。

Install · mojombo/jekyll Wiki

pygments.rbはgem install pygments.rbです。

またAmazon Linkを使うには、AWSのアカウントとruby-aawsのインストールが必要になります。以下を参考にしてください。

Amazon Plugin for Octopress - Zanshin.net

YFMにおいてunique_identifiertitle属性は必須です。language属性も本来必須の属性ですが、Maliqではデフォルトを’ja’としているので、その場合は省略できます。

チュートリアル用に小説を用意しました。上記ポイントに注意しながら目を通してください。中身は気にせずに…

chapter01.md

---
unique_identifier:
 - 'http:/example.jp/bookid_in_url'
 - 'BookID'
 - 'URL'
title: 'Rubyと鶏卵'
subtitle: 'Egg in the Ruby'
creator: 'melborne'
date: '2012-12-01'
---

# 1章 私を煮るなら殻にして

今にして思えばあの時にちゃんとRubyの中に鶏卵を納めておくべきだった。そうすれば、彼女がこんなに変わってしまうことはなかった。そのときの光景はおぞましくも僕の脳裏に焼き付いて離れないけど、それをコードで表現するなら差し詰め次のようになるだろう。

{% highlight ruby %}
if egg.nil?
  egg = Egg.new
elsif egg.empty?
  egg << Egg.new
end
{% endhighlight %}

僕はここで重大なミスを犯す。彼女は`egg`がnilのときにカラにして欲しいと望んだのに、どういう訳か僕は誤って`Egg.new`してしまった。

それからだった。彼女のすべてが変わってしまったのは。

<<<--- chapter02 --->>>


# 2章 怠惰な日々とはにわとGeorge

ルート101を北に向かってもう3時間も休みなしに走ってる。隣には「デカバチンはにわ」が100個ほど置いてある。全くやってられない。彼女は「デカバチンはにわ100個をGeorgeに必ず渡して」って言ったけど、僕はGeorgeがどこで何を生業として生きている人間であるかの情報を、これっぽっちも持ち合わせていない。あるのは彼がRubyと鶏卵に深い造詣があるという彼女からの情報だけだ。それとてフタシカなものだけれども。僕の今の陰鬱な気分をせめてコードで表現させてほしい。

{% gist 4174909 ruby_egg.rb %}

あぁ、どうやら頭が混乱しているようだ。これは昨日Stefanieが僕にpushしたコード片じゃないか。全く、どうかしているよ。

<<<--- chapter03 --->>>

# 3章 僕とタップを踊ろうよ、どんな意味においても

要約するならば、まあ僕がどうしようもなく世間知らずな若造だった、ってことだ。「デカバチンはにわ」を待ってるGeorgeなんて男は元々この世には存在しなかったし、`egg`がemptyのときは`Egg.new`をappendするってのも悪い方策とも言えない。問題の根本解決にはならないかもしれないけれども。それでも僕はルート101とはにわ100個の不整合性には、もっと早くに気づくべきだった。この一件に関しては完全に僕の負けを認めざるを得ない。ゴメンよRuby。許してくれるなら、僕とタップを踊ろうよ。どんな意味においても。

完

{{ 4806906557 | amazon_medium_image }}
{{ 4806906557 | amazon_link }}

小説中のgist tagはgistサーバー上のコードを指し示しています。内容は次のとおりです。

melborne’s gist: 4174909 — Gist

ruby_egg.rb

# encoding: UTF-8

= 1.0/0
(1..).lazy.map {|i| Statue.new(i) }
           .select {|statue| statue.of_liberty? }
           .take(100).send(:george)

# ~> YouLazzyError: undefined method ‘lazy’ for 1..Infinity:Range

Liquid Pluginの配置

次に、pluginsサブディレクトリを作って、ここにpluginを配置します。ここでは僕のgist上のものをcloneします。

Liquid filters for maliq gem to generate xhtml — Gist

my_first_ebook% mkdir plugins
my_first_ebook% git clone git://gist.github.com/4134497.git plugins

結果、ファイル構成は次のようになります。

my_first_ebook% tree
.
├── chapter01.md
└── plugins
    ├── amazon_liquid_tags.rb
    ├── gist_tag.rb
    ├── highlight.rb
    └── syntax.css

1 directory, 5 files

CSSおよび画像ファイルの配置

CSSや画像がある場合は、それぞれcss, imagesなどのサブディレクトリを作って配置します。ここではcssディレクトリを作って、簡単なスタイルシートstyle.cssとsyntax highliting用のsyntax.cssを配置します。syntax.cssは先程gistからcloneした中に含まれるものを使います。style.cssは以下のとおりです。

h1, h2, h3 {
  color: #8B1A1A;
}

ol {
  list-style-type: none;
}

ここでは実践しませんが、表紙画像がある場合はファイル名にcoverを使って(ex. cover.jpg)、imagesディレクトリに配置します。

XHTMLファイルの生成

さて下準備ができたので、maliqコマンドを使ってEPUB用XHTMLファイルを生成します。

my_first_ebook% maliq chapter01.md 
/Users/keyes/.rbenv/versions/1.9.3-p327/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require': iconv will be deprecated in the future, use String#encode instead.
'chapter01.xhtml' created.
'chapter02.xhtml' created.
Image downloading...
'chapter03.xhtml' created.

警告が出ますが、気にせずに生成されたファイル群を見てみます。

my_first_ebook% tree
.
├── chapter01.md
├── chapter01.xhtml
├── chapter02.xhtml
├── chapter03.xhtml
├── css
│   ├── style.css
│   └── syntax.css
├── images
│   └── 51C9X825VXL._SL160_.jpg
└── plugins
    ├── amazon_liquid_tags.rb
    ├── gist_tag.rb
    └── highlight.rb

2 directories, 8 files

chapter01〜03のXHTMLファイルが生成され、Amazonリンクに係る画像データがDLされているのが分かります。

chapter01.xhtmlの中身をちょっと覗いてみます。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xml:lang="ja">
  <head>
    <title>Rubyと鶏卵</title>
    <link href='css/style.css' rel='stylesheet' type='text/css'/>
<link href='css/syntax.css' rel='stylesheet' type='text/css'/>
  </head>
  <body>
<h1>1章 私を煮るなら殻にして</h1>

<p>今にして思えばあの時にちゃんとRubyの中に鶏卵を納めておくべきだった。そうすれば、彼女がこんなに変わってしまうことはなかった。そのときの光景はおぞましくも僕の脳裏に焼き付いて離れないけど、それをコードで表現するなら差し詰め次のようになるだろう。</p>

<div class="highlight"><pre><code class="ruby"><span class="k">if</span> <span class="n">egg</span><span class="o">.</span><span class="n">nil?</span>
  <span class="n">egg</span> <span class="o">=</span> <span class="no">Egg</span><span class="o">.</span><span class="n">new</span>
<span class="k">elsif</span> <span class="n">egg</span><span class="o">.</span><span class="n">empty?</span>
  <span class="n">egg</span> <span class="o">&lt;&lt;</span> <span class="no">Egg</span><span class="o">.</span><span class="n">new</span>
<span class="k">end</span>
</code></pre></div>


<p>僕はここで重大なミスを犯す。彼女は<code>egg</code>がnilのときにカラにして欲しいって望んだのに、どういう訳か僕は誤って<code>Egg.new</code>してしまった。</p>

<p>それからだった。彼女のすべてが変わってしまったのは。</p>
  </body>
</html>

うまく行ったようです。

EPUBパッケージの生成

さて、最後にmaliq_gepubコマンドを使って、EPUBファイルを生成します。

my_first_ebook% maliq_gepub -o ruby_egg.epub
my_first_ebook% ls -l
total 56
-rw-r--r--  1 keyes  staff   2733 11 30 19:07 chapter01.md
-rw-r--r--  1 keyes  staff   1541 11 30 21:21 chapter01.xhtml
-rw-r--r--  1 keyes  staff   1190 11 30 21:21 chapter02.xhtml
-rw-r--r--  1 keyes  staff   2065 11 30 21:21 chapter03.xhtml
drwxr-xr-x  3 keyes  staff    102 11 30 21:21 images
drwxr-xr-x  6 keyes  staff    204 11 30 19:27 plugins
-rw-r--r--  1 keyes  staff  11716 11 30 21:43 ruby_egg.epub

生成されたruby_egg.epubの中身を見てみます。

my_first_ebook% unzip -v ruby_egg.epub 
Archive:  ruby_egg.epub
 Length   Method    Size  Ratio   Date   Time   CRC-32    Name
 --------  ------  ------- -----   ----   ----   ------    ----
      20  Stored       20   0%  11-30-12 21:43  2cab616f  mimetype
     252  Defl:N      172  32%  11-30-12 21:43  e0f26a53  META-INF/container.xml
    1541  Defl:N      740  52%  11-30-12 21:43  a0b369fe  OEBPS/chapter01.xhtml
    1190  Defl:N      748  37%  11-30-12 21:43  6b7298be  OEBPS/chapter02.xhtml
    2065  Defl:N     1062  49%  11-30-12 21:43  7dd26128  OEBPS/chapter03.xhtml
    6034  Defl:N     6003   1%  11-30-12 21:43  988e6d97  OEBPS/images/51C9X825VXL._SL160_.jpg
     710  Defl:N      377  47%  11-30-12 21:43  0b041246  OEBPS/nav.html
     542  Defl:N      370  32%  11-30-12 21:43  05e77aca  OEBPS/nav.xhtml
    1504  Defl:N      552  63%  11-30-12 21:43  30d6f9d0  OEBPS/package.opf
    1227  Defl:N      514  58%  11-30-12 21:43  0a6ee4da  OEBPS/toc.ncx
--------          -------  ---                            -------
   15085            10558  30%                            10 files

よさそうです。

では、EPUBリーダーでファイルを開いてみます。

Alt title

Alt title

Alt title

Alt title

いいですね!

EPUB電子書籍の完成です。


電子書籍「これからRubyを始める人たちへ」の販売について

このEPUB生成ツールを使って、早々このブログにおけるRubyの入門記事を1つ電子書籍化しました。

そしてこれに表紙を付けて、「Gumroad」を通して販売させて戴くことにしました。

start Ruby

start Ruby start Ruby

価格は100円です。

コンテンツについては、ブログ記事「これからRubyを始める人たちへ」における、誤記の修正およびメディア向けの調整を行っていますが、実質的な内容についての追加・変更はありません。したがってテキストに関し、有料購入する価値は無いと思います。しかしながら、次の何れかの理由で興味を持たれる方が居られるかもしれません。

  1. コンテンツに関心があるので、それが電子書籍の形態で読めるのはやはり便利だ。

  2. コードのSyntax HighlightingをEPUBで実現したものをあまり見たことがない。どんなものかちょっと見てみたい。

  3. このEPUB生成ツールMaliqに関心がある。つまり自分もブログを電子書籍化したいので、その出力サンプルとして参考にしたい。

  4. ブログの記事を読んだが参考になった。これが無料なんて申し訳なく思うから買ってあげたい。

  5. ブログの記事は読んでないが、興味はあるのでどうせなら電子書籍で読んでみよう。

  6. なんか表紙が気に入ったからそれを眺めるために買ってみよう。

  7. このブログのネタは全体としてなかなか面白い。これからも継続して欲しいので寄付の気持ちで購入してもいいかな。

  8. タブレットを買ったばかりなので、いろいろな電子書籍を衝動買いしたい。

  9. 今日はいい気分だ。だれでもいいから俺の100円受け取って。

次のリンクはGumroadにおける商品購入リンクになっています。クリックすると、オーバーレイ・ウインドウが立ち上がって、この場でクレジットカード決済による購入が可能です。購入にはクレジット情報およびメールアドレスの入力が必要になります。購入すると、入力したメールアドレスにコンテンツのDLリンクが送られてきます。

電子書籍「これからRubyを始める人たちへ」EPUB版

ご検討のほど、よろしくお願いしますm(__)m

なお、EPUBはAmazon Kindleでは読めないので、mobiなどへの変換が必要です。変換には「calibre」が便利です。


以上、EPUB生成ツールMaliqの紹介と 電子書籍「これからRubyを始める人たちへ」の宣伝でした。


関連記事:エラーメッセージから学ぶ電子書籍EPUB - 最初の一歩


(追記:2012−12−04) pygments.rbのインストールについて追記しました。


Kindle Paperwhite 3G (2012年モデル)



blog comments powered by Disqus
ruby_pack8

100円〜で好評発売中!
M'ELBORNE BOOKS