review 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +1 -0
  3. data/ChangeLog +100 -0
  4. data/README.rdoc +11 -12
  5. data/Rakefile +6 -2
  6. data/bin/review-check +1 -1
  7. data/bin/review-compile +13 -4
  8. data/bin/review-epubmaker +172 -24
  9. data/bin/review-epubmaker-ng +8 -161
  10. data/bin/review-index +1 -1
  11. data/bin/review-init +17 -5
  12. data/bin/review-pdfmaker +40 -19
  13. data/bin/review-preproc +1 -1
  14. data/bin/review-validate +2 -2
  15. data/bin/review-vol +1 -1
  16. data/debian/control +2 -2
  17. data/doc/format.rdoc +23 -6
  18. data/doc/format_idg.rdoc +3 -3
  19. data/doc/libepubmaker/config.yaml +163 -0
  20. data/doc/quickstart.rdoc +27 -27
  21. data/doc/sample.yaml +10 -5
  22. data/lib/epubmaker.rb +2 -5
  23. data/lib/epubmaker/content.rb +9 -6
  24. data/lib/epubmaker/epubv2.rb +233 -109
  25. data/lib/epubmaker/epubv3.rb +83 -119
  26. data/lib/epubmaker/producer.rb +50 -20
  27. data/lib/epubmaker/resource.rb +22 -8
  28. data/lib/review/book/base.rb +1 -0
  29. data/lib/review/book/chapter.rb +2 -2
  30. data/lib/review/book/compilable.rb +1 -1
  31. data/lib/review/book/index.rb +33 -27
  32. data/lib/review/book/parameters.rb +3 -2
  33. data/lib/review/book/part.rb +1 -1
  34. data/lib/review/builder.rb +10 -42
  35. data/lib/review/compiler.rb +1 -1
  36. data/lib/review/configure.rb +3 -3
  37. data/lib/review/epubmaker.rb +428 -0
  38. data/lib/review/htmlbuilder.rb +45 -95
  39. data/lib/review/htmlutils.rb +2 -0
  40. data/lib/review/i18n.yaml +25 -0
  41. data/lib/review/idgxmlbuilder.rb +11 -9
  42. data/lib/review/inaobuilder.rb +1 -1
  43. data/lib/review/latexbuilder.rb +7 -6
  44. data/lib/review/latexutils.rb +6 -0
  45. data/lib/review/makerhelper.rb +4 -2
  46. data/lib/review/markdownbuilder.rb +8 -0
  47. data/lib/review/sec_counter.rb +71 -0
  48. data/lib/review/topbuilder.rb +0 -1
  49. data/lib/review/version.rb +2 -2
  50. data/review.gemspec +4 -4
  51. data/test/sample-book/README.md +2 -2
  52. data/test/sample-book/src/Rakefile +2 -2
  53. data/test/sample-book/src/config.yml +4 -4
  54. data/test/sample-book/src/images/cover.jpg +0 -0
  55. data/test/sample-book/src/sty/{samplemacro.sty → reviewmacro.sty} +1 -1
  56. data/test/test_book_parameter.rb +1 -1
  57. data/test/test_epubmaker.rb +77 -15
  58. data/test/test_epubmaker_cmd.rb +11 -7
  59. data/test/test_helper.rb +7 -0
  60. data/test/test_htmlbuilder.rb +39 -6
  61. data/test/test_idgxmlbuilder.rb +14 -2
  62. data/test/test_inaobuilder.rb +2 -1
  63. data/test/test_latexbuilder.rb +23 -2
  64. data/test/test_makerhelper.rb +19 -3
  65. data/test/test_markdownbuilder.rb +35 -0
  66. data/test/test_pdfmaker_cmd.rb +11 -7
  67. data/test/test_topbuilder.rb +36 -2
  68. metadata +18 -18
  69. data/VERSION +0 -1
  70. data/doc/libepubmaker/sample.yaml +0 -90
data/doc/format_idg.rdoc CHANGED
@@ -1,6 +1,6 @@
1
- = ReVIEW フォーマット InDesign XML 形式拡張
1
+ = Re:VIEW フォーマット InDesign XML 形式拡張
2
2
 
3
- ReVIEW フォーマットから、Adobe 社の DTP ソフトウェア「InDesign」
3
+ Re:VIEW フォーマットから、Adobe 社の DTP ソフトウェア「InDesign」
4
4
  で読み込んで利用しやすい XML 形式に変換できます (通常の XML とほぼ同じ
5
5
  ですが、文書構造ではなく見た目を指向した形態になっています)。
6
6
  現時点では idgxmlbuilder.rb と topbuilder.rb のみが拡張に対応しています。
@@ -107,7 +107,7 @@ XMLとしては<label id='〜' />と<labelref idref='〜' />というタグに
107
107
  という特別な書式を代わりに使います。
108
108
 
109
109
  == ロー指定
110
- 現時点で ReVIEW はブロックの入れ子処理ができないため、ロー指定で XML
110
+ 現時点で Re:VIEW はブロックの入れ子処理ができないため、ロー指定で XML
111
111
  エレメントを指定しなければならないこともあります。
112
112
 
113
113
  インラインの@<raw>{ 〜 }の他に、単一行の//raw[〜]、ブロック版の //rawblock{ 〜 //} でも、フォーマット処理をせずにそのままの文字列が出力できます。
@@ -0,0 +1,163 @@
1
+ # review-epubmaker-ng向けYAMLファイルのサンプル
2
+ #
3
+ # このファイルはUTF-8エンコーディングで記述してください
4
+ # YAMLにおける空は、「nil」ではなく「null」であることに注意してください
5
+
6
+ # ブック名(ファイル名になるもの。ASCII範囲の文字を使用)
7
+ bookname: sample
8
+ # 記述言語
9
+ language: ja
10
+ # 書名
11
+ title: "Re:VIEW EPUBのサンプル"
12
+
13
+ # 固有IDに使用するドメイン。指定しない場合には、時刻に基づくランダムUUIDが入る
14
+ # urnid: urn:uid:http://example.com/some-book-title/1.0.2/
15
+
16
+ # ISBN。省略した場合はランダム生成したUUIDが入る
17
+ # isbn: null
18
+
19
+ # 著者名。「, 」で区切って複数指定できる
20
+ aut: ["Minero Aoki", "Kenshi Muto", "Masayoshi Takahashi", "Masanori Kado"]
21
+
22
+ # 以下はオプション(autと同じように配列書式で複数指定可能)。
23
+ # a-が付いているものはcreator側、
24
+ # 付いていないものはcontributor側(二次協力者)に入る
25
+ # a-adp, adp: 異なるメディア向けに作り直した者
26
+ # a-ann, ann: 注釈記述者
27
+ # a-arr, arr: アレンジした者
28
+ # a-art, art: グラフィックデザインおよび芸術家
29
+ # a-asn, asn: 関連・かつての所有者・関係者
30
+ # a-aqt, aqt: 大きく引用された人物
31
+ # a-aft, aft: 後書き・奥付の責任者
32
+ # a-aui, aui: 序論・序文・前書きの責任者
33
+ # a-ant, ant: 目録責任者
34
+ # a-bkp, bkp: メディア制作責任者
35
+ # a-clb, clb: 限定参加または補足者
36
+ # a-cmm, cmm: 解釈・分析・考察者
37
+ # a-dsr, dsr: デザイナ
38
+ # a-edt, edt: 編集者
39
+ # a-ill, ill: イラストレータ
40
+ # a-lyr, lyr: 歌詞作成者
41
+ # a-mdc, mdc: メタデータセットの一次的責任者
42
+ # a-mus, mus: 音楽家
43
+ # a-nrt, nrt: 語り手
44
+ # a-oth, oth: その他
45
+ # a-pht, pht: 撮影責任者
46
+ # a-prt, prt: 出版社
47
+ # a-red, red: 項目の枠組起草者
48
+ # a-rev, rev: 評論者
49
+ # a-spn, spn: 援助者
50
+ # a-ths, ths: 監督者
51
+ # a-trc, trc: 筆記・タイプ作業者
52
+ # a-trl, trl: 翻訳者
53
+
54
+ # rights: 権利表記(配列で複数指定可)
55
+ # date: 刊行日(省略した場合は実行時の日付)
56
+ # description: 説明
57
+ # subject: 短い説明用タグ(配列で複数指定可)
58
+ # type: 書籍のカテゴリーなど(配列で複数指定可)
59
+ # format: メディアタイプおよび特徴(配列で複数指定可)
60
+ # source: 出版物生成の重要なリソース情報(配列で複数指定可)
61
+ # relation: 補助的リソース(配列で複数指定可)
62
+ # coverage: 内容の範囲や領域(配列で複数指定可)
63
+
64
+ # htmlext: HTMLファイルの拡張子(省略した場合はhtml)
65
+ # cover: カバーページのファイル名(省略した場合はbookname.xhtmlになる)
66
+ #
67
+ # coverimage: カバー用画像
68
+ #
69
+ # CSSファイル(配列で複数指定可)
70
+ stylesheet: ["stylesheet.css"]
71
+
72
+ # ePUBのバージョン (2か3)
73
+ # epubversion: 2
74
+ # HTMLのバージョン (4か5。epubversionを3にしたときには5にする)
75
+ # htmlversion: 4
76
+
77
+ # 目次として抽出する見出しレベル
78
+ # toclevel: 2
79
+ # 目次を要素の階層表現にしない。省略した場合(null)は階層化する。
80
+ # 構成によっては、階層化目次ではepubcheckにパスしない目次ができるが、
81
+ # そのようなときにはこれをtrueにする
82
+ # flattoc: null
83
+ # 目次のインデントレベルをスペース文字で表現する(flattocがtrueのときのみ)
84
+ # flattocindent: true
85
+ # 本文でセクション番号を表示する見出しレベル
86
+ # secnolevel: 2
87
+ # 前付でセクション番号を表示する見出しレベル
88
+ # pre_secnolevel: 0
89
+ # 後付でセクション番号を表示する見出しレベル
90
+ # post_secnolevel: 0
91
+ # 部番号を表示する見出しレベル
92
+ # part_secnolevel: 1
93
+
94
+ # NCX目次の見出しレベルごとの飾り(配列で設定)
95
+ #ncxindent:
96
+ #-
97
+ #- -
98
+
99
+ # EPUB2標準の目次以外に物理目次ファイルを作成するか。省略した場合はnull (作成しない)
100
+ # ePUB3においてはこの設定によらず必ず作成する
101
+ # mytoc: true
102
+
103
+ # 表紙の後に権利表記ページを作成するか。デフォルトでは作成されない。ファイル名を指定するとそのファイルが使われる(data配列にも指定しておく必要がある)
104
+ # titlepage: title.xhtml
105
+
106
+ # 奥付を作成するか。デフォルトでは作成されない。trueを指定するとデフォルトの奥付、ファイル名を指定するとそれがcolophon.xhtmlとしてコピーされる(data配列にも指定しておく必要がある)
107
+ # colophon: true
108
+ # pubhistory: 奥付履歴
109
+
110
+ # プロフィールページファイル。ファイル名を指定すると著者紹介として入る
111
+ # profile: null
112
+ # プロフィールページの目次上の見出し
113
+ # profiletitle: 著者紹介
114
+
115
+ # フックは、各段階で介入したいときのプログラムを指定する。自動で適切な引数が渡される
116
+ # プログラムには実行権限が必要
117
+
118
+ # ファイル変換処理の前に実行するプログラム。スタイルシートのコンパイルをしたいときなどに利用する。
119
+ # 渡される引数1=作業用展開ディレクトリ
120
+ # hook_beforeprocess: null
121
+
122
+ # 前付の変換後に実行するプログラム。作業用展開ディレクトリにある目次ファイル(toc-html.txt)を操作したいときなどに利用する。
123
+ # 渡される引数1=作業用展開ディレクトリ
124
+ # hook_afterfrontmatter: null
125
+
126
+ # 本文の変換後に実行するプログラム。作業用展開ディレクトリにある目次ファイル(toc-html.txt)を操作したいときなどに利用する。
127
+ # 渡される引数1=作業用展開ディレクトリ
128
+ # hook_afterbody: null
129
+
130
+ # 後付の変換後に実行するプログラム。作業用展開ディレクトリにある目次ファイル(toc-html.txt)を操作したいときなどに利用する。
131
+ # 渡される引数1=作業用展開ディレクトリ
132
+ # hook_afterbackmatter: null
133
+
134
+ # 画像およびフォントをコピーした後に実行するプログラム。別の画像やフォントを追加したいときなどに利用する。
135
+ # 渡される引数1=作業用展開ディレクトリ
136
+ # hook_aftercopyimage: null
137
+
138
+ # ePUB zipアーカイブ直前に実行するプログラム。メタ情報などを加工したいときなどに利用する。
139
+ # 渡される引数1=ePUB準備ディレクトリ
140
+ # hook_prepack: null
141
+
142
+ # ハイライトを有効にするか。pygments.gemが必要
143
+ # pygments: null
144
+
145
+ # 取り込む画像が格納されているディレクトリ。省略した場合は以下
146
+ # imagedir: images
147
+
148
+ # 取り込むフォントが格納されているディレクトリ。省略した場合は以下
149
+ # fontdir: fonts
150
+
151
+ # imagedir内から取り込まれる対象となるファイル拡張子。省略した場合は以下
152
+ # image_ext: ["png", "gif", "jpg", "jpeg", "svg", "ttf", "woff", "otf"]
153
+
154
+ # fontdir内から取り込まれる対象となるファイル拡張子。省略した場合は以下
155
+ # font_ext: ["ttf", "woff", "otf"]
156
+
157
+ # Re:VIEWファイル名を使わず、前付にpre01,pre02...、本文にchap01,chap02l...、後付にpost01,post02...という名前付けルールにするか
158
+ # rename_for_legacy: null
159
+
160
+ # ePUBアーカイブの非圧縮実行
161
+ # zip_stage1: "zip -0Xq"
162
+ # ePUBアーカイブの圧縮実行
163
+ # zip_stage2: "zip -Xr9Dq"
data/doc/quickstart.rdoc CHANGED
@@ -1,24 +1,24 @@
1
- = ReVIEWクイックスタートガイド
1
+ = Re:VIEWクイックスタートガイド
2
2
 
3
- ReVIEW は、EWB や RD あるいは Wiki に似た簡易フォーマットで記述したテキストファイルを、目的に応じて各種の形式に変換するツールセットです。
3
+ Re:VIEW は、EWB や RD あるいは Wiki に似た簡易フォーマットで記述したテキストファイルを、目的に応じて各種の形式に変換するツールセットです。
4
4
 
5
5
  平易な文法ながらも、コンピュータ関係のドキュメント作成のための多くの機能を備えており、テキスト、LaTeX、HTML、XML といった形式に変換できます。独自のカスタマイズも簡単です。
6
6
 
7
- ReVIEW は GNU Lesser General Public License Version 2.1 に基づいて配布されており、自由に利用、改変、再配布できます。このライセンスは、ReVIEW を使ってあなたが作成しようとする文書とは無関係であり、あなたの文書はこのライセンスに強制されることはありません。ReVIEW のツールセットあるいは ReVIEW を組み込んだシステムを配布あるいは販売しようとしているときには、ライセンスファイル COPYING をよく確認してください。
7
+ Re:VIEW は GNU Lesser General Public License Version 2.1 に基づいて配布されており、自由に利用、改変、再配布できます。このライセンスは、Re:VIEW を使ってあなたが作成しようとする文書とは無関係であり、あなたの文書はこのライセンスに強制されることはありません。Re:VIEW のツールセットあるいは Re:VIEW を組み込んだシステムを配布あるいは販売しようとしているときには、ライセンスファイル COPYING をよく確認してください。
8
8
 
9
- このドキュメントでは、ReVIEW のセットアップから変換の例までを簡単に説明します。
9
+ このドキュメントでは、Re:VIEW のセットアップから変換の例までを簡単に説明します。
10
10
 
11
11
  == セットアップ
12
12
 
13
- ReVIEW は Ruby 言語で記述されており、Linux/Unix 互換システムで動作します。Mac OS X および Windows Cygwin でも動作可能です。Ruby gem、Git、Subversion のいずれかを使ってダウンロード・展開します。
13
+ Re:VIEW は Ruby 言語で記述されており、Linux/Unix 互換システムで動作します。Mac OS X および Windows Cygwin でも動作可能です。Ruby gem、Git、Subversion のいずれかを使ってダウンロード・展開します。
14
14
 
15
- なお、ReVIEW フォーマット自体は文字で表現されたタグが付いている以外は単なるテキストファイルなので、エディタ、OS についてはまったく制限はありません。
15
+ なお、Re:VIEW フォーマット自体は文字で表現されたタグが付いている以外は単なるテキストファイルなので、エディタ、OS についてはまったく制限はありません。
16
16
 
17
17
  === Ruby gemを使う場合
18
18
 
19
- 機能セットがまとまった区切りごとに、ReVIEW の開発チームが ReVIEW の gem を更新しています。
19
+ 機能セットがまとまった区切りごとに、Re:VIEW の開発チームが Re:VIEW の gem を更新しています。
20
20
 
21
- 次のように ReVIEW の gem をインストールします。
21
+ 次のように Re:VIEW の gem をインストールします。
22
22
 
23
23
  gem install review
24
24
 
@@ -30,7 +30,7 @@ Ruby gem の bin ディレクトリにパスを通すようにしておいてく
30
30
 
31
31
  === Gitを使う場合
32
32
 
33
- ReVIEW は GitHub で開発されており、バージョン管理ツールの Git を使って最新の ReVIEW コードを入手できます。Git は分岐が容易なので、独自のカスタマイズを施すのにも向いています。
33
+ Re:VIEW は GitHub で開発されており、バージョン管理ツールの Git を使って最新の Re:VIEW コードを入手できます。Git は分岐が容易なので、独自のカスタマイズを施すのにも向いています。
34
34
 
35
35
  初めて取得するときには、次のようにします (コピーを作っています)。
36
36
 
@@ -56,19 +56,19 @@ review というディレクトリに展開されるので、review/bin にパ
56
56
 
57
57
  svn up
58
58
 
59
- = ReVIEW テキストの作成と変換
59
+ = Re:VIEW テキストの作成と変換
60
60
 
61
- セットアップを終えたら、ReVIEW フォーマットのテキストを作り、変換できるようになります。次に ReVIEW フォーマットテキストの簡単な例を示します。これを sample.re といった名前で保存します (拡張子も自由ですが、.re 拡張子を推奨します)。
61
+ セットアップを終えたら、Re:VIEW フォーマットのテキストを作り、変換できるようになります。次に Re:VIEW フォーマットテキストの簡単な例を示します。これを sample.re といった名前で保存します (拡張子も自由ですが、.re 拡張子を推奨します)。
62
62
 
63
- = はじめてのReVIEW
63
+ = はじめてのRe:VIEW
64
64
 
65
65
  //lead{
66
- 「Hello, ReVIEW.」
66
+ 「Hello, Re:VIEW.」
67
67
  //}
68
68
 
69
- == ReVIEWとは
69
+ == Re:VIEWとは
70
70
 
71
- @<b>{ReVIEW}は、EWBやRDあるいはWikiに似た簡易フォーマットで記述したテキストファイルを、目的に応じて各種の形式に変換するツールセットです。
71
+ @<b>{Re:VIEW}は、EWBやRDあるいはWikiに似た簡易フォーマットで記述したテキストファイルを、目的に応じて各種の形式に変換するツールセットです。
72
72
 
73
73
  平易な文法ながらも、コンピュータ関係のドキュメント作成のための多くの機能を備えており、次のような形式に変換できます。
74
74
 
@@ -85,13 +85,13 @@ review というディレクトリに展開されるので、review/bin にパ
85
85
 
86
86
  ホームページは@<tt>{https://github.com/kmuto/review/wiki/}です。
87
87
 
88
- テキストファイルの文字エンコーディングには、UTF-8 を使うことをお勧めします。ReVIEW は日本語文字エンコーディングとして UTF-8、EUC-JP、Shift-JIS、JIS を扱うことができ、入力ファイルについては自動判別、出力ファイルについても選択可能 (デフォルトは UTF-8) ですが、入力・出力のいずれにおいても、使用可能な文字についての制限が少ない UTF-8 が最適です。
88
+ テキストファイルの文字エンコーディングには、UTF-8 を使うことをお勧めします。Re:VIEW は日本語文字エンコーディングとして UTF-8、EUC-JP、Shift-JIS、JIS を扱うことができ、入力ファイルについては自動判別、出力ファイルについても選択可能 (デフォルトは UTF-8) ですが、入力・出力のいずれにおいても、使用可能な文字についての制限が少ない UTF-8 が最適です。
89
89
 
90
- 次に、章構成ファイルの CHAPS ファイルを同じディレクトリに用意します。このファイルには、ReVIEW フォーマットファイルの名前を格納します。
90
+ 次に、章構成ファイルの CHAPS ファイルを同じディレクトリに用意します。このファイルには、Re:VIEW フォーマットファイルの名前を格納します。
91
91
 
92
92
  sample.re
93
93
 
94
- CHAPS ファイルの1行目に書いたものが第1章、2行目に書いたものが第2章、……と構成されます (CHAPS に似たものとして、前付けを列挙する PREDEF ファイル、後付けを列挙する POSTDEF ファイルがあります)。
94
+ CHAPS ファイルの1行目に書いたものが第1章、2行目に書いたものが第2章、……と構成されます (CHAPS に似たものとして、前付けを列挙する PREDEF ファイル、後付けを列挙する POSTDEF ファイルがあります。これらを「カタログファイル」と呼びます)。
95
95
 
96
96
  sample.re から目的の形式に変換するには、review-compile コマンドを使います。
97
97
 
@@ -112,17 +112,17 @@ sample.re を HTML に変換すると、次のようになります。
112
112
  <head>
113
113
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
114
114
  <meta http-equiv="Content-Style-Type" content="text/css" />
115
- <meta name="generator" content="ReVIEW" />
116
- <title>はじめてのReVIEW</title>
115
+ <meta name="generator" content="Re:VIEW" />
116
+ <title>はじめてのRe:VIEW</title>
117
117
  </head>
118
118
  <body>
119
- <h1><a id="h1" />第1章 はじめてのReVIEW</h1>
119
+ <h1><a id="h1" />第1章 はじめてのRe:VIEW</h1>
120
120
  <div class="lead">
121
- <p>「Hello, ReVIEW.」</p>
121
+ <p>「Hello, Re:VIEW.」</p>
122
122
  </div>
123
123
 
124
- <h2><a id="h1-1" />1.1 ReVIEWとは</h2>
125
- <p><b>ReVIEW</b>は、EWBやRDあるいはWikiに似た簡易フォーマットで記述したテキストファイルを、目的に応じて各種の形式に変換するツールセットです。</p>
124
+ <h2><a id="h1-1" />1.1 Re:VIEWとは</h2>
125
+ <p><b>Re:VIEW</b>は、EWBやRDあるいはWikiに似た簡易フォーマットで記述したテキストファイルを、目的に応じて各種の形式に変換するツールセットです。</p>
126
126
  <p>平易な文法ながらも、コンピュータ関係のドキュメント作成のための多くの機能を備えており、次のような形式に変換できます。</p>
127
127
  <ul>
128
128
  <li>テキスト(指示タグ付き)</li>
@@ -140,13 +140,13 @@ sample.re を HTML に変換すると、次のようになります。
140
140
  </body>
141
141
  </html>
142
142
 
143
- ReVIEW フォーマットについての詳細は、 {format.rdoc}[https://github.com/kmuto/review/blob/master/doc/format.rdoc] を参照してください。
143
+ Re:VIEW フォーマットについての詳細は、 {format.rdoc}[https://github.com/kmuto/review/blob/master/doc/format.rdoc] を参照してください。
144
144
 
145
145
  review-compile を含め、ほとんどのコマンドは --help オプションを付けるとオプションについてのヘルプが表示されます。review-compile には多数のオプションがあるので確認してください。
146
146
 
147
147
  なお、--target で毎回指定するのは面倒なので、review-compile に対するシンボリックリンクを作成しておくとよいでしょう。「review2...」のコマンド名で呼び出せるようになります。
148
148
 
149
- cd ReVIEWのインストールされたパス/bin
149
+ cd Re:VIEWのインストールされたパス/bin
150
150
  ln -s review-compile review2text
151
151
  ln -s review-compile review2html
152
152
  ln -s review-compile review2latex
@@ -181,7 +181,7 @@ PDF を作成するには、pTeXLive2009 以上の環境が必要です。EPUB
181
181
 
182
182
  == クレジット
183
183
 
184
- ReVIEW は、青木峰郎によって最初に作成されました。武藤健志がこの開発・保守を引き継ぎ、201012月時点では、武藤健志、高橋征義、角征典が開発・保守を継続しています。
184
+ Re:VIEW は、青木峰郎によって最初に作成されました。武藤健志がこの開発・保守を引き継ぎ、20143月時点では、武藤健志、高橋征義、角征典が開発・保守を継続しています。
185
185
 
186
186
  バグ・パッチの報告、開発者用メーリングリストなどについての情報は、
187
187
  https://github.com/kmuto/review/wiki
data/doc/sample.yaml CHANGED
@@ -1,5 +1,5 @@
1
1
  # review-epubmaker向けの設定ファイルの例。
2
- # yamlファイルをReVIEWファイルのある場所に置き、
2
+ # yamlファイルをRe:VIEWファイルのある場所に置き、
3
3
  # 「review-epubmaker yamlファイル」を実行すると、<bookname>.epubファイルが
4
4
  # 生成されます。
5
5
  # このファイルはUTF-8エンコーディングで記述してください。
@@ -7,14 +7,15 @@
7
7
  # ブック名(ファイル名になるもの。ASCII範囲の文字を使用)
8
8
  bookname: review-sample
9
9
  # 書名
10
- booktitle: ReVIEW EPUBサンプル
10
+ booktitle: Re:VIEW EPUBサンプル
11
11
  # 著者
12
- aut: 吟遊詩人
12
+ aut: 執筆者
13
13
  # 以下はオプション
14
14
  # prt: 出版社
15
15
  # asn: Associated name
16
16
  # ant: Bibliographic antecedent
17
17
  # clb: 貢献者
18
+ # csl: 監修者
18
19
  # edt: 編集者
19
20
  # dsr: デザイナ
20
21
  # ill: イラストレータ
@@ -30,12 +31,14 @@ aut: 吟遊詩人
30
31
  #
31
32
  # 固有IDに使用するドメイン。指定しない場合には、時刻に基づくランダムUUIDが入る
32
33
  # urnid: urn:uid:http://example.com/some-book-title/1.0.2/
33
- # CSSファイル (yamlファイルおよびReVIEWファイルを置いたディレクトリにあること)
34
+ # CSSファイル (yamlファイルおよびRe:VIEWファイルを置いたディレクトリにあること)
34
35
  stylesheet: stylesheet.css
35
36
  # LaTeX用のスタイルファイル(styディレクトリ以下に置くこと)
36
37
  # texstyle: samplemacro
37
38
  # LaTeX用のdocumentclassを指定する
38
39
  # texdocumentclass: ["jsarticle", "b5paper,oneside"]
40
+ # LaTeX用のコマンドを指定する(platex or lualatex)
41
+ # texcommand: "platex"
39
42
  # 目次として抽出するレベル
40
43
  toclevel: 3
41
44
  # セクション番号を表示するレベル
@@ -52,11 +55,13 @@ toc: true
52
55
  mytoc: null
53
56
  # 奥付を作成するか。デフォルトでは作成されない。trueを指定するとデフォルトの奥付、ファイル名を指定するとそれがcolophon.htmlとしてコピーされる
54
57
  colophon: null
55
- # XHTML生成後に実行するプログラム。$1:HTMLの生成されたディレクトリ $2:ReVIEWファイルのあるディレクトリ $3:起動時指定のyamlファイル名
58
+ # XHTML生成後に実行するプログラム。$1:HTMLの生成されたディレクトリ $2:Re:VIEWファイルのあるディレクトリ $3:起動時指定のyamlファイル名
56
59
  # posthook: hook.sh
57
60
  # EPUBで表紙をコンテンツに含めるか。デフォルトでは作成されない。yesにするとiBooks等でも最初に表紙が表示されるようになる
58
61
  cover_linear: null
59
62
  # review-compileに渡すパラメータ
60
63
  params: --stylesheet=sample.css
64
+ # Pygmentsカラーリングを利用する (pygments外部gemが必要)
65
+ # pygments: true
61
66
  # デバッグフラグ。nullでないときには一時ファイルをカレントディレクトリに作成し、削除もしない
62
67
  debug: null
data/lib/epubmaker.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  # = epubmaker.rb -- EPUB production set.
3
3
  #
4
- # Copyright (c) 2010-2012 Kenshi Muto
4
+ # Copyright (c) 2010-2013 Kenshi Muto
5
5
  #
6
6
  # This program is free software.
7
7
  # You can distribute or modify this program under the terms of
@@ -9,16 +9,13 @@
9
9
  # For details of the GNU LGPL, see the file "COPYING".
10
10
  #
11
11
  # == Quick usage
12
- # (If you put xhtml files on current directory and put figures in
13
- # images subdirectory)
14
- #
15
12
  # require 'epubmaker'
16
13
  # epub = EPUBMaker::Producer.new
17
14
  # params = epub.load("config.yaml")
18
15
  # epub.contents.push(EPUBMaker::Content.new({"file" => "ch01.xhtml"}))
19
16
  # epub.contents.push(EPUBMaker::Content.new({"file" => "ch02.xhtml"}))
20
17
  # ...
21
- # epub.importImageInfo("images")
18
+ # epub.import_imageinfo("images")
22
19
  # epub.produce
23
20
 
24
21
  require 'epubmaker/producer'
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  # = content.rb -- Content object for EPUBMaker.
3
3
  #
4
- # Copyright (c) 2010 Kenshi Muto
4
+ # Copyright (c) 2010-2014 Kenshi Muto
5
5
  #
6
6
  # This program is free software.
7
7
  # You can distribute or modify this program under the terms of
@@ -11,11 +11,12 @@
11
11
 
12
12
  module EPUBMaker
13
13
 
14
- # EPUBMaker::Content describes a content data for EPUBMaker. EPUBMaker#contents takes an array of Content.
14
+ # EPUBMaker::Content represents a content data for EPUBMaker.
15
+ # EPUBMaker#contents takes an array of Content.
15
16
  class Content
16
17
  # ID
17
18
  attr_accessor :id
18
- # File path (can accept #<anchor> suffix also)
19
+ # File path (will accept #<anchor> suffix also)
19
20
  attr_accessor :file
20
21
  # MIME type
21
22
  attr_accessor :media
@@ -61,9 +62,10 @@ module EPUBMaker
61
62
 
62
63
  private
63
64
 
64
- # Complement other parameters from file parameter.
65
+ # Complement other parameters by using file parameter.
65
66
  def complement
66
- @id = @file.gsub(/[\\\/\.]/, '-') if @id.nil?
67
+ @id = @file.gsub(/[\\\/\. ]/, '-') if @id.nil?
68
+ @id = "rv-#{@id}" if @id =~ /\A[^a-z]/i
67
69
  @media = @file.sub(/.+\./, '').downcase if !@file.nil? && @media.nil?
68
70
 
69
71
  @media = "application/xhtml+xml" if @media == "xhtml" || @media == "xml" || @media == "html"
@@ -71,8 +73,9 @@ module EPUBMaker
71
73
  @media = "image/jpeg" if @media == "jpg" || @media == "jpeg" || @media == "image/jpg"
72
74
  @media = "image/png" if @media == "png"
73
75
  @media = "image/gif" if @media == "gif"
74
- @media = "image/svg" if @media == "svg"
75
76
  @media = "image/svg+xml" if @media == "svg" || @media == "image/svg"
77
+ @media = "application/vnd.ms-opentype" if @media == "ttf" || @media == "otf"
78
+ @media = "application/font-woff" if @media == "woff"
76
79
 
77
80
  if @id.nil? || @file.nil? || @media.nil?
78
81
  raise "Type error: #{id}, #{file}, #{media}, #{title}, #{notoc}"
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  # = epubv2.rb -- EPUB version 2 producer.
3
3
  #
4
- # Copyright (c) 2010-2012 Kenshi Muto and Masayoshi Takahashi
4
+ # Copyright (c) 2010-2013 Kenshi Muto and Masayoshi Takahashi
5
5
  #
6
6
  # This program is free software.
7
7
  # You can distribute or modify this program under the terms of
@@ -13,19 +13,19 @@ require 'epubmaker/producer'
13
13
  require 'cgi'
14
14
 
15
15
  module EPUBMaker
16
-
16
+
17
17
  # EPUBv2 is EPUB version 2 producer.
18
18
  class EPUBv2
19
19
  # Construct object with parameter hash +params+ and message resource hash +res+.
20
20
  def initialize(producer)
21
21
  @producer = producer
22
22
  end
23
-
23
+
24
24
  # Return mimetype content.
25
25
  def mimetype
26
- return "application/epub+zip"
26
+ "application/epub+zip"
27
27
  end
28
-
28
+
29
29
  # Return opf file content.
30
30
  def opf
31
31
  s = <<EOT
@@ -33,6 +33,23 @@ module EPUBMaker
33
33
  <package version="2.0" xmlns="http://www.idpf.org/2007/opf" unique-identifier="BookId">
34
34
  <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
35
35
  EOT
36
+
37
+ s << opf_metainfo
38
+ s << opf_coverimage
39
+
40
+ s << %Q[ </metadata>\n]
41
+
42
+ s << opf_manifest
43
+ s << opf_tocx
44
+ s << opf_guide
45
+
46
+ s << %Q[</package>\n]
47
+
48
+ s
49
+ end
50
+
51
+ def opf_metainfo
52
+ s = ""
36
53
  %w[title language date type format source description relation coverage subject rights].each do |item|
37
54
  next if @producer.params[item].nil?
38
55
  if @producer.params[item].instance_of?(Array)
@@ -41,22 +58,23 @@ EOT
41
58
  s << %Q[ <dc:#{item}>#{CGI.escapeHTML(@producer.params[item].to_s)}</dc:#{item}>\n]
42
59
  end
43
60
  end
44
-
61
+
45
62
  # ID
46
63
  if @producer.params["isbn"].nil?
47
64
  s << %Q[ <dc:identifier id="BookId">#{@producer.params["urnid"]}</dc:identifier>\n]
48
65
  else
49
66
  s << %Q[ <dc:identifier id="BookId" opf:scheme="ISBN">#{@producer.params["isbn"]}</dc:identifier>\n]
50
67
  end
51
-
52
- # creator
68
+
69
+ # creator (should be array)
53
70
  %w[aut a-adp a-ann a-arr a-art a-asn a-aqt a-aft a-aui a-ant a-bkp a-clb a-cmm a-dsr a-edt a-ill a-lyr a-mdc a-mus a-nrt a-oth a-pht a-prt a-red a-rev a-spn a-ths a-trc a-trl].each do |role|
54
71
  next if @producer.params[role].nil?
55
72
  @producer.params[role].each do |v|
56
73
  s << %Q[ <dc:creator opf:role="#{role.sub('a-', '')}">#{CGI.escapeHTML(v)}</dc:creator>\n]
57
74
  end
58
75
  end
59
- # contributor
76
+
77
+ # contributor (should be array)
60
78
  %w[adp ann arr art asn aqt aft aui ant bkp clb cmm dsr edt ill lyr mdc mus nrt oth pht prt red rev spn ths trc trl].each do |role|
61
79
  next if @producer.params[role].nil?
62
80
  @producer.params[role].each do |v|
@@ -66,56 +84,70 @@ EOT
66
84
  end
67
85
  end
68
86
  end
69
-
87
+
88
+ s
89
+ end
90
+
91
+ def opf_coverimage
92
+ s = ""
70
93
  if @producer.params["coverimage"]
94
+ file = nil
71
95
  @producer.contents.each do |item|
72
96
  if item.media =~ /\Aimage/ && item.file =~ /#{@producer.params["coverimage"]}\Z/
73
- s << %Q[ <meta name="cover" content="#{item.id}"/>\n]
97
+ s << %Q[ <meta name="cover" content="#{item.id}"/>\n]
98
+ file = item.file
74
99
  break
75
100
  end
76
101
  end
102
+ raise "coverimage #{@producer.params["coverimage"]} not found. Abort." if file.nil?
77
103
  end
78
-
79
- s << %Q[ </metadata>\n]
80
-
81
- # manifest
104
+ s
105
+ end
106
+
107
+ def opf_manifest
108
+ s = ""
82
109
  s << <<EOT
83
110
  <manifest>
84
111
  <item id="ncx" href="#{@producer.params["bookname"]}.ncx" media-type="application/x-dtbncx+xml"/>
85
112
  <item id="#{@producer.params["bookname"]}" href="#{@producer.params["cover"]}" media-type="application/xhtml+xml"/>
86
113
  EOT
87
114
 
88
- s << %Q[ <item id="toc" href="#{@producer.params["tocfile"]}" media-type="application/xhtml+xml"/>\n] unless @producer.params["mytoc"].nil?
89
-
115
+ s << %Q[ <item id="toc" href="#{@producer.params["bookname"]}-toc.#{@producer.params["htmlext"]}" media-type="application/xhtml+xml"/>\n] unless @producer.params["mytoc"].nil?
116
+
90
117
  @producer.contents.each do |item|
91
118
  next if item.file =~ /#/ # skip subgroup
92
119
  s << %Q[ <item id="#{item.id}" href="#{item.file}" media-type="#{item.media}"/>\n]
93
120
  end
94
121
  s << %Q[ </manifest>\n]
95
-
96
- # tocx
122
+ s
123
+ end
124
+
125
+ def opf_tocx
126
+ s = ""
97
127
  s << %Q[ <spine toc="ncx">\n]
98
128
  s << %Q[ <itemref idref="#{@producer.params["bookname"]}" linear="no"/>\n]
99
129
  s << %Q[ <itemref idref="toc" />\n] unless @producer.params["mytoc"].nil?
100
-
130
+
101
131
  @producer.contents.each do |item|
102
132
  next if item.media !~ /xhtml\+xml/ # skip non XHTML
103
133
  s << %Q[ <itemref idref="#{item.id}"/>\n] if item.notoc.nil?
104
134
  end
105
135
  s << %Q[ </spine>\n]
106
-
107
- # guide
136
+ s
137
+ end
138
+
139
+ def opf_guide
140
+ s = ""
108
141
  s << %Q[ <guide>\n]
109
142
  s << %Q[ <reference type="cover" title="#{@producer.res.v("covertitle")}" href="#{@producer.params["cover"]}"/>\n]
110
- s << %Q[ <reference type="title-page" title="#{@producer.res.v("titlepagetitle")}" href="#{@producer.params["titlepage"]}"/>\n] unless @producer.params["titlepage"].nil?
111
- s << %Q[ <reference type="toc" title="#{@producer.res.v("toctitle")}" href="#{@producer.params["tocfile"]}"/>\n] unless @producer.params["mytoc"].nil?
112
- s << %Q[ <reference type="colophon" title="#{@producer.res.v("colophontitle")}" href="colophon.#{@producer.params["htmlext"]}"/>\n] unless @producer.params["colophon"].nil? # FIXME: path
143
+ s << %Q[ <reference type="title-page" title="#{@producer.res.v("titlepagetitle")}" href="titlepage.#{@producer.params["htmlext"]}"/>\n] unless @producer.params["titlepage"].nil?
144
+ s << %Q[ <reference type="toc" title="#{@producer.res.v("toctitle")}" href="#{@producer.params["bookname"]}-toc.#{@producer.params["htmlext"]}"/>\n] unless @producer.params["mytoc"].nil?
145
+ s << %Q[ <reference type="colophon" title="#{@producer.res.v("colophontitle")}" href="colophon.#{@producer.params["htmlext"]}"/>\n] unless @producer.params["colophon"].nil?
113
146
  s << %Q[ </guide>\n]
114
- s << %Q[</package>\n]
115
- return s
147
+ s
116
148
  end
117
149
 
118
- # Return ncx content. +indentarray+ defines prefix string for each level.
150
+ # Return ncx content. +indentarray+ has prefix marks for each level.
119
151
  def ncx(indentarray)
120
152
  s = <<EOT
121
153
  <?xml version="1.0" encoding="UTF-8"?>
@@ -125,20 +157,41 @@ EOT
125
157
  <meta name="dtb:totalPageCount" content="0"/>
126
158
  <meta name="dtb:maxPageNumber" content="0"/>
127
159
  EOT
160
+ s << ncx_isbn
161
+
162
+ s << <<EOT
163
+ </head>
164
+ EOT
165
+ s << ncx_doctitle
166
+ s << ncx_navmap(indentarray)
167
+
168
+ s << <<EOT
169
+ </ncx>
170
+ EOT
171
+ s
172
+ end
173
+
174
+ def ncx_isbn
128
175
  if @producer.params["isbn"].nil?
129
- s << %Q[ <meta name="dtb:uid" content="#{@producer.params["urnid"]}"/>\n]
176
+ %Q[ <meta name="dtb:uid" content="#{@producer.params["urnid"]}"/>\n]
130
177
  else
131
- s << %Q[ <meta name="dtb:uid" content="#{@producer.params["isbn"]}"/>\n]
178
+ %Q[ <meta name="dtb:uid" content="#{@producer.params["isbn"]}"/>\n]
132
179
  end
133
-
134
- s << <<EOT
135
- </head>
180
+ end
181
+
182
+ def ncx_doctitle
183
+ <<EOT
136
184
  <docTitle>
137
185
  <text>#{CGI.escapeHTML(@producer.params["title"])}</text>
138
186
  </docTitle>
139
187
  <docAuthor>
140
188
  <text>#{@producer.params["aut"].nil? ? "" : CGI.escapeHTML(@producer.params["aut"].join(", "))}</text>
141
189
  </docAuthor>
190
+ EOT
191
+ end
192
+
193
+ def ncx_navmap(indentarray)
194
+ s = <<EOT
142
195
  <navMap>
143
196
  <navPoint id="top" playOrder="1">
144
197
  <navLabel>
@@ -149,19 +202,19 @@ EOT
149
202
  EOT
150
203
 
151
204
  nav_count = 2
152
-
205
+
153
206
  unless @producer.params["mytoc"].nil?
154
207
  s << <<EOT
155
208
  <navPoint id="toc" playOrder="#{nav_count}">
156
209
  <navLabel>
157
210
  <text>#{@producer.res.v("toctitle")}</text>
158
211
  </navLabel>
159
- <content src="#{@producer.params["tocfile"]}"/>
212
+ <content src="#{@producer.params["bookname"]}-toc.#{@producer.params["htmlext"]}"/>
160
213
  </navPoint>
161
214
  EOT
162
215
  nav_count += 1
163
216
  end
164
-
217
+
165
218
  @producer.contents.each do |item|
166
219
  next if item.title.nil?
167
220
  indent = indentarray.nil? ? [""] : indentarray
@@ -177,14 +230,13 @@ EOT
177
230
  EOT
178
231
  nav_count += 1
179
232
  end
180
-
233
+
181
234
  s << <<EOT
182
235
  </navMap>
183
- </ncx>
184
236
  EOT
185
- return s
237
+ s
186
238
  end
187
-
239
+
188
240
  # Return container content.
189
241
  def container
190
242
  s = <<EOT
@@ -195,9 +247,9 @@ EOT
195
247
  </rootfiles>
196
248
  </container>
197
249
  EOT
198
- return s
250
+ s
199
251
  end
200
-
252
+
201
253
  # Return cover content.
202
254
  def cover
203
255
  s = common_header
@@ -224,13 +276,13 @@ EOT
224
276
  <img src="#{file}" alt="#{CGI.escapeHTML(@producer.params["title"])}" class="max"/>
225
277
  </div>
226
278
  EOT
227
- end
228
-
279
+ end
280
+
229
281
  s << <<EOT
230
282
  </body>
231
283
  </html>
232
284
  EOT
233
- return s
285
+ s
234
286
  end
235
287
 
236
288
  # Return title (copying) content.
@@ -249,7 +301,7 @@ EOT
249
301
  <br />
250
302
  <br />
251
303
  </p>
252
- <h2 class="tp-author">#{CGI.escapeHTML(@producer.params["aut"])}</h2>
304
+ <h2 class="tp-author">#{CGI.escapeHTML(@producer.params["aut"].join(", "))}</h2>
253
305
  EOT
254
306
  end
255
307
 
@@ -261,7 +313,7 @@ EOT
261
313
  <br />
262
314
  <br />
263
315
  </p>
264
- <h3 class="tp-publisher">#{CGI.escapeHTML(@producer.params["prt"])}</h3>
316
+ <h3 class="tp-publisher">#{CGI.escapeHTML(@producer.params["prt"].join(", "))}</h3>
265
317
  EOT
266
318
  end
267
319
 
@@ -269,7 +321,8 @@ EOT
269
321
  </body>
270
322
  </html>
271
323
  EOT
272
- return s
324
+
325
+ s
273
326
  end
274
327
 
275
328
  # Return colophon content.
@@ -280,26 +333,65 @@ EOT
280
333
  </head>
281
334
  <body>
282
335
  <div class="colophon">
336
+ EOT
337
+
338
+ if @producer.params["subtitle"].nil?
339
+ s << <<EOT
283
340
  <p class="title">#{CGI.escapeHTML(@producer.params["title"])}</p>
284
341
  EOT
342
+ else
343
+ s << <<EOT
344
+ <p class="title">#{CGI.escapeHTML(@producer.params["title"])}<br /><span class="subtitle">#{CGI.escapeHTML(@producer.params["subtitle"])}</span></p>
345
+ EOT
346
+ end
285
347
 
286
- if @producer.params["pubhistory"]
287
- s << %Q[ <div class="pubhistory">\n <p>#{@producer.params["pubhistory"].gsub(/\n/, "<br />")}</p>\n </div>\n] # FIXME: should be array?
348
+ if @producer.params["date"] || @producer.params["history"]
349
+ s << %Q[ <div class="pubhistory">\n]
350
+ if @producer.params["history"]
351
+ @producer.params["history"].each_with_index do |items, edit|
352
+ items.each_with_index do |item, rev|
353
+ editstr = (edit == 0) ? "初版" : "第#{edit + 1}版" # FIXME:i18n
354
+ revstr = "第#{rev + 1}刷"
355
+ s << %Q[ <p>#{date_to_s(item)} #{editstr}#{revstr} 発行</p>\n] # FIXME:i18n
356
+ end
357
+ end
358
+ else
359
+ s << %Q[ <p>#{date_to_s(@producer.params["date"])} 発行</p>\n] #FIXME:i18n
360
+ end
361
+ s << %Q[ </div>\n]
288
362
  end
289
-
363
+
290
364
  s << %Q[ <table class="colophon">\n]
291
- s << %Q[ <tr><th>#{@producer.res.v("c-aut")}</th><td>#{CGI.escapeHTML(@producer.params["aut"])}</td></tr>\n] if @producer.params["aut"]
292
- s << %Q[ <tr><th>#{@producer.res.v("c-dsr")}</th><td>#{CGI.escapeHTML(@producer.params["dsr"])}</td></tr>\n] if @producer.params["dsr"]
293
- s << %Q[ <tr><th>#{@producer.res.v("c-ill")}</th><td>#{CGI.escapeHTML(@producer.params["ill"])}</td></tr>\n] if @producer.params["ill"]
294
- s << %Q[ <tr><th>#{@producer.res.v("c-edt")}</th><td>#{CGI.escapeHTML(@producer.params["edt"])}</td></tr>\n] if @producer.params["edt"]
295
- s << %Q[ <tr><th>#{@producer.res.v("c-prt")}</th><td>#{CGI.escapeHTML(@producer.params["prt"])}</td></tr>\n] if @producer.params["prt"]
365
+ s << %Q[ <tr><th>#{@producer.res.v("c-aut")}</th><td>#{CGI.escapeHTML(@producer.params["aut"].join(", "))}</td></tr>\n] unless @producer.params["aut"].nil?
366
+ s << %Q[ <tr><th>#{@producer.res.v("c-csl")}</th><td>#{CGI.escapeHTML(@producer.params["csl"].join(", "))}</td></tr>\n] unless @producer.params["csl"].nil?
367
+ s << %Q[ <tr><th>#{@producer.res.v("c-trl")}</th><td>#{CGI.escapeHTML(@producer.params["trl"].join(", "))}</td></tr>\n] unless @producer.params["trl"].nil?
368
+ s << %Q[ <tr><th>#{@producer.res.v("c-dsr")}</th><td>#{CGI.escapeHTML(@producer.params["dsr"].join(", "))}</td></tr>\n] unless @producer.params["dsr"].nil?
369
+ s << %Q[ <tr><th>#{@producer.res.v("c-ill")}</th><td>#{CGI.escapeHTML(@producer.params["ill"].join(", "))}</td></tr>\n] unless @producer.params["ill"].nil?
370
+ s << %Q[ <tr><th>#{@producer.res.v("c-edt")}</th><td>#{CGI.escapeHTML(@producer.params["edt"].join(", "))}</td></tr>\n] unless @producer.params["edt"].nil?
371
+ s << %Q[ <tr><th>#{@producer.res.v("c-prt")}</th><td>#{CGI.escapeHTML(@producer.params["prt"].join(", "))}</td></tr>\n] unless @producer.params["prt"].nil?
372
+ s << %Q[ <tr><th>#{@producer.res.v("c-pht")}</th><td>#{CGI.escapeHTML(@producer.params["pht"].join(", "))}</td></tr>\n] unless @producer.params["pht"].nil?
373
+ if @producer.params["isbn"].to_s =~ /\A\d{10}\Z/ || @producer.params["isbn"].to_s =~ /\A\d{13}\Z/
374
+ isbn = nil
375
+ str = @producer.params["isbn"].to_s
376
+ if str.size == 10
377
+ isbn = "#{str[0..0]}-#{str[1..5]}-#{str[6..8]}-#{str[9..9]}"
378
+ else
379
+ isbn = "#{str[0..2]}-#{str[3..3]}-#{str[4..8]}-#{str[9..11]}-#{str[12..12]}"
380
+ end
381
+ s << %Q[ <tr><th>ISBN</th><td>#{isbn}</td></tr>\n]
382
+ end
296
383
  s << <<EOT
297
384
  </table>
298
385
  </div>
299
386
  </body>
300
387
  </html>
301
388
  EOT
302
- return s
389
+ s
390
+ end
391
+
392
+ def date_to_s(date)
393
+ ymd = date.to_s.split('-')
394
+ "#{ymd[0]}年#{ymd[1].sub(/\A0/, '')}月#{ymd[2].sub(/\A0/, '')}日" # FIXME:i18n
303
395
  end
304
396
 
305
397
  # Return own toc content.
@@ -310,68 +402,109 @@ EOT
310
402
  </head>
311
403
  <body>
312
404
  <h1 class="toc-title">#{@producer.res.v("toctitle")}</h1>
313
- <ul class="toc-h1">
314
405
  EOT
315
406
 
316
- # FIXME: indent
317
- current = 1
318
- init_item = true
407
+ if @producer.params["flattoc"].nil?
408
+ s << hierarchy_ncx("ul")
409
+ else
410
+ s << flat_ncx("ul", @producer.params["flattocindent"])
411
+ end
412
+
413
+ s << <<EOT
414
+ </body>
415
+ </html>
416
+ EOT
417
+ s
418
+ end
419
+
420
+ def hierarchy_ncx(type)
421
+ require 'rexml/document'
422
+ level = 1
423
+ find_jump = nil
424
+
425
+ # check part existance
426
+ @producer.contents.each do |item|
427
+ if item.notoc.nil? && item.level == 0
428
+ level = 0
429
+ end
430
+ end
431
+
432
+ doc = REXML::Document.new(%Q[<#{type} class="toc-h#{level}"><li /></#{type}>])
433
+
434
+ e = doc.root.elements[1] # first <li/>
319
435
  @producer.contents.each do |item|
320
436
  next if !item.notoc.nil? || item.level.nil? || item.file.nil? || item.title.nil? || item.level > @producer.params["toclevel"].to_i
321
- if item.level > current
322
- s << %Q[\n<ul class="toc-h#{item.level}">\n]
323
- current = item.level
324
- elsif item.level < current
325
- (current - 1).downto(item.level) do |n|
326
- s << %Q[</li>\n</ul>\n]
437
+
438
+ if item.level == level
439
+ e2 = e.parent.add_element("li")
440
+ e = e2
441
+ elsif item.level > level
442
+ find_jump = true if (item.level - level) > 1
443
+ # deeper
444
+ (level + 1).upto(item.level) do |n|
445
+ e2 = e.add_element(type, {"class" => "toc-h#{n}"})
446
+ e3 = e2.add_element("li")
447
+ e = e3
327
448
  end
328
- s << %Q[</li>\n]
329
- current = item.level
330
- elsif init_item
331
- # noop
332
- else
333
- s << %Q[</li>\n]
449
+ level = item.level
450
+ elsif item.level < level
451
+ # shallower
452
+ (level - 1).downto(item.level) do |n|
453
+ e = e.parent.parent
454
+ end
455
+ e2 = e.parent.add_element("li")
456
+ e = e2
457
+ level = item.level
334
458
  end
335
- s << %Q[<li><a href="#{item.file}">#{item.title}</a>]
336
- init_item = false
337
- end
338
-
339
- (current - 1).downto(1) do |n|
340
- s << %Q[</li>\n</ul>\n]
459
+ e2 = e.add_element("a", {"href" => item.file})
460
+ e2.add_text(REXML::Text.new(item.title, true))
341
461
  end
342
- if !init_item
343
- s << %Q[</li>\n]
462
+
463
+ warn "found level jumping in table of contents. consider to use 'flattoc: true' for strict ePUB validator." unless find_jump.nil?
464
+
465
+ doc.to_s.gsub("<li/>", "").gsub("</li>", "</li>\n").gsub("href='", "href=\"").gsub(" class='", " class=\"").gsub("'>", "\">").gsub("<#{type} ", "\n" + '\&') # ugly
466
+ end
467
+
468
+ def flat_ncx(type, indent=nil)
469
+ s = %Q[<#{type} class="toc-h1">\n]
470
+ @producer.contents.each do |item|
471
+ next if !item.notoc.nil? || item.level.nil? || item.file.nil? || item.title.nil? || item.level > @producer.params["toclevel"].to_i
472
+ is = indent == true ? " " * item.level : ""
473
+ s << %Q[<li><a href="#{item.file}">#{is}#{item.title}</a></li>\n]
344
474
  end
345
- s << <<EOT
346
- </ul>
347
- </body>
348
- </html>
349
- EOT
350
- return s
475
+ s << %Q[</#{type}>\n]
476
+
477
+ s
351
478
  end
352
479
 
353
480
  # Produce EPUB file +epubfile+.
354
481
  # +basedir+ points the directory has contents.
355
482
  # +tmpdir+ defines temporary directory.
356
483
  def produce(epubfile, basedir, tmpdir)
484
+ produce_write_common(basedir, tmpdir)
485
+
486
+ File.open("#{tmpdir}/OEBPS/#{@producer.params["bookname"]}.ncx", "w") {|f| @producer.ncx(f, @producer.params["ncxindent"]) }
487
+ File.open("#{tmpdir}/OEBPS/#{@producer.params["bookname"]}-toc.#{@producer.params["htmlext"]}", "w") {|f| @producer.mytoc(f) } unless @producer.params["mytoc"].nil?
488
+
489
+ @producer.call_hook(@producer.params["hook_prepack"], tmpdir)
490
+ export_zip(tmpdir, epubfile)
491
+ end
492
+
493
+ def produce_write_common(basedir, tmpdir)
357
494
  File.open("#{tmpdir}/mimetype", "w") {|f| @producer.mimetype(f) }
358
-
495
+
359
496
  Dir.mkdir("#{tmpdir}/META-INF") unless File.exist?("#{tmpdir}/META-INF")
360
497
  File.open("#{tmpdir}/META-INF/container.xml", "w") {|f| @producer.container(f) }
361
-
498
+
362
499
  Dir.mkdir("#{tmpdir}/OEBPS") unless File.exist?("#{tmpdir}/OEBPS")
363
500
  File.open("#{tmpdir}/OEBPS/#{@producer.params["bookname"]}.opf", "w") {|f| @producer.opf(f) }
364
- File.open("#{tmpdir}/OEBPS/#{@producer.params["bookname"]}.ncx", "w") {|f| @producer.ncx(f, @producer.params["ncxindent"]) }
365
- File.open("#{tmpdir}/OEBPS/#{@producer.params["tocfile"]}", "w") {|f| @producer.mytoc(f) } unless @producer.params["mytoc"].nil?
366
-
501
+
367
502
  if File.exist?("#{basedir}/#{@producer.params["cover"]}")
368
503
  FileUtils.cp("#{basedir}/#{@producer.params["cover"]}", "#{tmpdir}/OEBPS")
369
504
  else
370
505
  File.open("#{tmpdir}/OEBPS/#{@producer.params["cover"]}", "w") {|f| @producer.cover(f) }
371
506
  end
372
-
373
- # FIXME:colophon and titlepage should be included in @producer.contents.
374
-
507
+
375
508
  @producer.contents.each do |item|
376
509
  next if item.file =~ /#/ # skip subgroup
377
510
  fname = "#{basedir}/#{item.file}"
@@ -379,19 +512,11 @@ EOT
379
512
  FileUtils.mkdir_p(File.dirname("#{tmpdir}/OEBPS/#{item.file}")) unless File.exist?(File.dirname("#{tmpdir}/OEBPS/#{item.file}"))
380
513
  FileUtils.cp(fname, "#{tmpdir}/OEBPS/#{item.file}")
381
514
  end
515
+ end
382
516
 
383
- fork {
384
- Dir.chdir(tmpdir) {|d|
385
- exec("zip", "-0X", "#{epubfile}", "mimetype")
386
- }
387
- }
388
- Process.waitall
389
- fork {
390
- Dir.chdir(tmpdir) {|d|
391
- exec("zip", "-Xr9D", "#{epubfile}", "META-INF", "OEBPS")
392
- }
393
- }
394
- Process.waitall
517
+ def export_zip(tmpdir, epubfile)
518
+ Dir.chdir(tmpdir) {|d| system("#{@producer.params["zip_stage1"]} #{epubfile} mimetype") }
519
+ Dir.chdir(tmpdir) {|d| system("#{@producer.params["zip_stage2"]} #{epubfile} META-INF OEBPS") }
395
520
  end
396
521
 
397
522
  private
@@ -411,8 +536,7 @@ EOT
411
536
  @producer.params["stylesheet"].each do |file|
412
537
  s << %Q[ <link rel="stylesheet" type="text/css" href="#{file}"/>\n]
413
538
  end
414
- return s
539
+ s
415
540
  end
416
541
  end
417
-
418
542
  end