review 2.1.0 → 2.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 (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