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.
- checksums.yaml +7 -0
- data/.travis.yml +1 -0
- data/ChangeLog +100 -0
- data/README.rdoc +11 -12
- data/Rakefile +6 -2
- data/bin/review-check +1 -1
- data/bin/review-compile +13 -4
- data/bin/review-epubmaker +172 -24
- data/bin/review-epubmaker-ng +8 -161
- data/bin/review-index +1 -1
- data/bin/review-init +17 -5
- data/bin/review-pdfmaker +40 -19
- data/bin/review-preproc +1 -1
- data/bin/review-validate +2 -2
- data/bin/review-vol +1 -1
- data/debian/control +2 -2
- data/doc/format.rdoc +23 -6
- data/doc/format_idg.rdoc +3 -3
- data/doc/libepubmaker/config.yaml +163 -0
- data/doc/quickstart.rdoc +27 -27
- data/doc/sample.yaml +10 -5
- data/lib/epubmaker.rb +2 -5
- data/lib/epubmaker/content.rb +9 -6
- data/lib/epubmaker/epubv2.rb +233 -109
- data/lib/epubmaker/epubv3.rb +83 -119
- data/lib/epubmaker/producer.rb +50 -20
- data/lib/epubmaker/resource.rb +22 -8
- data/lib/review/book/base.rb +1 -0
- data/lib/review/book/chapter.rb +2 -2
- data/lib/review/book/compilable.rb +1 -1
- data/lib/review/book/index.rb +33 -27
- data/lib/review/book/parameters.rb +3 -2
- data/lib/review/book/part.rb +1 -1
- data/lib/review/builder.rb +10 -42
- data/lib/review/compiler.rb +1 -1
- data/lib/review/configure.rb +3 -3
- data/lib/review/epubmaker.rb +428 -0
- data/lib/review/htmlbuilder.rb +45 -95
- data/lib/review/htmlutils.rb +2 -0
- data/lib/review/i18n.yaml +25 -0
- data/lib/review/idgxmlbuilder.rb +11 -9
- data/lib/review/inaobuilder.rb +1 -1
- data/lib/review/latexbuilder.rb +7 -6
- data/lib/review/latexutils.rb +6 -0
- data/lib/review/makerhelper.rb +4 -2
- data/lib/review/markdownbuilder.rb +8 -0
- data/lib/review/sec_counter.rb +71 -0
- data/lib/review/topbuilder.rb +0 -1
- data/lib/review/version.rb +2 -2
- data/review.gemspec +4 -4
- data/test/sample-book/README.md +2 -2
- data/test/sample-book/src/Rakefile +2 -2
- data/test/sample-book/src/config.yml +4 -4
- data/test/sample-book/src/images/cover.jpg +0 -0
- data/test/sample-book/src/sty/{samplemacro.sty → reviewmacro.sty} +1 -1
- data/test/test_book_parameter.rb +1 -1
- data/test/test_epubmaker.rb +77 -15
- data/test/test_epubmaker_cmd.rb +11 -7
- data/test/test_helper.rb +7 -0
- data/test/test_htmlbuilder.rb +39 -6
- data/test/test_idgxmlbuilder.rb +14 -2
- data/test/test_inaobuilder.rb +2 -1
- data/test/test_latexbuilder.rb +23 -2
- data/test/test_makerhelper.rb +19 -3
- data/test/test_markdownbuilder.rb +35 -0
- data/test/test_pdfmaker_cmd.rb +11 -7
- data/test/test_topbuilder.rb +36 -2
- metadata +18 -18
- data/VERSION +0 -1
- data/doc/libepubmaker/sample.yaml +0 -90
data/lib/epubmaker/resource.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# = resource.rb -- Message resources for EPUBMaker.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2010 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
|
@@ -21,44 +21,58 @@ module EPUBMaker
|
|
21
21
|
rescue
|
22
22
|
@hash = __send__ :en
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
@hash.each_pair do |k, v|
|
26
26
|
@hash[k] = params[k] unless params[k].nil?
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
# Return message translation for +key+.
|
31
31
|
def v(key)
|
32
32
|
return @hash[key]
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
private
|
36
|
-
# English
|
36
|
+
# English message catalog
|
37
37
|
def en
|
38
38
|
{
|
39
39
|
"toctitle" => "Table of Contents",
|
40
40
|
"covertitle" => "Cover",
|
41
41
|
"titlepagetitle" => "Title Page",
|
42
|
+
"originaltitle" => "Title Page of Original",
|
43
|
+
"credittitle" => "Credit",
|
42
44
|
"colophontitle" => "Colophon",
|
45
|
+
"profiletitle" => "Profile",
|
46
|
+
"advtitle" => "Advertisement",
|
43
47
|
"c-aut" => "Author",
|
48
|
+
"c-csl" => "Consultant",
|
44
49
|
"c-dsr" => "Designer",
|
45
50
|
"c-ill" => "Illustrator",
|
46
51
|
"c-edt" => "Editor",
|
52
|
+
"c-pht" => "Director of Photography",
|
53
|
+
"c-trl" => "Translator",
|
47
54
|
"c-prt" => "Publisher",
|
48
55
|
}
|
49
56
|
end
|
50
|
-
|
51
|
-
# Japanese
|
57
|
+
|
58
|
+
# Japanese message catalog
|
52
59
|
def ja
|
53
60
|
{
|
54
61
|
"toctitle" => "目次",
|
55
62
|
"covertitle" => "表紙",
|
56
|
-
"titlepagetitle" => "
|
63
|
+
"titlepagetitle" => "大扉",
|
64
|
+
"originaltitle" => "原書大扉",
|
65
|
+
"credittitle" => "クレジット",
|
57
66
|
"colophontitle" => "奥付",
|
67
|
+
"advtitle" => "広告",
|
68
|
+
"profiletitle" => "著者紹介",
|
58
69
|
"c-aut" => "著 者",
|
70
|
+
"c-csl" => "監 修",
|
59
71
|
"c-dsr" => "デザイン",
|
60
72
|
"c-ill" => "イラスト",
|
61
73
|
"c-edt" => "編 集",
|
74
|
+
"c-pht" => "撮 影",
|
75
|
+
"c-trl" => "翻 訳",
|
62
76
|
"c-prt" => "発行所",
|
63
77
|
}
|
64
78
|
end
|
data/lib/review/book/base.rb
CHANGED
data/lib/review/book/chapter.rb
CHANGED
@@ -22,8 +22,8 @@ module ReVIEW
|
|
22
22
|
book = (books[File.expand_path(basedir)] ||= Book.load(basedir))
|
23
23
|
begin
|
24
24
|
book.chapter(File.basename(path, '.*'))
|
25
|
-
rescue KeyError
|
26
|
-
raise FileNotFound, "
|
25
|
+
rescue KeyError
|
26
|
+
raise FileNotFound, "No such chapter in your book. Check if the catalog files contain the chapter. : #{path}"
|
27
27
|
end
|
28
28
|
}
|
29
29
|
end
|
data/lib/review/book/index.rb
CHANGED
@@ -132,6 +132,8 @@ module ReVIEW
|
|
132
132
|
|
133
133
|
class ImageIndex < Index
|
134
134
|
class Item
|
135
|
+
@@entries = nil
|
136
|
+
|
135
137
|
def initialize(id, number)
|
136
138
|
@id = id
|
137
139
|
@number = number
|
@@ -167,39 +169,43 @@ module ReVIEW
|
|
167
169
|
@chapid = chapid
|
168
170
|
@basedir = basedir
|
169
171
|
@types = types
|
172
|
+
|
173
|
+
@@entries ||= get_entries
|
174
|
+
end
|
175
|
+
|
176
|
+
def get_entries
|
177
|
+
Dir.glob(File.join(@basedir, "**/*.*"))
|
170
178
|
end
|
171
179
|
|
172
180
|
# internal use only
|
173
181
|
def find_pathes(id)
|
174
|
-
|
175
|
-
re = /\A#{id}(?i:#{@types.join('|')})\z/x
|
176
|
-
entries().select {|ent| re =~ ent }\
|
177
|
-
.sort_by {|ent| @types.index(File.extname(ent).downcase) }\
|
178
|
-
.map {|ent| "#{@basedir}/#{@chapid}/#{ent}" }
|
179
|
-
elsif ReVIEW.book.param["singledirmode"]
|
180
|
-
re = /\A#{id}(?i:#{@types.join('|')})\z/x
|
181
|
-
entries().select {|ent| re =~ ent }\
|
182
|
-
.sort_by {|ent| @types.index(File.extname(ent).downcase) }\
|
183
|
-
.map {|ent| "#{@basedir}/#{ent}" }
|
184
|
-
else
|
185
|
-
re = /\A#{@chapid.gsub('+', '\\\+').gsub('-', '\\\-')}-#{id}(?i:#{@types.join('|')})\z/x
|
186
|
-
entries().select {|ent| re =~ ent }\
|
187
|
-
.sort_by {|ent| @types.index(File.extname(ent).downcase) }\
|
188
|
-
.map {|ent| "#{@basedir}/#{ent}" }
|
189
|
-
end
|
190
|
-
end
|
182
|
+
pathes = []
|
191
183
|
|
192
|
-
|
184
|
+
# 1. <basedir>/<builder>/<chapid>/<id>.<ext>
|
185
|
+
target = "#{@basedir}/#{ReVIEW.book.param['builder']}/#{@chapid}/#{id}"
|
186
|
+
@types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
|
193
187
|
|
194
|
-
|
195
|
-
#
|
196
|
-
if
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
188
|
+
# 2. <basedir>/<builder>/<chapid>-<id>.<ext>
|
189
|
+
target = "#{@basedir}/#{ReVIEW.book.param['builder']}/#{@chapid}-#{id}"
|
190
|
+
@types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
|
191
|
+
|
192
|
+
# 3. <basedir>/<builder>/<id>.<ext>
|
193
|
+
target = "#{@basedir}/#{ReVIEW.book.param['builder']}/#{id}"
|
194
|
+
@types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
|
195
|
+
|
196
|
+
# 4. <basedir>/<chapid>/<id>.<ext>
|
197
|
+
target = "#{@basedir}/#{@chapid}/#{id}"
|
198
|
+
@types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
|
199
|
+
|
200
|
+
# 5. <basedir>/<chapid>-<id>.<ext>
|
201
|
+
target = "#{@basedir}/#{@chapid}-#{id}"
|
202
|
+
@types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
|
203
|
+
|
204
|
+
# 6. <basedir>/<id>.<ext>
|
205
|
+
target = "#{@basedir}/#{id}"
|
206
|
+
@types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
|
207
|
+
|
208
|
+
return pathes
|
203
209
|
end
|
204
210
|
end
|
205
211
|
|
@@ -45,7 +45,8 @@ module ReVIEW
|
|
45
45
|
PageMetric.new(const_get_safe(mod, :LINES_PER_PAGE_list) || 46,
|
46
46
|
const_get_safe(mod, :COLUMNS_list) || 80,
|
47
47
|
const_get_safe(mod, :LINES_PER_PAGE_text) || 30,
|
48
|
-
const_get_safe(mod, :COLUMNS_text) || 74
|
48
|
+
const_get_safe(mod, :COLUMNS_text) || 74, # 37zw
|
49
|
+
const_get_safe(mod, :PAGE_PER_KBYTE) || 1) # 37zw
|
49
50
|
end
|
50
51
|
|
51
52
|
def Parameters.const_get_safe(mod, name)
|
@@ -89,7 +90,7 @@ module ReVIEW
|
|
89
90
|
path_param :postdef_file
|
90
91
|
attr_reader :ext
|
91
92
|
path_param :image_dir
|
92
|
-
|
93
|
+
attr_accessor :image_types
|
93
94
|
attr_reader :page_metric
|
94
95
|
|
95
96
|
end
|
data/lib/review/book/part.rb
CHANGED
data/lib/review/builder.rb
CHANGED
@@ -10,6 +10,7 @@
|
|
10
10
|
require 'review/book/index'
|
11
11
|
require 'review/exception'
|
12
12
|
require 'review/textutils'
|
13
|
+
require 'review/compiler'
|
13
14
|
require 'stringio'
|
14
15
|
require 'cgi'
|
15
16
|
|
@@ -60,9 +61,9 @@ module ReVIEW
|
|
60
61
|
alias :raw_result result
|
61
62
|
|
62
63
|
def print(*s)
|
63
|
-
@output.print
|
64
|
+
@output.print(*s.map{|i|
|
64
65
|
convert_outencoding(i, ReVIEW.book.param["outencoding"])
|
65
|
-
}
|
66
|
+
})
|
66
67
|
end
|
67
68
|
|
68
69
|
def puts(*s)
|
@@ -119,7 +120,7 @@ module ReVIEW
|
|
119
120
|
|
120
121
|
begin
|
121
122
|
table_header id, caption unless caption.nil?
|
122
|
-
rescue KeyError
|
123
|
+
rescue KeyError
|
123
124
|
error "no such table: #{id}"
|
124
125
|
end
|
125
126
|
return if rows.empty?
|
@@ -171,7 +172,7 @@ module ReVIEW
|
|
171
172
|
end
|
172
173
|
|
173
174
|
def inline_chapref(id)
|
174
|
-
@chapter.env.chapter_index.display_string(id)
|
175
|
+
compile_inline @chapter.env.chapter_index.display_string(id)
|
175
176
|
rescue KeyError
|
176
177
|
error "unknown chapter: #{id}"
|
177
178
|
nofunc_text("[UnknownChapter:#{id}]")
|
@@ -276,35 +277,6 @@ module ReVIEW
|
|
276
277
|
end
|
277
278
|
end
|
278
279
|
|
279
|
-
def find_pathes(id)
|
280
|
-
if ReVIEW.book.param["subdirmode"]
|
281
|
-
re = /\A#{id}(?i:#{@chapter.name.join('|')})\z/x
|
282
|
-
entries().select {|ent| re =~ ent }\
|
283
|
-
.sort_by {|ent| @book.image_types.index(File.extname(ent).downcase) }\
|
284
|
-
.map {|ent| "#{@book.basedir}/#{@chapter.name}/#{ent}" }
|
285
|
-
elsif ReVIEW.book.param["singledirmode"]
|
286
|
-
re = /\A#{id}(?i:#{@chapter.name.join('|')})\z/x
|
287
|
-
entries().select {|ent| re =~ ent }\
|
288
|
-
.sort_by {|ent| @book.image_types.index(File.extname(ent).downcase) }\
|
289
|
-
.map {|ent| "#{@book.basedir}/#{ent}" }
|
290
|
-
else
|
291
|
-
re = /\A#{@chapter.name}-#{id}(?i:#{@book.image_types.join('|')})\z/x
|
292
|
-
entries().select {|ent| re =~ ent }\
|
293
|
-
.sort_by {|ent| @book.image_types.index(File.extname(ent).downcase) }\
|
294
|
-
.map {|ent| "#{@book.basedir}/#{ent}" }
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
def entries
|
299
|
-
if ReVIEW.book.param["subdirmode"]
|
300
|
-
@entries ||= Dir.entries(File.join(@book.basedir + @book.image_dir, @chapter.name))
|
301
|
-
else
|
302
|
-
@entries ||= Dir.entries(@book.basedir + @book.image_dir)
|
303
|
-
end
|
304
|
-
rescue Errno::ENOENT
|
305
|
-
@entries = []
|
306
|
-
end
|
307
|
-
|
308
280
|
def warn(msg)
|
309
281
|
$stderr.puts "#{@location}: warning: #{msg}"
|
310
282
|
end
|
@@ -368,14 +340,10 @@ module ReVIEW
|
|
368
340
|
end
|
369
341
|
|
370
342
|
def graph(lines, id, command, caption = nil)
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
file = "#{id}.#{image_ext}"
|
376
|
-
elsif ReVIEW.book.param["singledirmode"]
|
377
|
-
file = "#{id}.#{image_ext}"
|
378
|
-
end
|
343
|
+
c = self.class.to_s.gsub(/ReVIEW::/, '').gsub(/Builder/, '').downcase
|
344
|
+
dir = File.join(@book.basedir, @book.image_dir, c)
|
345
|
+
Dir.mkdir(dir) unless File.exist?(dir)
|
346
|
+
file = "#{id}.#{image_ext}"
|
379
347
|
file_path = File.join(dir, file)
|
380
348
|
|
381
349
|
line = CGI.unescapeHTML(lines.join("\n"))
|
@@ -392,7 +360,7 @@ module ReVIEW
|
|
392
360
|
warn cmd
|
393
361
|
system cmd
|
394
362
|
|
395
|
-
image(lines, id, caption)
|
363
|
+
image(lines, id, caption ||= "")
|
396
364
|
end
|
397
365
|
|
398
366
|
def image_ext
|
data/lib/review/compiler.rb
CHANGED
@@ -412,7 +412,7 @@ module ReVIEW
|
|
412
412
|
|
413
413
|
def compile_paragraph(f)
|
414
414
|
buf = []
|
415
|
-
f.until_match(%r<\A//|\A
|
415
|
+
f.until_match(%r<\A//|\A\#@>) do |line|
|
416
416
|
break if line.strip.empty?
|
417
417
|
buf.push text(line.sub(/^(\t+)\s*/) {|m| "<!ESCAPETAB!>" * m.size}.strip.gsub(/<!ESCAPETAB!>/, "\t"))
|
418
418
|
end
|
data/lib/review/configure.rb
CHANGED
@@ -4,8 +4,8 @@ module ReVIEW
|
|
4
4
|
def self.values
|
5
5
|
{ # These parameters can be overridden by YAML file.
|
6
6
|
"bookname"=> "example", # it defines epub file name also
|
7
|
-
"booktitle" => "
|
8
|
-
"title" =>
|
7
|
+
"booktitle" => "Re:VIEW EPUBサンプル",
|
8
|
+
"title" => nil,
|
9
9
|
"aut" => nil, # author
|
10
10
|
"prt" => nil, # printer(publisher)
|
11
11
|
"asn" => nil, # associated name
|
@@ -30,7 +30,7 @@ module ReVIEW
|
|
30
30
|
"epubversion" => 2,
|
31
31
|
"titlepage" => true, # Use title page
|
32
32
|
"toc" => true, # Use table of contents
|
33
|
-
"colophon" =>
|
33
|
+
"colophon" => nil, # Use colophon
|
34
34
|
"debug" => nil, # debug flag
|
35
35
|
}
|
36
36
|
end
|
@@ -0,0 +1,428 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Copyright (c) 2010-2014 Kenshi Muto and Masayoshi Takahashi
|
4
|
+
#
|
5
|
+
# This program is free software.
|
6
|
+
# You can distribute or modify this program under the terms of
|
7
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
8
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
9
|
+
#
|
10
|
+
require 'review'
|
11
|
+
require 'rexml/document'
|
12
|
+
require 'rexml/streamlistener'
|
13
|
+
require 'epubmaker'
|
14
|
+
|
15
|
+
module ReVIEW
|
16
|
+
class EPUBMaker
|
17
|
+
include ::EPUBMaker
|
18
|
+
include REXML
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@epub = nil
|
22
|
+
@tochtmltxt = "toc-html.txt"
|
23
|
+
end
|
24
|
+
|
25
|
+
def log(s)
|
26
|
+
puts s unless @params["debug"].nil?
|
27
|
+
end
|
28
|
+
|
29
|
+
def load_yaml(yamlfile)
|
30
|
+
@params = ReVIEW::Configure.values.merge(YAML.load_file(yamlfile)) # FIXME:設定がRe:VIEW側とepubmaker/producer.rb側の2つに分かれて面倒
|
31
|
+
@epub = Producer.new(@params)
|
32
|
+
@epub.load(yamlfile)
|
33
|
+
@params = @epub.params
|
34
|
+
end
|
35
|
+
|
36
|
+
def produce(yamlfile, bookname=nil)
|
37
|
+
load_yaml(yamlfile)
|
38
|
+
bookname = @params["bookname"] if bookname.nil?
|
39
|
+
log("Loaded yaml file (#{yamlfile}). I will produce #{bookname}.epub.")
|
40
|
+
|
41
|
+
File.unlink("#{bookname}.epub") if File.exist?("#{bookname}.epub")
|
42
|
+
FileUtils.rm_rf(bookname) if @params["debug"] && File.exist?(bookname)
|
43
|
+
|
44
|
+
Dir.mktmpdir(bookname, Dir.pwd) do |basetmpdir|
|
45
|
+
log("Created first temporary directory as #{basetmpdir}.")
|
46
|
+
|
47
|
+
log("Call hook_beforeprocess. (#{@params["hook_beforeprocess"]})")
|
48
|
+
call_hook(@params["hook_beforeprocess"], basetmpdir)
|
49
|
+
|
50
|
+
copy_stylesheet(basetmpdir)
|
51
|
+
|
52
|
+
copy_frontmatter(basetmpdir)
|
53
|
+
log("Call hook_afterfrontmatter. (#{@params["hook_afterfrontmatter"]})")
|
54
|
+
call_hook(@params["hook_afterfrontmatter"], basetmpdir)
|
55
|
+
|
56
|
+
build_body(basetmpdir, yamlfile)
|
57
|
+
log("Call hook_afterbody. (#{@params["hook_afterbody"]})")
|
58
|
+
call_hook(@params["hook_afterbody"], basetmpdir)
|
59
|
+
|
60
|
+
copy_backmatter(basetmpdir)
|
61
|
+
log("Call hook_afterbackmatter. (#{@params["hook_afterbackmatter"]})")
|
62
|
+
call_hook(@params["hook_afterbackmatter"], basetmpdir)
|
63
|
+
|
64
|
+
push_contents(basetmpdir)
|
65
|
+
|
66
|
+
copy_images(@params["imagedir"], "#{basetmpdir}/images")
|
67
|
+
copy_images("covers", "#{basetmpdir}/images")
|
68
|
+
copy_images("adv", "#{basetmpdir}/images")
|
69
|
+
copy_images(@params["fontdir"], "#{basetmpdir}/fonts", @params["font_ext"])
|
70
|
+
log("Call hook_aftercopyimage. (#{@params["hook_aftercopyimage"]})")
|
71
|
+
call_hook(@params["hook_aftercopyimage"], basetmpdir)
|
72
|
+
|
73
|
+
@epub.import_imageinfo("#{basetmpdir}/images", basetmpdir)
|
74
|
+
@epub.import_imageinfo("#{basetmpdir}/fonts", basetmpdir, @params["font_ext"])
|
75
|
+
|
76
|
+
epubtmpdir = @params["debug"].nil? ? nil : "#{Dir.pwd}/#{bookname}"
|
77
|
+
Dir.mkdir(bookname) unless @params["debug"].nil?
|
78
|
+
log("Call ePUB producer.")
|
79
|
+
@epub.produce("#{bookname}.epub", basetmpdir, epubtmpdir)
|
80
|
+
log("Finished.")
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def call_hook(filename, *params)
|
86
|
+
if !filename.nil? && File.exist?(filename) && FileTest.executable?(filename)
|
87
|
+
system(filename, *params)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def copy_images(imagedir, destdir, allow_exts=nil)
|
92
|
+
return nil unless File.exist?(imagedir)
|
93
|
+
allow_exts = @params["image_ext"] if allow_exts.nil?
|
94
|
+
FileUtils.mkdir_p(destdir) unless FileTest.directory?(destdir)
|
95
|
+
recursive_copy_images(imagedir, destdir, allow_exts)
|
96
|
+
end
|
97
|
+
|
98
|
+
def recursive_copy_images(imagedir, destdir, allow_exts)
|
99
|
+
Dir.open(imagedir) do |dir|
|
100
|
+
dir.each do |fname|
|
101
|
+
next if fname =~ /\A\./
|
102
|
+
if FileTest.directory?("#{imagedir}/#{fname}")
|
103
|
+
recursive_copy_images("#{imagedir}/#{fname}", "#{destdir}/#{fname}", allow_exts)
|
104
|
+
else
|
105
|
+
if fname =~ /\.(#{allow_exts.join("|")})\Z/i
|
106
|
+
Dir.mkdir(destdir) unless File.exist?(destdir)
|
107
|
+
log("Copy #{imagedir}/#{fname} to the temporary directory.")
|
108
|
+
FileUtils.cp("#{imagedir}/#{fname}", destdir)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def build_body(basetmpdir, yamlfile)
|
116
|
+
@precount = 0
|
117
|
+
@bodycount = 0
|
118
|
+
@postcount = 0
|
119
|
+
|
120
|
+
@manifeststr = ""
|
121
|
+
@ncxstr = ""
|
122
|
+
@tocdesc = Array.new
|
123
|
+
# toccount = 2 ## not used
|
124
|
+
|
125
|
+
basedir = Dir.pwd
|
126
|
+
base_path = Pathname.new(basedir)
|
127
|
+
ReVIEW::Book.load(basedir).parts.each do |part|
|
128
|
+
htmlfile = nil
|
129
|
+
if part.name.present?
|
130
|
+
if part.file?
|
131
|
+
build_chap(part, base_path, basetmpdir, yamlfile, true)
|
132
|
+
else
|
133
|
+
htmlfile = "part_#{part.number}.#{@params["htmlext"]}"
|
134
|
+
build_part(part, basetmpdir, htmlfile)
|
135
|
+
title = ReVIEW::I18n.t("part", part.number)
|
136
|
+
title += ReVIEW::I18n.t("chapter_postfix") + part.name.strip if part.name.strip.present?
|
137
|
+
write_tochtmltxt(basetmpdir, "0\t#{htmlfile}\t#{title}")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
part.chapters.each do |chap|
|
142
|
+
build_chap(chap, base_path, basetmpdir, yamlfile, nil)
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def build_part(part, basetmpdir, htmlfile)
|
149
|
+
log("Create #{htmlfile} from a template.")
|
150
|
+
File.open("#{basetmpdir}/#{htmlfile}", "w") do |f|
|
151
|
+
f.puts header(CGI.escapeHTML(@params["booktitle"]))
|
152
|
+
f.puts <<EOT
|
153
|
+
<div class="part">
|
154
|
+
<h1 class="part-number">#{ReVIEW::I18n.t("part", part.number)}</h1>
|
155
|
+
EOT
|
156
|
+
if part.name.strip.present?
|
157
|
+
f.puts <<EOT
|
158
|
+
<h2 class="part-title">#{part.name.strip}</h2>
|
159
|
+
EOT
|
160
|
+
end
|
161
|
+
|
162
|
+
f.puts <<EOT
|
163
|
+
</div>
|
164
|
+
EOT
|
165
|
+
f.puts footer
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def build_chap(chap, base_path, basetmpdir, yamlfile, ispart=nil)
|
170
|
+
filename = ""
|
171
|
+
if !ispart.nil?
|
172
|
+
filename = chap.path
|
173
|
+
else
|
174
|
+
filename = Pathname.new(chap.path).relative_path_from(base_path).to_s
|
175
|
+
end
|
176
|
+
id = filename.sub(/\.re\Z/, "")
|
177
|
+
|
178
|
+
if @params["rename_for_legacy"] && ispart.nil?
|
179
|
+
if chap.on_PREDEF?
|
180
|
+
@precount += 1
|
181
|
+
id = sprintf("pre%02d", @precount)
|
182
|
+
elsif chap.on_POSTDEF?
|
183
|
+
@postcount += 1
|
184
|
+
id = sprintf("post%02d", @postcount)
|
185
|
+
else
|
186
|
+
@bodycount += 1
|
187
|
+
id = sprintf("chap%02d", @bodycount)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
htmlfile = "#{id}.#{@params["htmlext"]}"
|
192
|
+
log("Create #{htmlfile} from #{filename}.")
|
193
|
+
|
194
|
+
level = @params["secnolevel"]
|
195
|
+
|
196
|
+
if !ispart.nil?
|
197
|
+
level = @params["part_secnolevel"]
|
198
|
+
else
|
199
|
+
level = @params["pre_secnolevel"] if chap.on_PREDEF?
|
200
|
+
level = @params["post_secnolevel"] if chap.on_POSTDEF?
|
201
|
+
end
|
202
|
+
|
203
|
+
stylesheet = ""
|
204
|
+
if @params["stylesheet"].size > 0
|
205
|
+
stylesheet = "--stylesheet=#{@params["stylesheet"].join(",")}"
|
206
|
+
end
|
207
|
+
|
208
|
+
system("review-compile --yaml=#{yamlfile} --target=html --level=#{level} --htmlversion=#{@params["htmlversion"]} --epubversion=#{@params["epubversion"]} #{stylesheet} #{@params["params"]} #{filename} > \"#{basetmpdir}/#{htmlfile}\"")
|
209
|
+
|
210
|
+
write_info_body(basetmpdir, id, htmlfile, ispart)
|
211
|
+
end
|
212
|
+
|
213
|
+
def write_info_body(basetmpdir, id, filename, ispart=nil)
|
214
|
+
headlines = []
|
215
|
+
# FIXME:nonumを修正する必要あり
|
216
|
+
Document.parse_stream(File.new("#{basetmpdir}/#{filename}"), ReVIEWHeaderListener.new(headlines))
|
217
|
+
first = true
|
218
|
+
headlines.each do |headline|
|
219
|
+
headline["level"] = 0 if !ispart.nil? && headline["level"] == 1
|
220
|
+
if first.nil?
|
221
|
+
write_tochtmltxt(basetmpdir, "#{headline["level"]}\t#{filename}##{headline["id"]}\t#{headline["title"]}")
|
222
|
+
else
|
223
|
+
write_tochtmltxt(basetmpdir, "#{headline["level"]}\t#{filename}\t#{headline["title"]}\tforce_include=true")
|
224
|
+
first = nil
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def push_contents(basetmpdir)
|
230
|
+
File.open("#{basetmpdir}/#{@tochtmltxt}") do |f|
|
231
|
+
f.each_line do |l|
|
232
|
+
force_include = nil
|
233
|
+
customid = nil
|
234
|
+
level, file, title, custom = l.chomp.split("\t")
|
235
|
+
unless custom.nil?
|
236
|
+
# custom setting
|
237
|
+
vars = custom.split(/,\s*/)
|
238
|
+
vars.each do |var|
|
239
|
+
k, v = var.split("=")
|
240
|
+
case k
|
241
|
+
when "id"
|
242
|
+
customid = v
|
243
|
+
when "force_include"
|
244
|
+
force_include = true
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
next if level.to_i > @params["toclevel"] && force_include.nil?
|
249
|
+
log("Push #{file} to ePUB contents.")
|
250
|
+
|
251
|
+
if customid.nil?
|
252
|
+
@epub.contents.push(Content.new("file" => file, "level" => level.to_i, "title" => title))
|
253
|
+
else
|
254
|
+
@epub.contents.push(Content.new("id" => customid, "file" => file, "level" => level.to_i, "title" => title))
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def copy_stylesheet(basetmpdir)
|
261
|
+
if @params["stylesheet"].size > 0
|
262
|
+
@params["stylesheet"].each do |sfile|
|
263
|
+
FileUtils.cp(sfile, basetmpdir)
|
264
|
+
@epub.contents.push(Content.new("file" => sfile))
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def copy_frontmatter(basetmpdir)
|
270
|
+
FileUtils.cp(@params["cover"], "#{basetmpdir}/#{File.basename(@params["cover"])}") if !@params["cover"].nil? && File.exist?(@params["cover"])
|
271
|
+
|
272
|
+
if @params["titlepage"]
|
273
|
+
if @params["titlepagefile"].nil?
|
274
|
+
build_titlepage(basetmpdir, "titlepage.#{@params["htmlext"]}")
|
275
|
+
else
|
276
|
+
FileUtils.cp(@params["titlepagefile"], "titlepage.#{@params["htmlext"]}")
|
277
|
+
end
|
278
|
+
write_tochtmltxt(basetmpdir, "1\ttitlepage.#{@params["htmlext"]}\t#{@epub.res.v("titlepagetitle")}")
|
279
|
+
end
|
280
|
+
|
281
|
+
if !@params["originaltitlefile"].nil? && File.exist?(@params["originaltitlefile"])
|
282
|
+
FileUtils.cp(@params["originaltitlefile"], "#{basetmpdir}/#{File.basename(@params["originaltitlefile"])}")
|
283
|
+
write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["originaltitlefile"])}\t#{@epub.res.v("originaltitle")}")
|
284
|
+
end
|
285
|
+
|
286
|
+
if !@params["creditfile"].nil? && File.exist?(@params["creditfile"])
|
287
|
+
FileUtils.cp(@params["creditfile"], "#{basetmpdir}/#{File.basename(@params["creditfile"])}")
|
288
|
+
write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["creditfile"])}\t#{@epub.res.v("credittitle")}")
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def build_titlepage(basetmpdir, htmlfile)
|
293
|
+
File.open("#{basetmpdir}/#{htmlfile}", "w") do |f|
|
294
|
+
f.puts header(CGI.escapeHTML(@params["booktitle"]))
|
295
|
+
f.puts <<EOT
|
296
|
+
<div class="titlepage">
|
297
|
+
<h1 class="tp-title">#{CGI.escapeHTML(@params["booktitle"])}</h1>
|
298
|
+
EOT
|
299
|
+
|
300
|
+
if @params["aut"]
|
301
|
+
f.puts <<EOT
|
302
|
+
<h2 class="tp-author">#{@params["aut"].join(", ")}</h2>
|
303
|
+
EOT
|
304
|
+
end
|
305
|
+
if @params["prt"]
|
306
|
+
f.puts <<EOT
|
307
|
+
<h3 class="tp-publisher">#{@params["prt"].join(", ")}</h3>
|
308
|
+
EOT
|
309
|
+
end
|
310
|
+
|
311
|
+
f.puts <<EOT
|
312
|
+
</div>
|
313
|
+
EOT
|
314
|
+
f.puts footer
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def copy_backmatter(basetmpdir)
|
319
|
+
if @params["profile"]
|
320
|
+
FileUtils.cp(@params["profile"], "#{basetmpdir}/#{File.basename(@params["profile"])}")
|
321
|
+
write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["profile"])}\t#{@epub.res.v("profiletitle")}")
|
322
|
+
end
|
323
|
+
|
324
|
+
if @params["advfile"]
|
325
|
+
FileUtils.cp(@params["advfile"], "#{basetmpdir}/#{File.basename(@params["advfile"])}")
|
326
|
+
write_tochtmltxt(basetmpdir, "1\t#{File.basename(@params["advfile"])}\t#{@epub.res.v("advtitle")}")
|
327
|
+
end
|
328
|
+
|
329
|
+
if @params["colophon"]
|
330
|
+
if @params["colophon"].instance_of?(String) # FIXME:このやり方はやめる?
|
331
|
+
FileUtils.cp(@params["colophon"], "#{basetmpdir}/colophon.#{@params["htmlext"]}")
|
332
|
+
else
|
333
|
+
File.open("#{basetmpdir}/colophon.#{@params["htmlext"]}", "w") {|f| @epub.colophon(f) }
|
334
|
+
end
|
335
|
+
write_tochtmltxt(basetmpdir, "1\tcolophon.#{@params["htmlext"]}\t#{@epub.res.v("colophontitle")}")
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
def write_tochtmltxt(basetmpdir, s)
|
340
|
+
File.open("#{basetmpdir}/#{@tochtmltxt}", "a") do |f|
|
341
|
+
f.puts s
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def header(title)
|
346
|
+
# titleはすでにエスケープ済みと想定
|
347
|
+
s = <<EOT
|
348
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
349
|
+
EOT
|
350
|
+
if @params["htmlversion"] == 5
|
351
|
+
s << <<EOT
|
352
|
+
<!DOCTYPE html>
|
353
|
+
<html xml:lang='ja' xmlns:ops='http://www.idpf.org/2007/ops' xmlns='http://www.w3.org/1999/xhtml'>
|
354
|
+
<head>
|
355
|
+
<meta charset="UTF-8" />
|
356
|
+
EOT
|
357
|
+
else
|
358
|
+
s << <<EOT
|
359
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
360
|
+
<html xml:lang='ja' xmlns:ops='http://www.idpf.org/2007/ops' xmlns='http://www.w3.org/1999/xhtml'>
|
361
|
+
<head>
|
362
|
+
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8' />
|
363
|
+
<meta http-equiv='Content-Style-Type' content='text/css' />
|
364
|
+
EOT
|
365
|
+
end
|
366
|
+
if @params["stylesheet"].size > 0
|
367
|
+
@params["stylesheet"].each do |sfile|
|
368
|
+
s << <<EOT
|
369
|
+
<link rel='stylesheet' type='text/css' href='#{sfile}' />
|
370
|
+
EOT
|
371
|
+
end
|
372
|
+
end
|
373
|
+
s << <<EOT
|
374
|
+
<meta content='Re:VIEW' name='generator'/>
|
375
|
+
<title>#{title}</title>
|
376
|
+
</head>
|
377
|
+
<body>
|
378
|
+
EOT
|
379
|
+
end
|
380
|
+
|
381
|
+
def footer
|
382
|
+
<<EOT
|
383
|
+
</body>
|
384
|
+
</html>
|
385
|
+
EOT
|
386
|
+
end
|
387
|
+
|
388
|
+
class ReVIEWHeaderListener
|
389
|
+
include REXML::StreamListener
|
390
|
+
def initialize(headlines)
|
391
|
+
@level = nil
|
392
|
+
@content = ""
|
393
|
+
@headlines = headlines
|
394
|
+
end
|
395
|
+
|
396
|
+
def tag_start(name, attrs)
|
397
|
+
if name =~ /\Ah(\d+)/
|
398
|
+
unless @level.nil?
|
399
|
+
raise "#{name}, #{attrs}"
|
400
|
+
end
|
401
|
+
@level = $1.to_i
|
402
|
+
@id = attrs["id"] if !attrs["id"].nil?
|
403
|
+
elsif !@level.nil?
|
404
|
+
if name == "img" && !attrs["alt"].nil?
|
405
|
+
@content << attrs["alt"]
|
406
|
+
elsif name == "a" && !attrs["id"].nil?
|
407
|
+
@id = attrs["id"]
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def tag_end(name)
|
413
|
+
if name =~ /\Ah\d+/
|
414
|
+
@headlines.push({"level" => @level, "id" => @id, "title" => @content}) unless @id.nil?
|
415
|
+
@content = ""
|
416
|
+
@level = nil
|
417
|
+
@id = nil
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
def text(text)
|
422
|
+
unless @level.nil?
|
423
|
+
@content << text.gsub("\t", " ") # FIXME:区切り文字
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|