review 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.rubocop.yml +293 -6
  4. data/.rubocop_todo.yml +3 -608
  5. data/.travis.yml +6 -13
  6. data/README.md +5 -3
  7. data/Rakefile +6 -6
  8. data/bin/review-catalog-converter +2 -2
  9. data/bin/review-check +1 -1
  10. data/bin/review-compile +1 -2
  11. data/bin/review-init +6 -3
  12. data/bin/review-validate +3 -3
  13. data/bin/review-vol +2 -1
  14. data/doc/NEWS.ja.md +138 -25
  15. data/doc/NEWS.md +137 -25
  16. data/doc/config.yml.sample +2 -2
  17. data/doc/config.yml.sample-simple +1 -1
  18. data/doc/format.ja.md +86 -5
  19. data/doc/format.md +67 -2
  20. data/doc/makeindex.ja.md +95 -0
  21. data/doc/makeindex.md +97 -0
  22. data/doc/sample.css +214 -0
  23. data/lib/epubmaker.rb +6 -6
  24. data/lib/epubmaker/epubcommon.rb +19 -47
  25. data/lib/epubmaker/epubv2.rb +3 -1
  26. data/lib/epubmaker/epubv3.rb +4 -26
  27. data/lib/epubmaker/producer.rb +46 -46
  28. data/lib/epubmaker/zip_exporter.rb +86 -0
  29. data/lib/review/book/base.rb +13 -15
  30. data/lib/review/book/chapter.rb +2 -1
  31. data/lib/review/book/compilable.rb +9 -9
  32. data/lib/review/book/image_finder.rb +13 -13
  33. data/lib/review/book/index.rb +2 -2
  34. data/lib/review/book/volume.rb +2 -2
  35. data/lib/review/builder.rb +57 -1
  36. data/lib/review/catalog.rb +2 -2
  37. data/lib/review/compiler.rb +15 -7
  38. data/lib/review/configure.rb +11 -0
  39. data/lib/review/epubmaker.rb +403 -401
  40. data/lib/review/ewbbuilder.rb +16 -16
  41. data/lib/review/htmlbuilder.rb +42 -58
  42. data/lib/review/htmltoc.rb +1 -1
  43. data/lib/review/htmlutils.rb +50 -4
  44. data/lib/review/i18n.rb +2 -2
  45. data/lib/review/idgxmlbuilder.rb +30 -47
  46. data/lib/review/latexbuilder.rb +86 -41
  47. data/lib/review/latexutils.rb +19 -19
  48. data/lib/review/markdownbuilder.rb +16 -4
  49. data/lib/review/md2inaobuilder.rb +0 -9
  50. data/lib/review/pdfmaker.rb +91 -48
  51. data/lib/review/preprocessor.rb +1 -1
  52. data/lib/review/rstbuilder.rb +763 -0
  53. data/lib/review/sec_counter.rb +7 -9
  54. data/lib/review/tocparser.rb +3 -3
  55. data/lib/review/tocprinter.rb +5 -5
  56. data/lib/review/topbuilder.rb +48 -56
  57. data/lib/review/version.rb +1 -1
  58. data/lib/review/webmaker.rb +6 -7
  59. data/review.gemspec +1 -0
  60. data/templates/latex/layout.tex.erb +27 -2
  61. data/test/assets/test_template.tex +10 -1
  62. data/test/book_test_helper.rb +1 -2
  63. data/test/run_test.rb +10 -0
  64. data/test/sample-book/src/style.css +215 -0
  65. data/test/sample-book/src/vendor/jumoline/lppl.txt +416 -0
  66. data/test/test_book.rb +0 -1
  67. data/test/test_catalog.rb +1 -0
  68. data/test/test_converter.rb +1 -1
  69. data/test/test_epub3maker.rb +44 -51
  70. data/test/test_epubmaker.rb +82 -38
  71. data/test/test_epubmaker_cmd.rb +1 -1
  72. data/test/test_extentions_hash.rb +8 -1
  73. data/test/test_htmlbuilder.rb +411 -18
  74. data/test/test_i18n.rb +17 -0
  75. data/test/test_idgxmlbuilder.rb +88 -3
  76. data/test/test_image_finder.rb +18 -0
  77. data/test/test_index.rb +2 -0
  78. data/test/test_latexbuilder.rb +96 -8
  79. data/test/test_makerhelper.rb +2 -2
  80. data/test/test_markdownbuilder.rb +22 -1
  81. data/test/test_md2inaobuilder.rb +0 -5
  82. data/test/test_pdfmaker.rb +54 -36
  83. data/test/test_pdfmaker_cmd.rb +1 -1
  84. data/test/test_rstbuilder.rb +356 -0
  85. data/test/test_textutils.rb +14 -4
  86. data/test/test_topbuilder.rb +23 -4
  87. data/test/test_zip_exporter.rb +113 -0
  88. metadata +28 -2
@@ -65,11 +65,22 @@ module ReVIEW
65
65
  "chapref" => nil, # for IDGXML
66
66
  "structuredxml" => nil, # for IDGXML
67
67
  "pt_to_mm_unit" => 0.3528, # for IDGXML (DTP: 1pt = 0.3528mm, JIS: 1pt = 0.3514mm)
68
+
68
69
  "footnotetext" => nil, # for LaTeX
69
70
  "texcommand" => "uplatex", # for LaTeX
70
71
  "texdocumentclass" => ["jsbook", "uplatex,oneside"], # for LaTeX
71
72
  "dvicommand" => "dvipdfmx", # for LaTeX
72
73
  "dvioptions" => "-d 5", # for LaTeX
74
+
75
+ "pdfmaker" => {
76
+ "makeindex" => nil, # Make index page
77
+ "makeindex_command" => "mendex", # works only when makeindex is true
78
+ "makeindex_options" => "-f -r -I utf8",
79
+ "makeindex_sty" => nil,
80
+ "makeindex_dic" => nil,
81
+ "makeindex_mecab" => true,
82
+ "makeindex_mecab_opts" => "-Oyomi",
83
+ },
73
84
  ]
74
85
  conf.maker = nil
75
86
  conf
@@ -26,509 +26,511 @@ require 'rexml/streamlistener'
26
26
  require 'epubmaker'
27
27
 
28
28
  module ReVIEW
29
- class EPUBMaker
30
- include ::EPUBMaker
31
- include REXML
32
-
33
- def initialize
34
- @producer = nil
35
- @htmltoc = nil
36
- @buildlogtxt = "build-log.txt"
37
- end
29
+ class EPUBMaker
30
+ include ::EPUBMaker
31
+ include REXML
38
32
 
39
- def log(s)
40
- puts s if @params["debug"].present?
41
- end
33
+ def initialize
34
+ @producer = nil
35
+ @htmltoc = nil
36
+ @buildlogtxt = "build-log.txt"
37
+ end
42
38
 
43
- def load_yaml(yamlfile)
44
- loader = ReVIEW::YAMLLoader.new
45
- @params = ReVIEW::Configure.values.deep_merge(loader.load_file(yamlfile))
46
- @producer = Producer.new(@params)
47
- @producer.load(yamlfile)
48
- @params = @producer.params
49
- @params.maker = "epubmaker"
50
- end
39
+ def log(s)
40
+ puts s if @params["debug"].present?
41
+ end
42
+
43
+ def load_yaml(yamlfile)
44
+ loader = ReVIEW::YAMLLoader.new
45
+ @params = ReVIEW::Configure.values.deep_merge(loader.load_file(yamlfile))
46
+ @producer = Producer.new(@params)
47
+ @producer.load(yamlfile)
48
+ @params = @producer.params
49
+ @params.maker = "epubmaker"
50
+ end
51
51
 
52
- def build_path
53
- if @params["debug"]
54
- path = File.expand_path("#{@params["bookname"]}-epub", Dir.pwd)
55
- if File.exist?(path)
56
- FileUtils.rm_rf(path, :secure => true)
52
+ def build_path
53
+ if @params["debug"]
54
+ path = File.expand_path("#{@params["bookname"]}-epub", Dir.pwd)
55
+ if File.exist?(path)
56
+ FileUtils.rm_rf(path, :secure => true)
57
+ end
58
+ Dir.mkdir(path)
59
+ return path
60
+ else
61
+ return Dir.mktmpdir("#{@params["bookname"]}-epub-")
57
62
  end
58
- Dir.mkdir(path)
59
- return path
60
- else
61
- return Dir.mktmpdir("#{@params["bookname"]}-epub-")
62
63
  end
63
- end
64
64
 
65
- def produce(yamlfile, bookname=nil)
66
- load_yaml(yamlfile)
67
- I18n.setup(@params["language"])
68
- bookname = @params["bookname"] if bookname.nil?
69
- booktmpname = "#{bookname}-epub"
65
+ def produce(yamlfile, bookname=nil)
66
+ load_yaml(yamlfile)
67
+ I18n.setup(@params["language"])
68
+ bookname = @params["bookname"] if bookname.nil?
69
+ booktmpname = "#{bookname}-epub"
70
70
 
71
- begin
72
- @params.check_version(ReVIEW::VERSION)
73
- rescue ReVIEW::ConfigError => e
74
- warn e.message
75
- end
76
- log("Loaded yaml file (#{yamlfile}). I will produce #{bookname}.epub.")
71
+ begin
72
+ @params.check_version(ReVIEW::VERSION)
73
+ rescue ReVIEW::ConfigError => e
74
+ warn e.message
75
+ end
76
+ log("Loaded yaml file (#{yamlfile}). I will produce #{bookname}.epub.")
77
77
 
78
- FileUtils.rm_f("#{bookname}.epub")
79
- FileUtils.rm_rf(booktmpname) if @params["debug"]
78
+ FileUtils.rm_f("#{bookname}.epub")
79
+ FileUtils.rm_rf(booktmpname) if @params["debug"]
80
80
 
81
- basetmpdir = build_path()
82
- begin
83
- log("Created first temporary directory as #{basetmpdir}.")
81
+ basetmpdir = build_path()
82
+ begin
83
+ log("Created first temporary directory as #{basetmpdir}.")
84
84
 
85
- call_hook("hook_beforeprocess", basetmpdir)
85
+ call_hook("hook_beforeprocess", basetmpdir)
86
86
 
87
- @htmltoc = ReVIEW::HTMLToc.new(basetmpdir)
88
- ## copy all files into basetmpdir
89
- copy_stylesheet(basetmpdir)
87
+ @htmltoc = ReVIEW::HTMLToc.new(basetmpdir)
88
+ ## copy all files into basetmpdir
89
+ copy_stylesheet(basetmpdir)
90
90
 
91
- copy_frontmatter(basetmpdir)
92
- call_hook("hook_afterfrontmatter", basetmpdir)
91
+ copy_frontmatter(basetmpdir)
92
+ call_hook("hook_afterfrontmatter", basetmpdir)
93
93
 
94
- build_body(basetmpdir, yamlfile)
95
- call_hook("hook_afterbody", basetmpdir)
94
+ build_body(basetmpdir, yamlfile)
95
+ call_hook("hook_afterbody", basetmpdir)
96
96
 
97
- copy_backmatter(basetmpdir)
98
- call_hook("hook_afterbackmatter", basetmpdir)
97
+ copy_backmatter(basetmpdir)
98
+ call_hook("hook_afterbackmatter", basetmpdir)
99
99
 
100
- ## push contents in basetmpdir into @producer
101
- push_contents(basetmpdir)
100
+ ## push contents in basetmpdir into @producer
101
+ push_contents(basetmpdir)
102
102
 
103
- if @params["epubmaker"]["verify_target_images"].present?
104
- verify_target_images(basetmpdir)
105
- copy_images(@params["imagedir"], basetmpdir)
106
- else
107
- copy_images(@params["imagedir"], "#{basetmpdir}/images")
108
- end
103
+ if @params["epubmaker"]["verify_target_images"].present?
104
+ verify_target_images(basetmpdir)
105
+ copy_images(@params["imagedir"], basetmpdir)
106
+ else
107
+ copy_images(@params["imagedir"], "#{basetmpdir}/#{@params["imagedir"]}")
108
+ end
109
109
 
110
- copy_resources("covers", "#{basetmpdir}/images")
111
- copy_resources("adv", "#{basetmpdir}/images")
112
- copy_resources(@params["fontdir"], "#{basetmpdir}/fonts", @params["font_ext"])
110
+ copy_resources("covers", "#{basetmpdir}/#{@params["imagedir"]}")
111
+ copy_resources("adv", "#{basetmpdir}/#{@params["imagedir"]}")
112
+ copy_resources(@params["fontdir"], "#{basetmpdir}/fonts", @params["font_ext"])
113
113
 
114
- call_hook("hook_aftercopyimage", basetmpdir)
114
+ call_hook("hook_aftercopyimage", basetmpdir)
115
115
 
116
- @producer.import_imageinfo("#{basetmpdir}/images", basetmpdir)
117
- @producer.import_imageinfo("#{basetmpdir}/fonts", basetmpdir, @params["font_ext"])
116
+ @producer.import_imageinfo("#{basetmpdir}/#{@params["imagedir"]}", basetmpdir)
117
+ @producer.import_imageinfo("#{basetmpdir}/fonts", basetmpdir, @params["font_ext"])
118
118
 
119
- epubtmpdir = nil
120
- if @params["debug"].present?
121
- epubtmpdir = "#{basetmpdir}/#{booktmpname}"
122
- Dir.mkdir(epubtmpdir)
123
- end
124
- log("Call ePUB producer.")
125
- @producer.produce("#{bookname}.epub", basetmpdir, epubtmpdir)
126
- log("Finished.")
127
- ensure
128
- unless @params["debug"]
129
- FileUtils.remove_entry_secure basetmpdir
119
+ epubtmpdir = nil
120
+ if @params["debug"].present?
121
+ epubtmpdir = "#{basetmpdir}/#{booktmpname}"
122
+ Dir.mkdir(epubtmpdir)
123
+ end
124
+ log("Call ePUB producer.")
125
+ @producer.produce("#{bookname}.epub", basetmpdir, epubtmpdir)
126
+ log("Finished.")
127
+ ensure
128
+ unless @params["debug"]
129
+ FileUtils.remove_entry_secure basetmpdir
130
+ end
130
131
  end
131
132
  end
132
- end
133
133
 
134
- def call_hook(hook_name, *params)
135
- filename = @params["epubmaker"][hook_name]
136
- log("Call #{hook_name}. (#{filename})")
137
- if filename.present? && File.exist?(filename) && FileTest.executable?(filename)
138
- if ENV["REVIEW_SAFE_MODE"].to_i & 1 > 0
139
- warn "hook is prohibited in safe mode. ignored."
140
- else
141
- system(filename, *params)
134
+ def call_hook(hook_name, *params)
135
+ filename = @params["epubmaker"][hook_name]
136
+ log("Call #{hook_name}. (#{filename})")
137
+ if filename.present? && File.exist?(filename) && FileTest.executable?(filename)
138
+ if ENV["REVIEW_SAFE_MODE"].to_i & 1 > 0
139
+ warn "hook is prohibited in safe mode. ignored."
140
+ else
141
+ system(filename, *params)
142
+ end
142
143
  end
143
144
  end
144
- end
145
145
 
146
- def verify_target_images(basetmpdir)
147
- @producer.contents.each do |content|
148
- if content.media == "application/xhtml+xml"
146
+ def verify_target_images(basetmpdir)
147
+ @producer.contents.each do |content|
148
+ if content.media == "application/xhtml+xml"
149
149
 
150
- File.open("#{basetmpdir}/#{content.file}") do |f|
151
- Document.new(File.new(f)).each_element("//img") do |e|
152
- @params["epubmaker"]["force_include_images"].push(e.attributes["src"])
153
- if e.attributes["src"] =~ /svg\Z/i
154
- content.properties.push("svg")
150
+ File.open("#{basetmpdir}/#{content.file}") do |f|
151
+ Document.new(File.new(f)).each_element("//img") do |e|
152
+ @params["epubmaker"]["force_include_images"].push(e.attributes["src"])
153
+ if e.attributes["src"] =~ /svg\Z/i
154
+ content.properties.push("svg")
155
+ end
155
156
  end
156
157
  end
157
- end
158
- elsif content.media == "text/css"
159
- File.open("#{basetmpdir}/#{content.file}") do |f|
160
- f.each_line do |l|
161
- l.scan(/url\((.+?)\)/) do |m|
162
- @params["epubmaker"]["force_include_images"].push($1.strip)
158
+ elsif content.media == "text/css"
159
+ File.open("#{basetmpdir}/#{content.file}") do |f|
160
+ f.each_line do |l|
161
+ l.scan(/url\((.+?)\)/) do |m|
162
+ @params["epubmaker"]["force_include_images"].push($1.strip)
163
+ end
163
164
  end
164
165
  end
165
166
  end
166
167
  end
168
+ @params["epubmaker"]["force_include_images"] = @params["epubmaker"]["force_include_images"].sort.uniq
167
169
  end
168
- @params["epubmaker"]["force_include_images"] = @params["epubmaker"]["force_include_images"].sort.uniq
169
- end
170
170
 
171
- def copy_images(resdir, destdir, allow_exts=nil)
172
- return nil unless File.exist?(resdir)
173
- allow_exts = @params["image_ext"] if allow_exts.nil?
174
- FileUtils.mkdir_p(destdir)
175
- if @params["epubmaker"]["verify_target_images"].present?
176
- @params["epubmaker"]["force_include_images"].each do |file|
177
- unless File.exist?(file)
178
- warn "#{file} is not found, skip." if file !~ /\Ahttp[s]?:/
179
- next
171
+ def copy_images(resdir, destdir, allow_exts=nil)
172
+ return nil unless File.exist?(resdir)
173
+ allow_exts = @params["image_ext"] if allow_exts.nil?
174
+ FileUtils.mkdir_p(destdir)
175
+ if @params["epubmaker"]["verify_target_images"].present?
176
+ @params["epubmaker"]["force_include_images"].each do |file|
177
+ unless File.exist?(file)
178
+ warn "#{file} is not found, skip." if file !~ /\Ahttp[s]?:/
179
+ next
180
+ end
181
+ basedir = File.dirname(file)
182
+ FileUtils.mkdir_p("#{destdir}/#{basedir}")
183
+ log("Copy #{file} to the temporary directory.")
184
+ FileUtils.cp(file, "#{destdir}/#{basedir}")
180
185
  end
181
- basedir = File.dirname(file)
182
- FileUtils.mkdir_p("#{destdir}/#{basedir}")
183
- log("Copy #{file} to the temporary directory.")
184
- FileUtils.cp(file, "#{destdir}/#{basedir}")
186
+ else
187
+ recursive_copy_files(resdir, destdir, allow_exts)
185
188
  end
186
- else
187
- recursive_copy_files(resdir, destdir, allow_exts)
188
189
  end
189
- end
190
190
 
191
- def copy_resources(resdir, destdir, allow_exts=nil)
192
- return nil unless File.exist?(resdir)
193
- allow_exts = @params["image_ext"] if allow_exts.nil?
194
- FileUtils.mkdir_p(destdir)
195
- recursive_copy_files(resdir, destdir, allow_exts)
196
- end
191
+ def copy_resources(resdir, destdir, allow_exts=nil)
192
+ return nil unless File.exist?(resdir)
193
+ allow_exts = @params["image_ext"] if allow_exts.nil?
194
+ FileUtils.mkdir_p(destdir)
195
+ recursive_copy_files(resdir, destdir, allow_exts)
196
+ end
197
197
 
198
- def recursive_copy_files(resdir, destdir, allow_exts)
199
- Dir.open(resdir) do |dir|
200
- dir.each do |fname|
201
- next if fname.start_with?('.')
202
- if FileTest.directory?("#{resdir}/#{fname}")
203
- recursive_copy_files("#{resdir}/#{fname}", "#{destdir}/#{fname}", allow_exts)
204
- else
205
- if fname =~ /\.(#{allow_exts.join("|")})\Z/i
206
- FileUtils.mkdir_p(destdir)
207
- log("Copy #{resdir}/#{fname} to the temporary directory.")
208
- FileUtils.cp("#{resdir}/#{fname}", destdir)
198
+ def recursive_copy_files(resdir, destdir, allow_exts)
199
+ Dir.open(resdir) do |dir|
200
+ dir.each do |fname|
201
+ next if fname.start_with?('.')
202
+ if FileTest.directory?("#{resdir}/#{fname}")
203
+ recursive_copy_files("#{resdir}/#{fname}", "#{destdir}/#{fname}", allow_exts)
204
+ else
205
+ if fname =~ /\.(#{allow_exts.join("|")})\Z/i
206
+ FileUtils.mkdir_p(destdir)
207
+ log("Copy #{resdir}/#{fname} to the temporary directory.")
208
+ FileUtils.cp("#{resdir}/#{fname}", destdir)
209
+ end
209
210
  end
210
211
  end
211
212
  end
212
213
  end
213
- end
214
-
215
- def check_compile_status
216
- return unless @compile_errors
217
-
218
- $stderr.puts "compile error, No EPUB file output."
219
- exit 1
220
- end
221
214
 
222
- def build_body(basetmpdir, yamlfile)
223
- @precount = 0
224
- @bodycount = 0
225
- @postcount = 0
226
-
227
- @manifeststr = ""
228
- @ncxstr = ""
229
- @tocdesc = Array.new
230
-
231
- basedir = File.dirname(yamlfile)
232
- base_path = Pathname.new(basedir)
233
- book = ReVIEW::Book.load(basedir)
234
- book.config = @params
235
- @converter = ReVIEW::Converter.new(book, ReVIEW::HTMLBuilder.new)
236
- @compile_errors = nil
237
- book.parts.each do |part|
238
- htmlfile = nil
239
- if part.name.present?
240
- if part.file?
241
- build_chap(part, base_path, basetmpdir, true)
242
- else
243
- htmlfile = "part_#{part.number}.#{@params["htmlext"]}"
244
- build_part(part, basetmpdir, htmlfile)
245
- title = ReVIEW::I18n.t("part", part.number)
246
- title += ReVIEW::I18n.t("chapter_postfix") + part.name.strip if part.name.strip.present?
247
- @htmltoc.add_item(0, htmlfile, title, {:chaptype => "part"})
248
- write_buildlogtxt(basetmpdir, htmlfile, "")
215
+ def check_compile_status
216
+ return unless @compile_errors
217
+
218
+ $stderr.puts "compile error, No EPUB file output."
219
+ exit 1
220
+ end
221
+
222
+ def build_body(basetmpdir, yamlfile)
223
+ @precount = 0
224
+ @bodycount = 0
225
+ @postcount = 0
226
+
227
+ @manifeststr = ""
228
+ @ncxstr = ""
229
+ @tocdesc = []
230
+
231
+ basedir = File.dirname(yamlfile)
232
+ base_path = Pathname.new(basedir)
233
+ book = ReVIEW::Book.load(basedir)
234
+ book.config = @params
235
+ @converter = ReVIEW::Converter.new(book, ReVIEW::HTMLBuilder.new)
236
+ @compile_errors = nil
237
+ book.parts.each do |part|
238
+ htmlfile = nil
239
+ if part.name.present?
240
+ if part.file?
241
+ build_chap(part, base_path, basetmpdir, true)
242
+ else
243
+ htmlfile = "part_#{part.number}.#{@params["htmlext"]}"
244
+ build_part(part, basetmpdir, htmlfile)
245
+ title = ReVIEW::I18n.t("part", part.number)
246
+ title += ReVIEW::I18n.t("chapter_postfix") + part.name.strip if part.name.strip.present?
247
+ @htmltoc.add_item(0, htmlfile, title, {:chaptype => "part"})
248
+ write_buildlogtxt(basetmpdir, htmlfile, "")
249
+ end
249
250
  end
250
- end
251
251
 
252
- part.chapters.each do |chap|
253
- build_chap(chap, base_path, basetmpdir, false)
252
+ part.chapters.each do |chap|
253
+ build_chap(chap, base_path, basetmpdir, false)
254
+ end
254
255
  end
255
-
256
+ check_compile_status()
256
257
  end
257
- check_compile_status()
258
- end
259
258
 
260
- def build_part(part, basetmpdir, htmlfile)
261
- log("Create #{htmlfile} from a template.")
262
- File.open("#{basetmpdir}/#{htmlfile}", "w") do |f|
263
- @body = ""
264
- @body << "<div class=\"part\">\n"
265
- @body << "<h1 class=\"part-number\">#{CGI.escapeHTML(ReVIEW::I18n.t("part", part.number))}</h1>\n"
266
- if part.name.strip.present?
267
- @body << "<h2 class=\"part-title\">#{CGI.escapeHTML(part.name.strip)}</h2>\n"
268
- end
269
- @body << "</div>\n"
270
-
271
- @language = @producer.params['language']
272
- @stylesheets = @producer.params["stylesheet"]
273
- tmplfile = File.expand_path(template_name, ReVIEW::Template::TEMPLATE_DIR)
274
- tmpl = ReVIEW::Template.load(tmplfile)
275
- f.write tmpl.result(binding)
276
- end
277
- end
259
+ def build_part(part, basetmpdir, htmlfile)
260
+ log("Create #{htmlfile} from a template.")
261
+ File.open("#{basetmpdir}/#{htmlfile}", "w") do |f|
262
+ @body = ""
263
+ @body << "<div class=\"part\">\n"
264
+ @body << "<h1 class=\"part-number\">#{CGI.escapeHTML(ReVIEW::I18n.t("part", part.number))}</h1>\n"
265
+ if part.name.strip.present?
266
+ @body << "<h2 class=\"part-title\">#{CGI.escapeHTML(part.name.strip)}</h2>\n"
267
+ end
268
+ @body << "</div>\n"
278
269
 
279
- def template_name
280
- if @producer.params["htmlversion"].to_i == 5
281
- './html/layout-html5.html.erb'
282
- else
283
- './html/layout-xhtml1.html.erb'
270
+ @language = @producer.params['language']
271
+ @stylesheets = @producer.params["stylesheet"]
272
+ tmplfile = File.expand_path(template_name, ReVIEW::Template::TEMPLATE_DIR)
273
+ tmpl = ReVIEW::Template.load(tmplfile)
274
+ f.write tmpl.result(binding)
275
+ end
284
276
  end
285
- end
286
277
 
287
- def build_chap(chap, base_path, basetmpdir, ispart)
288
- filename = ""
289
-
290
- chaptype = "body"
291
- if ispart
292
- chaptype = "part"
293
- elsif chap.on_PREDEF?
294
- chaptype = "pre"
295
- elsif chap.on_APPENDIX?
296
- chaptype = "post"
278
+ def template_name
279
+ if @producer.params["htmlversion"].to_i == 5
280
+ './html/layout-html5.html.erb'
281
+ else
282
+ './html/layout-xhtml1.html.erb'
283
+ end
297
284
  end
298
285
 
299
- if ispart.present?
300
- filename = chap.path
301
- else
302
- filename = Pathname.new(chap.path).relative_path_from(base_path).to_s
303
- end
304
- id = filename.sub(/\.re\Z/, "")
286
+ def build_chap(chap, base_path, basetmpdir, ispart)
287
+ filename = ""
305
288
 
306
- if @params["epubmaker"]["rename_for_legacy"] && ispart.nil?
307
- if chap.on_PREDEF?
308
- @precount += 1
309
- id = sprintf("pre%02d", @precount)
289
+ chaptype = "body"
290
+ if ispart
291
+ chaptype = "part"
292
+ elsif chap.on_PREDEF?
293
+ chaptype = "pre"
310
294
  elsif chap.on_APPENDIX?
311
- @postcount += 1
312
- id = sprintf("post%02d", @postcount)
295
+ chaptype = "post"
296
+ end
297
+
298
+ if ispart.present?
299
+ filename = chap.path
313
300
  else
314
- @bodycount += 1
315
- id = sprintf("chap%02d", @bodycount)
301
+ filename = Pathname.new(chap.path).relative_path_from(base_path).to_s
302
+ end
303
+ id = filename.sub(/\.re\Z/, "")
304
+
305
+ if @params["epubmaker"]["rename_for_legacy"] && ispart.nil?
306
+ if chap.on_PREDEF?
307
+ @precount += 1
308
+ id = sprintf("pre%02d", @precount)
309
+ elsif chap.on_APPENDIX?
310
+ @postcount += 1
311
+ id = sprintf("post%02d", @postcount)
312
+ else
313
+ @bodycount += 1
314
+ id = sprintf("chap%02d", @bodycount)
315
+ end
316
316
  end
317
- end
318
317
 
319
- htmlfile = "#{id}.#{@params["htmlext"]}"
320
- write_buildlogtxt(basetmpdir, htmlfile, filename)
321
- log("Create #{htmlfile} from #{filename}.")
318
+ htmlfile = "#{id}.#{@params["htmlext"]}"
319
+ write_buildlogtxt(basetmpdir, htmlfile, filename)
320
+ log("Create #{htmlfile} from #{filename}.")
322
321
 
323
- if @params["params"].present?
324
- warn "'params:' in config.yml is obsoleted."
325
- if @params["params"] =~ /stylesheet=/
326
- warn "stylesheets should be defined in 'stylesheet:', not in 'params:'"
322
+ if @params["params"].present?
323
+ warn "'params:' in config.yml is obsoleted."
324
+ if @params["params"] =~ /stylesheet=/
325
+ warn "stylesheets should be defined in 'stylesheet:', not in 'params:'"
326
+ end
327
+ end
328
+ begin
329
+ @converter.convert(filename, File.join(basetmpdir, htmlfile))
330
+ write_info_body(basetmpdir, id, htmlfile, ispart, chaptype)
331
+ remove_hidden_title(basetmpdir, htmlfile)
332
+ rescue => e
333
+ @compile_errors = true
334
+ warn "compile error in #{filename} (#{e.class})"
335
+ warn e.message
327
336
  end
328
337
  end
329
- begin
330
- @converter.convert(filename, File.join(basetmpdir, htmlfile))
331
- write_info_body(basetmpdir, id, htmlfile, ispart, chaptype)
332
- remove_hidden_title(basetmpdir, htmlfile)
333
- rescue => e
334
- @compile_errors = true
335
- warn "compile error in #{filename} (#{e.class})"
336
- warn e.message
337
- end
338
- end
339
338
 
340
- def remove_hidden_title(basetmpdir, htmlfile)
341
- File.open("#{basetmpdir}/#{htmlfile}", "r+") do |f|
342
- body = f.read.
343
- gsub(/<h\d .*?hidden=['"]true['"].*?>.*?<\/h\d>\n/, '').
344
- gsub(/(<h\d .*?)\s*notoc=['"]true['"]\s*(.*?>.*?<\/h\d>\n)/, '\1\2')
345
- f.rewind
346
- f.print body
347
- f.truncate(f.tell)
339
+ def remove_hidden_title(basetmpdir, htmlfile)
340
+ File.open("#{basetmpdir}/#{htmlfile}", "r+") do |f|
341
+ body = f.read.
342
+ gsub(/<h\d .*?hidden=['"]true['"].*?>.*?<\/h\d>\n/, '').
343
+ gsub(/(<h\d .*?)\s*notoc=['"]true['"]\s*(.*?>.*?<\/h\d>\n)/, '\1\2')
344
+ f.rewind
345
+ f.print body
346
+ f.truncate(f.tell)
347
+ end
348
348
  end
349
- end
350
349
 
351
- def detect_properties(path)
352
- properties = []
353
- File.open(path) do |f|
354
- doc = REXML::Document.new(f)
355
- if REXML::XPath.first(doc, "//m:math", {'m' => 'http://www.w3.org/1998/Math/MathML'})
356
- properties<< "mathml"
357
- end
358
- if REXML::XPath.first(doc, "//s:svg", {'s' => 'http://www.w3.org/2000/svg'})
359
- properties<< "svg"
350
+ def detect_properties(path)
351
+ properties = []
352
+ File.open(path) do |f|
353
+ doc = REXML::Document.new(f)
354
+ if REXML::XPath.first(doc, "//m:math", {'m' => 'http://www.w3.org/1998/Math/MathML'})
355
+ properties<< "mathml"
356
+ end
357
+ if REXML::XPath.first(doc, "//s:svg", {'s' => 'http://www.w3.org/2000/svg'})
358
+ properties<< "svg"
359
+ end
360
360
  end
361
+ properties
361
362
  end
362
- properties
363
- end
364
363
 
365
- def write_info_body(basetmpdir, id, filename, ispart=nil, chaptype=nil)
366
- headlines = []
367
- path = File.join(basetmpdir, filename)
368
- Document.parse_stream(File.new(path), ReVIEWHeaderListener.new(headlines))
369
- properties = detect_properties(path)
370
- prop_str = ""
371
- if properties.present?
372
- prop_str = ",properties="+properties.join(" ")
373
- end
374
- first = true
375
- headlines.each do |headline|
376
- headline["level"] = 0 if ispart.present? && headline["level"] == 1
377
- if first.nil?
378
- @htmltoc.add_item(headline["level"], filename+"#"+headline["id"], headline["title"], {:chaptype => chaptype, :notoc => headline["notoc"]})
379
- else
380
- @htmltoc.add_item(headline["level"], filename, headline["title"], {:force_include => true, :chaptype => chaptype+prop_str, :notoc => headline["notoc"]})
381
- first = nil
364
+ def write_info_body(basetmpdir, id, filename, ispart=nil, chaptype=nil)
365
+ headlines = []
366
+ path = File.join(basetmpdir, filename)
367
+ Document.parse_stream(File.new(path), ReVIEWHeaderListener.new(headlines))
368
+ properties = detect_properties(path)
369
+ prop_str = ""
370
+ if properties.present?
371
+ prop_str = ",properties="+properties.join(" ")
372
+ end
373
+ first = true
374
+ headlines.each do |headline|
375
+ headline["level"] = 0 if ispart.present? && headline["level"] == 1
376
+ if first.nil?
377
+ @htmltoc.add_item(headline["level"], filename+"#"+headline["id"], headline["title"], {:chaptype => chaptype, :notoc => headline["notoc"]})
378
+ else
379
+ @htmltoc.add_item(headline["level"], filename, headline["title"], {:force_include => true, :chaptype => chaptype+prop_str, :notoc => headline["notoc"]})
380
+ first = nil
381
+ end
382
382
  end
383
383
  end
384
- end
385
384
 
386
- def push_contents(basetmpdir)
387
- @htmltoc.each_item do |level, file, title, args|
388
- next if level.to_i > @params["toclevel"] && args[:force_include].nil?
389
- log("Push #{file} to ePUB contents.")
385
+ def push_contents(basetmpdir)
386
+ @htmltoc.each_item do |level, file, title, args|
387
+ next if level.to_i > @params["toclevel"] && args[:force_include].nil?
388
+ log("Push #{file} to ePUB contents.")
390
389
 
391
- hash = {"file" => file, "level" => level.to_i, "title" => title, "chaptype" => args[:chaptype]}
392
- if args[:id].present?
393
- hash["id"] = args[:id]
394
- end
395
- if args[:properties].present?
396
- hash["properties"] = args[:properties].split(" ")
397
- end
398
- if args[:notoc].present?
399
- hash["notoc"] = args[:notoc]
390
+ hash = {"file" => file, "level" => level.to_i, "title" => title, "chaptype" => args[:chaptype]}
391
+ if args[:id].present?
392
+ hash["id"] = args[:id]
393
+ end
394
+ if args[:properties].present?
395
+ hash["properties"] = args[:properties].split(" ")
396
+ end
397
+ if args[:notoc].present?
398
+ hash["notoc"] = args[:notoc]
399
+ end
400
+ @producer.contents.push(Content.new(hash))
400
401
  end
401
- @producer.contents.push(Content.new(hash))
402
402
  end
403
- end
404
403
 
405
- def copy_stylesheet(basetmpdir)
406
- if @params["stylesheet"].size > 0
407
- @params["stylesheet"].each do |sfile|
408
- FileUtils.cp(sfile, basetmpdir)
409
- @producer.contents.push(Content.new("file" => sfile))
404
+ def copy_stylesheet(basetmpdir)
405
+ if @params["stylesheet"].size > 0
406
+ @params["stylesheet"].each do |sfile|
407
+ FileUtils.cp(sfile, basetmpdir)
408
+ @producer.contents.push(Content.new("file" => sfile))
409
+ end
410
410
  end
411
411
  end
412
- end
413
412
 
414
- def copy_frontmatter(basetmpdir)
415
- FileUtils.cp(@params["cover"], "#{basetmpdir}/#{File.basename(@params["cover"])}") if @params["cover"].present? && File.exist?(@params["cover"])
413
+ def copy_frontmatter(basetmpdir)
414
+ FileUtils.cp(@params["cover"], "#{basetmpdir}/#{File.basename(@params["cover"])}") if @params["cover"].present? && File.exist?(@params["cover"])
416
415
 
417
- if @params["titlepage"]
418
- if @params["titlefile"].nil?
419
- build_titlepage(basetmpdir, "titlepage.#{@params["htmlext"]}")
420
- else
421
- FileUtils.cp(@params["titlefile"], "#{basetmpdir}/titlepage.#{@params["htmlext"]}")
416
+ if @params["titlepage"]
417
+ if @params["titlefile"].nil?
418
+ build_titlepage(basetmpdir, "titlepage.#{@params["htmlext"]}")
419
+ else
420
+ FileUtils.cp(@params["titlefile"], "#{basetmpdir}/titlepage.#{@params["htmlext"]}")
421
+ end
422
+ @htmltoc.add_item(1, "titlepage.#{@params['htmlext']}", @producer.res.v("titlepagetitle"), {:chaptype => "pre"})
422
423
  end
423
- @htmltoc.add_item(1, "titlepage.#{@params['htmlext']}", @producer.res.v("titlepagetitle"), {:chaptype => "pre"})
424
- end
425
424
 
426
- if @params["originaltitlefile"].present? && File.exist?(@params["originaltitlefile"])
427
- FileUtils.cp(@params["originaltitlefile"], "#{basetmpdir}/#{File.basename(@params["originaltitlefile"])}")
428
- @htmltoc.add_item(1, File.basename(@params["originaltitlefile"]), @producer.res.v("originaltitle"), {:chaptype => "pre"})
429
- end
425
+ if @params["originaltitlefile"].present? && File.exist?(@params["originaltitlefile"])
426
+ FileUtils.cp(@params["originaltitlefile"], "#{basetmpdir}/#{File.basename(@params["originaltitlefile"])}")
427
+ @htmltoc.add_item(1, File.basename(@params["originaltitlefile"]), @producer.res.v("originaltitle"), {:chaptype => "pre"})
428
+ end
430
429
 
431
- if @params["creditfile"].present? && File.exist?(@params["creditfile"])
432
- FileUtils.cp(@params["creditfile"], "#{basetmpdir}/#{File.basename(@params["creditfile"])}")
433
- @htmltoc.add_item(1, File.basename(@params["creditfile"]), @producer.res.v("credittitle"), {:chaptype => "pre"})
430
+ if @params["creditfile"].present? && File.exist?(@params["creditfile"])
431
+ FileUtils.cp(@params["creditfile"], "#{basetmpdir}/#{File.basename(@params["creditfile"])}")
432
+ @htmltoc.add_item(1, File.basename(@params["creditfile"]), @producer.res.v("credittitle"), {:chaptype => "pre"})
433
+ end
434
434
  end
435
- end
436
435
 
437
- def build_titlepage(basetmpdir, htmlfile)
438
- # TODO: should be created via epubcommon
439
- @title = CGI.escapeHTML(@params.name_of("booktitle"))
440
- File.open("#{basetmpdir}/#{htmlfile}", "w") do |f|
441
- @body = ""
442
- @body << "<div class=\"titlepage\">\n"
443
- @body << "<h1 class=\"tp-title\">#{CGI.escapeHTML(@params.name_of("booktitle"))}</h1>\n"
444
- if @params["aut"]
445
- @body << "<h2 class=\"tp-author\">#{CGI.escapeHTML(@params.names_of("aut").join(ReVIEW::I18n.t("names_splitter")))}</h2>\n"
446
- end
447
- if @params["prt"]
448
- @body << "<h3 class=\"tp-publisher\">#{CGI.escapeHTML(@params.names_of("prt").join(ReVIEW::I18n.t("names_splitter")))}</h3>\n"
449
- end
450
- @body << "</div>"
451
-
452
- @language = @producer.params['language']
453
- @stylesheets = @producer.params["stylesheet"]
454
- tmplfile = File.expand_path(template_name, ReVIEW::Template::TEMPLATE_DIR)
455
- tmpl = ReVIEW::Template.load(tmplfile)
456
- f.write tmpl.result(binding)
457
- end
458
- end
436
+ def build_titlepage(basetmpdir, htmlfile)
437
+ # TODO: should be created via epubcommon
438
+ @title = CGI.escapeHTML(@params.name_of("booktitle"))
439
+ File.open("#{basetmpdir}/#{htmlfile}", "w") do |f|
440
+ @body = ""
441
+ @body << "<div class=\"titlepage\">\n"
442
+ @body << "<h1 class=\"tp-title\">#{CGI.escapeHTML(@params.name_of("booktitle"))}</h1>\n"
443
+ if @params["subtitle"]
444
+ @body << "<h2 class=\"tp-subtitle\">#{CGI.escapeHTML(@params.name_of("subtitle"))}</h2>\n"
445
+ end
446
+ if @params["aut"]
447
+ @body << "<h2 class=\"tp-author\">#{CGI.escapeHTML(@params.names_of("aut").join(ReVIEW::I18n.t("names_splitter")))}</h2>\n"
448
+ end
449
+ if @params["prt"]
450
+ @body << "<h3 class=\"tp-publisher\">#{CGI.escapeHTML(@params.names_of("prt").join(ReVIEW::I18n.t("names_splitter")))}</h3>\n"
451
+ end
452
+ @body << "</div>"
459
453
 
460
- def copy_backmatter(basetmpdir)
461
- if @params["profile"]
462
- FileUtils.cp(@params["profile"], "#{basetmpdir}/#{File.basename(@params["profile"])}")
463
- @htmltoc.add_item(1, File.basename(@params["profile"]), @producer.res.v("profiletitle"), {:chaptype => "post"})
454
+ @language = @producer.params['language']
455
+ @stylesheets = @producer.params["stylesheet"]
456
+ tmplfile = File.expand_path(template_name, ReVIEW::Template::TEMPLATE_DIR)
457
+ tmpl = ReVIEW::Template.load(tmplfile)
458
+ f.write tmpl.result(binding)
459
+ end
464
460
  end
465
461
 
466
- if @params["advfile"]
467
- FileUtils.cp(@params["advfile"], "#{basetmpdir}/#{File.basename(@params["advfile"])}")
468
- @htmltoc.add_item(1, File.basename(@params["advfile"]), @producer.res.v("advtitle"), {:chaptype => "post"})
469
- end
462
+ def copy_backmatter(basetmpdir)
463
+ if @params["profile"]
464
+ FileUtils.cp(@params["profile"], "#{basetmpdir}/#{File.basename(@params["profile"])}")
465
+ @htmltoc.add_item(1, File.basename(@params["profile"]), @producer.res.v("profiletitle"), {:chaptype => "post"})
466
+ end
470
467
 
471
- if @params["colophon"]
472
- if @params["colophon"].kind_of?(String) # FIXME:このやり方はやめる?
473
- FileUtils.cp(@params["colophon"], "#{basetmpdir}/colophon.#{@params["htmlext"]}")
474
- else
475
- File.open("#{basetmpdir}/colophon.#{@params["htmlext"]}", "w") {|f| @producer.colophon(f) }
468
+ if @params["advfile"]
469
+ FileUtils.cp(@params["advfile"], "#{basetmpdir}/#{File.basename(@params["advfile"])}")
470
+ @htmltoc.add_item(1, File.basename(@params["advfile"]), @producer.res.v("advtitle"), {:chaptype => "post"})
476
471
  end
477
- @htmltoc.add_item(1, "colophon.#{@params["htmlext"]}", @producer.res.v("colophontitle"), {:chaptype => "post"})
478
- end
479
472
 
480
- if @params["backcover"]
481
- FileUtils.cp(@params["backcover"], "#{basetmpdir}/#{File.basename(@params["backcover"])}")
482
- @htmltoc.add_item(1, File.basename(@params["backcover"]), @producer.res.v("backcovertitle"), {:chaptype => "post"})
483
- end
484
- end
473
+ if @params["colophon"]
474
+ if @params["colophon"].kind_of?(String) # FIXME: このやり方はやめる?
475
+ FileUtils.cp(@params["colophon"], "#{basetmpdir}/colophon.#{@params["htmlext"]}")
476
+ else
477
+ File.open("#{basetmpdir}/colophon.#{@params["htmlext"]}", "w") {|f| @producer.colophon(f) }
478
+ end
479
+ @htmltoc.add_item(1, "colophon.#{@params["htmlext"]}", @producer.res.v("colophontitle"), {:chaptype => "post"})
480
+ end
485
481
 
486
- def write_buildlogtxt(basetmpdir, htmlfile, reviewfile)
487
- File.open("#{basetmpdir}/#{@buildlogtxt}", "a") do |f|
488
- f.puts "#{htmlfile},#{reviewfile}"
482
+ if @params["backcover"]
483
+ FileUtils.cp(@params["backcover"], "#{basetmpdir}/#{File.basename(@params["backcover"])}")
484
+ @htmltoc.add_item(1, File.basename(@params["backcover"]), @producer.res.v("backcovertitle"), {:chaptype => "post"})
485
+ end
489
486
  end
490
- end
491
487
 
492
- class ReVIEWHeaderListener
493
- include REXML::StreamListener
494
- def initialize(headlines)
495
- @level = nil
496
- @content = ""
497
- @headlines = headlines
488
+ def write_buildlogtxt(basetmpdir, htmlfile, reviewfile)
489
+ File.open("#{basetmpdir}/#{@buildlogtxt}", "a") do |f|
490
+ f.puts "#{htmlfile},#{reviewfile}"
491
+ end
498
492
  end
499
493
 
500
- def tag_start(name, attrs)
501
- if name =~ /\Ah(\d+)/
502
- if @level.present?
503
- raise "#{name}, #{attrs}"
504
- end
505
- @level = $1.to_i
506
- @id = attrs["id"] if attrs["id"].present?
507
- @notoc = attrs["notoc"] if attrs["notoc"].present?
508
- elsif !@level.nil?
509
- if name == "img" && attrs["alt"].present?
510
- @content << attrs["alt"]
511
- elsif name == "a" && attrs["id"].present?
512
- @id = attrs["id"]
494
+ class ReVIEWHeaderListener
495
+ include REXML::StreamListener
496
+ def initialize(headlines)
497
+ @level = nil
498
+ @content = ""
499
+ @headlines = headlines
500
+ end
501
+
502
+ def tag_start(name, attrs)
503
+ if name =~ /\Ah(\d+)/
504
+ if @level.present?
505
+ raise "#{name}, #{attrs}"
506
+ end
507
+ @level = $1.to_i
508
+ @id = attrs["id"] if attrs["id"].present?
509
+ @notoc = attrs["notoc"] if attrs["notoc"].present?
510
+ elsif !@level.nil?
511
+ if name == "img" && attrs["alt"].present?
512
+ @content << attrs["alt"]
513
+ elsif name == "a" && attrs["id"].present?
514
+ @id = attrs["id"]
515
+ end
513
516
  end
514
517
  end
515
- end
516
518
 
517
- def tag_end(name)
518
- if name =~ /\Ah\d+/
519
- @headlines.push({"level" => @level, "id" => @id, "title" => @content, "notoc" => @notoc}) if @id.present?
520
- @content = ""
521
- @level = nil
522
- @id = nil
523
- @notoc = nil
519
+ def tag_end(name)
520
+ if name =~ /\Ah\d+/
521
+ @headlines.push({"level" => @level, "id" => @id, "title" => @content, "notoc" => @notoc}) if @id.present?
522
+ @content = ""
523
+ @level = nil
524
+ @id = nil
525
+ @notoc = nil
526
+ end
524
527
  end
525
- end
526
528
 
527
- def text(text)
528
- if @level.present?
529
- @content << text.gsub("\t", " ") # FIXME:区切り文字
529
+ def text(text)
530
+ if @level.present?
531
+ @content << text.gsub("\t", " ") # FIXME: 区切り文字
532
+ end
530
533
  end
531
534
  end
532
535
  end
533
- end
534
536
  end