review 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +11 -1
- data/.travis.yml +16 -15
- data/NEWS.ja.md +75 -0
- data/NEWS.md +75 -0
- data/appveyor.yml +20 -2
- data/bin/review-catalog-converter +3 -3
- data/bin/review-check +3 -3
- data/bin/review-compile +6 -6
- data/bin/review-epubmaker +3 -35
- data/bin/review-index +5 -5
- data/bin/review-preproc +4 -4
- data/bin/review-vol +5 -5
- data/doc/format.ja.md +6 -4
- data/doc/format.md +3 -1
- data/lib/epubmaker/epubcommon.rb +1 -2
- data/lib/epubmaker/epubv2.rb +1 -1
- data/lib/epubmaker/epubv3.rb +1 -0
- data/lib/epubmaker/producer.rb +2 -1
- data/lib/review/book/base.rb +5 -5
- data/lib/review/book/index.rb +18 -5
- data/lib/review/builder.rb +8 -2
- data/lib/review/compiler.rb +11 -34
- data/lib/review/epub2html.rb +37 -4
- data/lib/review/epubmaker.rb +40 -3
- data/lib/review/htmlbuilder.rb +2 -2
- data/lib/review/idgxmlbuilder.rb +9 -8
- data/lib/review/init.rb +7 -7
- data/lib/review/latexbuilder.rb +36 -14
- data/lib/review/location.rb +32 -0
- data/lib/review/markdownbuilder.rb +8 -1
- data/lib/review/plaintextbuilder.rb +9 -9
- data/lib/review/preprocessor.rb +2 -24
- data/lib/review/topbuilder.rb +4 -4
- data/lib/review/update.rb +3 -3
- data/lib/review/version.rb +1 -1
- data/lib/review/yamlloader.rb +23 -16
- data/review.gemspec +3 -2
- data/templates/latex/config.erb +4 -0
- data/templates/latex/review-jlreq/review-base.sty +45 -22
- data/templates/latex/review-jsbook/review-base.sty +20 -15
- data/templates/latex/review-jsbook/review-jsbook.cls +3 -3
- data/templates/opf/epubv3.opf.erb +1 -0
- data/test/assets/test_template.tex +4 -0
- data/test/assets/test_template_backmatter.tex +4 -0
- data/test/test_book.rb +1 -1
- data/test/test_builder.rb +16 -0
- data/test/test_catalog.rb +5 -0
- data/test/test_htmlbuilder.rb +471 -96
- data/test/test_idgxmlbuilder.rb +132 -17
- data/test/test_index.rb +40 -0
- data/test/test_latexbuilder.rb +668 -72
- data/test/test_latexbuilder_v2.rb +597 -68
- data/test/test_markdownbuilder.rb +90 -13
- data/test/test_md2inaobuilder.rb +20 -7
- data/test/test_plaintextbuilder.rb +241 -19
- data/test/test_preprocessor.rb +2 -16
- data/test/test_rstbuilder.rb +216 -22
- data/test/test_topbuilder.rb +334 -22
- metadata +20 -6
data/bin/review-vol
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
# Copyright (c) 2014-
|
3
|
+
# Copyright (c) 2014-2019 Minero Aoki, Kenshi Muto
|
4
4
|
# 2003-2014 Minero Aoki
|
5
5
|
#
|
6
6
|
# This program is free software.
|
@@ -37,8 +37,8 @@ def main
|
|
37
37
|
end
|
38
38
|
begin
|
39
39
|
opts.parse!
|
40
|
-
rescue OptionParser::ParseError =>
|
41
|
-
@logger.error
|
40
|
+
rescue OptionParser::ParseError => e
|
41
|
+
@logger.error e.message
|
42
42
|
$stderr.puts opts.help
|
43
43
|
exit 1
|
44
44
|
end
|
@@ -70,9 +70,9 @@ def main
|
|
70
70
|
end
|
71
71
|
puts '============================='
|
72
72
|
print_volume book.volume # puts "Total #{book.volume}"
|
73
|
-
rescue ReVIEW::ApplicationError, Errno::ENOENT =>
|
73
|
+
rescue ReVIEW::ApplicationError, Errno::ENOENT => e
|
74
74
|
raise if $DEBUG
|
75
|
-
@logger.error "#{File.basename($PROGRAM_NAME)}: #{
|
75
|
+
@logger.error "#{File.basename($PROGRAM_NAME)}: #{e.message}"
|
76
76
|
exit 1
|
77
77
|
end
|
78
78
|
|
data/doc/format.ja.md
CHANGED
@@ -20,9 +20,9 @@ Re:VIEW フォーマットの文法について解説します。Re:VIEW フォ
|
|
20
20
|
* 2行以上空けても、1行空きと同じ意味になります。
|
21
21
|
* 空行せずに改行して段落の記述を続ける際、英文の単語間スペースについては考慮されないことに注意してください。Re:VIEW は各行を単純に連結するだけであり、TeX のように前後の単語を判断してスペースを入れるようなことはしません。
|
22
22
|
|
23
|
-
##
|
23
|
+
## 章・節・項・目・段(見出し)
|
24
24
|
|
25
|
-
|
25
|
+
章・節・項・目といった見出しは「`=`」「`==`」「`===`」「`====`」「`=====`」で表します。7 レベル以上は使えません。`=`のあとにはスペースを入れます。
|
26
26
|
|
27
27
|
例:
|
28
28
|
|
@@ -33,9 +33,11 @@ Re:VIEW フォーマットの文法について解説します。Re:VIEW フォ
|
|
33
33
|
|
34
34
|
=== 項のキャプション
|
35
35
|
|
36
|
-
====
|
36
|
+
==== 目のキャプション
|
37
37
|
|
38
|
-
=====
|
38
|
+
===== 段のキャプション
|
39
|
+
|
40
|
+
====== 小段のキャプション
|
39
41
|
```
|
40
42
|
|
41
43
|
見出しは行の先頭から始める必要があります。行頭に空白を入れると、ただの本文と見なされます。
|
data/doc/format.md
CHANGED
@@ -24,7 +24,7 @@ Two empty lines or more are same as one empty line.
|
|
24
24
|
|
25
25
|
## Chapter, Section, Subsection (headings)
|
26
26
|
|
27
|
-
Chapters, sections, subsections, subsubsections use `=`, `==`, `===`, `====`,
|
27
|
+
Chapters, sections, subsections, subsubsections use `=`, `==`, `===`, `====`, `=====`, and `======`.
|
28
28
|
You should add one or more spaces after `=`.
|
29
29
|
|
30
30
|
Usage:
|
@@ -39,6 +39,8 @@ Usage:
|
|
39
39
|
==== 4th level
|
40
40
|
|
41
41
|
===== 5th level
|
42
|
+
|
43
|
+
====== 6th level
|
42
44
|
```
|
43
45
|
|
44
46
|
Headings should not have any spaces before title; if line head has space, it is as paragraph.
|
data/lib/epubmaker/epubcommon.rb
CHANGED
@@ -36,10 +36,9 @@ module EPUBMaker
|
|
36
36
|
if @producer.config['coverimage']
|
37
37
|
file = nil
|
38
38
|
@producer.contents.each do |item|
|
39
|
-
if !item.media.start_with?('image') || item.file !~ /#{@producer.config[
|
39
|
+
if !item.media.start_with?('image') || item.file !~ /#{@producer.config['coverimage']}\Z/
|
40
40
|
next
|
41
41
|
end
|
42
|
-
|
43
42
|
s << %Q( <meta name="cover" content="#{item.id}"/>\n)
|
44
43
|
file = item.file
|
45
44
|
break
|
data/lib/epubmaker/epubv2.rb
CHANGED
@@ -39,7 +39,7 @@ module EPUBMaker
|
|
39
39
|
if @producer.config[item].is_a?(Array)
|
40
40
|
s << @producer.config.names_of(item).map { |i| %Q( <dc:#{item}>#{CGI.escapeHTML(i)}</dc:#{item}>\n) }.join
|
41
41
|
else
|
42
|
-
s << %Q( <dc:#{item}>#{CGI.escapeHTML(@producer.config.name_of(item))}</dc:#{item}>\n)
|
42
|
+
s << %Q( <dc:#{item}>#{CGI.escapeHTML(@producer.config.name_of(item).to_s)}</dc:#{item}>\n)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
data/lib/epubmaker/epubv3.rb
CHANGED
data/lib/epubmaker/producer.rb
CHANGED
@@ -192,7 +192,8 @@ module EPUBMaker
|
|
192
192
|
current = Dir.pwd
|
193
193
|
basedir ||= current
|
194
194
|
|
195
|
-
|
195
|
+
# use Dir to solve a path for Windows (see #1011)
|
196
|
+
new_tmpdir = Dir[File.join(tmpdir.nil? ? Dir.mktmpdir : tmpdir)][0]
|
196
197
|
if epubfile !~ %r{\A/}
|
197
198
|
epubfile = "#{current}/#{epubfile}"
|
198
199
|
end
|
data/lib/review/book/base.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2009-
|
2
|
+
# Copyright (c) 2009-2019 Minero Aoki, Kenshi Muto
|
3
3
|
# 2002-2008 Minero Aoki
|
4
4
|
#
|
5
5
|
# This program is free software.
|
@@ -266,8 +266,8 @@ module ReVIEW
|
|
266
266
|
if File.file?(predef_file)
|
267
267
|
mkpart_from_namelistfile(predef_file)
|
268
268
|
end
|
269
|
-
rescue FileNotFound =>
|
270
|
-
raise FileNotFound, "preface #{
|
269
|
+
rescue FileNotFound => e
|
270
|
+
raise FileNotFound, "preface #{e.message}"
|
271
271
|
end
|
272
272
|
end
|
273
273
|
|
@@ -283,8 +283,8 @@ module ReVIEW
|
|
283
283
|
if File.file?(postdef_file)
|
284
284
|
mkpart_from_namelistfile(postdef_file)
|
285
285
|
end
|
286
|
-
rescue FileNotFound =>
|
287
|
-
raise FileNotFound, "postscript #{
|
286
|
+
rescue FileNotFound => e
|
287
|
+
raise FileNotFound, "postscript #{e.message}"
|
288
288
|
end
|
289
289
|
end
|
290
290
|
|
data/lib/review/book/index.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2008-
|
1
|
+
# Copyright (c) 2008-2019 Minero Aoki, Kenshi Muto
|
2
2
|
# 2002-2007 Minero Aoki
|
3
3
|
#
|
4
4
|
# This program is free software.
|
@@ -316,6 +316,7 @@ module ReVIEW
|
|
316
316
|
if m.nil? || m[1].size > 10 # Ignore too deep index
|
317
317
|
next
|
318
318
|
end
|
319
|
+
|
319
320
|
index = m[1].size - 2
|
320
321
|
|
321
322
|
# column
|
@@ -335,7 +336,9 @@ module ReVIEW
|
|
335
336
|
|
336
337
|
next unless index >= 0
|
337
338
|
if indexs.size > (index + 1)
|
338
|
-
|
339
|
+
unless %w[nonum notoc nodisp].include?(m[2])
|
340
|
+
indexs = indexs.take(index + 1)
|
341
|
+
end
|
339
342
|
headlines = headlines.take(index + 1)
|
340
343
|
end
|
341
344
|
if indexs[index].nil?
|
@@ -343,9 +346,15 @@ module ReVIEW
|
|
343
346
|
indexs[i] ||= 0
|
344
347
|
end
|
345
348
|
end
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
+
|
350
|
+
if %w[nonum notoc nodisp].include?(m[2])
|
351
|
+
headlines[index] = m[3].present? ? m[3].strip : m[4].strip
|
352
|
+
items.push Item.new(headlines.join('|'), nil, m[4].strip)
|
353
|
+
else
|
354
|
+
indexs[index] += 1
|
355
|
+
headlines[index] = m[3].present? ? m[3].strip : m[4].strip
|
356
|
+
items.push Item.new(headlines.join('|'), indexs.dup, m[4].strip)
|
357
|
+
end
|
349
358
|
end
|
350
359
|
new(items, chap)
|
351
360
|
end
|
@@ -364,6 +373,10 @@ module ReVIEW
|
|
364
373
|
end
|
365
374
|
|
366
375
|
def number(id)
|
376
|
+
unless self[id].number
|
377
|
+
# when notoc
|
378
|
+
return ''
|
379
|
+
end
|
367
380
|
n = @chap.number
|
368
381
|
# XXX: remove magic number (move to lib/review/book/chapter.rb)
|
369
382
|
if @chap.on_appendix? && @chap.number > 0 && @chap.number < 28
|
data/lib/review/builder.rb
CHANGED
@@ -165,6 +165,7 @@ module ReVIEW
|
|
165
165
|
rows.push(line.strip.split(/\t+/).map { |s| s.sub(/\A\./, '') })
|
166
166
|
end
|
167
167
|
rows = adjust_n_cols(rows)
|
168
|
+
error 'no rows in the table' if rows.empty?
|
168
169
|
|
169
170
|
begin
|
170
171
|
if caption.present?
|
@@ -173,7 +174,6 @@ module ReVIEW
|
|
173
174
|
rescue KeyError
|
174
175
|
error "no such table: #{id}"
|
175
176
|
end
|
176
|
-
return if rows.empty?
|
177
177
|
table_begin rows.first.size
|
178
178
|
if sepidx
|
179
179
|
sepidx.times do
|
@@ -478,7 +478,9 @@ module ReVIEW
|
|
478
478
|
def extract_chapter_id(chap_ref)
|
479
479
|
m = /\A([\w+-]+)\|(.+)/.match(chap_ref)
|
480
480
|
if m
|
481
|
-
|
481
|
+
ch = @book.contents.detect { |chap| chap.id == m[1] }
|
482
|
+
raise KeyError unless ch
|
483
|
+
return [ch, m[2]]
|
482
484
|
end
|
483
485
|
[@chapter, chap_ref]
|
484
486
|
end
|
@@ -614,6 +616,10 @@ EOTGNUPLOT
|
|
614
616
|
end
|
615
617
|
end
|
616
618
|
|
619
|
+
def over_secnolevel?(n)
|
620
|
+
@book.config['secnolevel'] >= n.to_s.split('.').size
|
621
|
+
end
|
622
|
+
|
617
623
|
## override TextUtils::detab
|
618
624
|
def detab(str, num = nil)
|
619
625
|
if num
|
data/lib/review/compiler.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2009-
|
1
|
+
# Copyright (c) 2009-2019 Minero Aoki, Kenshi Muto
|
2
2
|
# Copyright (c) 2002-2007 Minero Aoki
|
3
3
|
#
|
4
4
|
# This program is free software.
|
@@ -9,32 +9,10 @@
|
|
9
9
|
require 'review/extentions'
|
10
10
|
require 'review/preprocessor'
|
11
11
|
require 'review/exception'
|
12
|
+
require 'review/location'
|
12
13
|
require 'strscan'
|
13
14
|
|
14
15
|
module ReVIEW
|
15
|
-
class Location
|
16
|
-
def initialize(filename, f)
|
17
|
-
@filename = filename
|
18
|
-
@f = f
|
19
|
-
end
|
20
|
-
|
21
|
-
attr_reader :filename
|
22
|
-
|
23
|
-
def lineno
|
24
|
-
@f.lineno
|
25
|
-
end
|
26
|
-
|
27
|
-
def string
|
28
|
-
begin
|
29
|
-
"#{@filename}:#{@f.lineno}"
|
30
|
-
rescue
|
31
|
-
"#{@filename}:nil"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
alias_method :to_s, :string
|
36
|
-
end
|
37
|
-
|
38
16
|
class Compiler
|
39
17
|
def initialize(strategy)
|
40
18
|
@strategy = strategy
|
@@ -380,11 +358,10 @@ module ReVIEW
|
|
380
358
|
@strategy.ul_item_begin buf
|
381
359
|
elsif level < current_level # down
|
382
360
|
level_diff = current_level - level
|
383
|
-
|
384
|
-
|
385
|
-
@strategy.ul_begin { i }
|
386
|
-
@strategy.ul_item_begin []
|
361
|
+
if level_diff != 1
|
362
|
+
error 'too many *.'
|
387
363
|
end
|
364
|
+
level = current_level
|
388
365
|
@strategy.ul_begin { level }
|
389
366
|
@strategy.ul_item_begin buf
|
390
367
|
elsif level > current_level # up
|
@@ -501,8 +478,8 @@ module ReVIEW
|
|
501
478
|
end
|
502
479
|
begin
|
503
480
|
syntax.check_args args
|
504
|
-
rescue CompileError =>
|
505
|
-
error
|
481
|
+
rescue CompileError => e
|
482
|
+
error e.message
|
506
483
|
args = ['(NoArgument)'] * syntax.min_argc
|
507
484
|
end
|
508
485
|
if syntax.block_allowed?
|
@@ -564,8 +541,8 @@ module ReVIEW
|
|
564
541
|
result << @strategy.nofunc_text(revert_replace_fence(words.shift))
|
565
542
|
end
|
566
543
|
result
|
567
|
-
rescue =>
|
568
|
-
error
|
544
|
+
rescue => e
|
545
|
+
error e.message
|
569
546
|
end
|
570
547
|
public :text # called from strategy
|
571
548
|
|
@@ -578,8 +555,8 @@ module ReVIEW
|
|
578
555
|
raise "strategy does not support inline op: @<#{op}>"
|
579
556
|
end
|
580
557
|
@strategy.__send__("inline_#{op}", arg)
|
581
|
-
rescue =>
|
582
|
-
error
|
558
|
+
rescue => e
|
559
|
+
error e.message
|
583
560
|
@strategy.nofunc_text(str)
|
584
561
|
end
|
585
562
|
|
data/lib/review/epub2html.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2018 Kenshi Muto
|
2
|
+
# Copyright (c) 2018-2019 Kenshi Muto
|
3
3
|
#
|
4
4
|
# This program is free software.
|
5
5
|
# You can distribute or modify this program under the terms of
|
@@ -9,6 +9,8 @@
|
|
9
9
|
require 'zip'
|
10
10
|
require 'rexml/document'
|
11
11
|
require 'cgi'
|
12
|
+
require 'optparse'
|
13
|
+
require 'review/version'
|
12
14
|
|
13
15
|
module ReVIEW
|
14
16
|
class Epub2Html
|
@@ -17,13 +19,26 @@ module ReVIEW
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def execute(*args)
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
opts = OptionParser.new
|
23
|
+
|
24
|
+
opts.banner = <<EOT
|
25
|
+
Usage: review-epub2html [options] EPUBfile [file_for_head_and_foot] > HTMLfile
|
23
26
|
file_for_head_and_foot: HTML file to extract header and footer area.
|
24
27
|
This file must be contained in the EPUB.
|
25
28
|
If omitted, the first found file is used.
|
29
|
+
|
26
30
|
EOT
|
31
|
+
opts.version = ReVIEW::VERSION
|
32
|
+
opts.on('--help', 'Prints this message and quit.') do
|
33
|
+
puts opts.help
|
34
|
+
exit 0
|
35
|
+
end
|
36
|
+
opts.on('--inline-footnote', 'Embed footnote blocks in paragraph.') { @inline_footnote = true }
|
37
|
+
|
38
|
+
opts.parse!(args)
|
39
|
+
|
40
|
+
if args[0].nil? || !File.exist?(args[0])
|
41
|
+
puts opts.help
|
27
42
|
exit 1
|
28
43
|
end
|
29
44
|
|
@@ -36,6 +51,7 @@ EOT
|
|
36
51
|
@htmls = {}
|
37
52
|
@head = nil
|
38
53
|
@tail = nil
|
54
|
+
@inline_footnote = nil
|
39
55
|
end
|
40
56
|
|
41
57
|
def parse_epub(epubname)
|
@@ -99,6 +115,23 @@ EOT
|
|
99
115
|
e.attributes['href'] = "##{anc}"
|
100
116
|
end
|
101
117
|
|
118
|
+
if @inline_footnote
|
119
|
+
# move footnotes to inline as same as LaTeX.
|
120
|
+
footnotes = {}
|
121
|
+
|
122
|
+
doc.each_element("//div[@class='footnote']") do |e|
|
123
|
+
e.name = 'span'
|
124
|
+
e.attributes.delete('epub:type')
|
125
|
+
footnotes[e.attributes['id']] = e
|
126
|
+
e.remove
|
127
|
+
end
|
128
|
+
|
129
|
+
doc.each_element("//a[@class='noteref']") do |e|
|
130
|
+
e.parent.insert_after(e, footnotes[e.attributes['href'].sub('#', '')])
|
131
|
+
e.remove
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
102
135
|
doc.to_s.
|
103
136
|
sub(/.*(<body.*?>)/m, %Q(<section id="#{sanitize(fname)}">)).
|
104
137
|
sub(%r{(</body>).*}m, '</section>')
|
data/lib/review/epubmaker.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2010-
|
1
|
+
# Copyright (c) 2010-2019 Kenshi Muto and Masayoshi Takahashi
|
2
2
|
#
|
3
3
|
# This program is free software.
|
4
4
|
# You can distribute or modify this program under the terms of
|
@@ -64,7 +64,45 @@ module ReVIEW
|
|
64
64
|
@producer.load(yamlfile)
|
65
65
|
@config = @producer.config
|
66
66
|
@config.maker = 'epubmaker'
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.execute(*args)
|
70
|
+
self.new.execute(*args)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_opts(args)
|
74
|
+
cmd_config = {}
|
75
|
+
opts = OptionParser.new
|
76
|
+
|
77
|
+
opts.banner = 'Usage: review-epubmaker [options] configfile [export_filename]'
|
78
|
+
opts.version = ReVIEW::VERSION
|
79
|
+
opts.on('--help', 'Prints this message and quit.') do
|
80
|
+
puts opts.help
|
81
|
+
exit 0
|
82
|
+
end
|
83
|
+
opts.on('--[no-]debug', 'Keep temporary files.') { |debug| cmd_config['debug'] = debug }
|
84
|
+
|
85
|
+
opts.parse!(args)
|
86
|
+
if args.size < 1 || args.size > 2
|
87
|
+
puts opts.help
|
88
|
+
exit 0
|
89
|
+
end
|
90
|
+
|
91
|
+
[cmd_config, args[0], args[1]]
|
92
|
+
end
|
93
|
+
|
94
|
+
def execute(*args)
|
95
|
+
@config = ReVIEW::Configure.values
|
96
|
+
@config.maker = 'epubmaker'
|
97
|
+
cmd_config, yamlfile, exportfile = parse_opts(args)
|
98
|
+
error "#{yamlfile} not found." unless File.exist?(yamlfile)
|
99
|
+
|
100
|
+
load_yaml(yamlfile)
|
101
|
+
@config.deep_merge!(cmd_config)
|
67
102
|
update_log_level
|
103
|
+
log("Loaded yaml file (#{yamlfile}).")
|
104
|
+
|
105
|
+
produce(yamlfile, exportfile)
|
68
106
|
end
|
69
107
|
|
70
108
|
def update_log_level
|
@@ -89,7 +127,6 @@ module ReVIEW
|
|
89
127
|
end
|
90
128
|
|
91
129
|
def produce(yamlfile, bookname = nil)
|
92
|
-
load_yaml(yamlfile)
|
93
130
|
I18n.setup(@config['language'])
|
94
131
|
bookname ||= @config['bookname']
|
95
132
|
booktmpname = "#{bookname}-epub"
|
@@ -99,7 +136,7 @@ module ReVIEW
|
|
99
136
|
rescue ReVIEW::ConfigError => e
|
100
137
|
warn e.message
|
101
138
|
end
|
102
|
-
log("
|
139
|
+
log("#{bookname}.epub will be created.")
|
103
140
|
|
104
141
|
FileUtils.rm_f("#{bookname}.epub")
|
105
142
|
if @config['debug']
|