review 5.2.0 → 5.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby-tex.yml +1 -1
- data/.github/workflows/ruby-win.yml +1 -1
- data/.github/workflows/ruby.yml +1 -1
- data/.rubocop.yml +1 -319
- data/NEWS.ja.md +116 -0
- data/NEWS.md +117 -0
- data/README.md +9 -8
- data/bin/review +1 -1
- data/bin/review-catalog-converter +15 -15
- data/bin/review-check +7 -7
- data/bin/review-compile +6 -8
- data/bin/review-index +1 -1
- data/bin/review-preproc +1 -1
- data/bin/review-validate +2 -2
- data/doc/config.yml.sample +7 -1
- data/doc/config.yml.sample-simple +1 -1
- data/doc/format.ja.md +34 -4
- data/doc/format.md +32 -3
- data/lib/review/book/base.rb +3 -3
- data/lib/review/book/book_unit.rb +13 -3
- data/lib/review/book/chapter.rb +1 -1
- data/lib/review/book/index.rb +7 -4
- data/lib/review/book/part.rb +12 -13
- data/lib/review/book/volume.rb +1 -1
- data/lib/review/builder.rb +82 -28
- data/lib/review/catalog.rb +6 -5
- data/lib/review/compiler.rb +20 -14
- data/lib/review/configure.rb +5 -2
- data/lib/review/epub2html.rb +12 -12
- data/lib/review/epubmaker/content.rb +1 -1
- data/lib/review/epubmaker/epubcommon.rb +47 -45
- data/lib/review/epubmaker/epubv2.rb +2 -1
- data/lib/review/epubmaker/epubv3.rb +5 -4
- data/lib/review/epubmaker/producer.rb +3 -3
- data/lib/review/epubmaker/reviewheaderlistener.rb +1 -1
- data/lib/review/epubmaker.rb +35 -32
- data/lib/review/extentions/string.rb +1 -1
- data/lib/review/htmlbuilder.rb +65 -15
- data/lib/review/htmlutils.rb +17 -17
- data/lib/review/i18n.rb +3 -3
- data/lib/review/i18n.yml +6 -0
- data/lib/review/idgxmlbuilder.rb +42 -21
- data/lib/review/idgxmlmaker.rb +15 -13
- data/lib/review/img_math.rb +1 -0
- data/lib/review/index_builder.rb +100 -38
- data/lib/review/init.rb +4 -4
- data/lib/review/latexbuilder.rb +69 -34
- data/lib/review/lineinput.rb +3 -3
- data/lib/review/location.rb +1 -1
- data/lib/review/logger.rb +21 -21
- data/lib/review/makerhelper.rb +3 -3
- data/lib/review/markdownbuilder.rb +16 -8
- data/lib/review/pdfmaker.rb +40 -21
- data/lib/review/plaintextbuilder.rb +8 -7
- data/lib/review/preprocessor/repository.rb +1 -1
- data/lib/review/preprocessor.rb +5 -5
- data/lib/review/rstbuilder.rb +11 -2
- data/lib/review/textmaker.rb +20 -18
- data/lib/review/textutils.rb +5 -6
- data/lib/review/tocprinter.rb +11 -6
- data/lib/review/topbuilder.rb +89 -12
- data/lib/review/update.rb +16 -8
- data/lib/review/version.rb +1 -1
- data/lib/review/volumeprinter.rb +9 -9
- data/lib/review/webmaker.rb +32 -32
- data/lib/review/webtocprinter.rb +10 -10
- data/lib/review/yamlloader.rb +36 -2
- data/review.gemspec +2 -0
- data/samples/sample-book/src/config.yml +0 -1
- data/samples/syntax-book/ch02.re +16 -1
- data/templates/html/_titlepage.html.erb +9 -17
- data/templates/latex/config.erb +3 -0
- data/templates/latex/review-jlreq/review-base.sty +2 -1
- data/templates/latex/review-jlreq/review-jlreq.cls +36 -3
- data/templates/latex/review-jsbook/review-base.sty +7 -1
- data/templates/latex/review-jsbook/review-jsbook.cls +31 -4
- data/templates/opf/opf_manifest_epubv2.opf.erb +1 -1
- data/templates/opf/opf_manifest_epubv3.opf.erb +1 -1
- data/test/assets/syntax_book_index_detail.txt +10 -8
- data/test/assets/test_template.tex +4 -1
- data/test/assets/test_template_backmatter.tex +4 -1
- data/test/book_test_helper.rb +10 -10
- data/test/test_book_chapter.rb +25 -2
- data/test/test_builder.rb +5 -3
- data/test/test_epub3maker.rb +3 -3
- data/test/test_epubmaker.rb +14 -29
- data/test/test_epubmaker_cmd.rb +2 -2
- data/test/test_htmlbuilder.rb +80 -8
- data/test/test_idgxmlbuilder.rb +13 -13
- data/test/test_idgxmlmaker_cmd.rb +1 -1
- data/test/test_img_math.rb +11 -2
- data/test/test_index.rb +30 -4
- data/test/test_latexbuilder.rb +53 -6
- data/test/test_markdownbuilder.rb +45 -0
- data/test/test_pdfmaker.rb +19 -0
- data/test/test_pdfmaker_cmd.rb +10 -10
- data/test/test_plaintextbuilder.rb +45 -4
- data/test/test_rstbuilder.rb +13 -0
- data/test/test_textmaker_cmd.rb +1 -1
- data/test/test_topbuilder.rb +169 -11
- data/test/test_yamlloader.rb +28 -42
- metadata +19 -4
data/lib/review/book/part.rb
CHANGED
@@ -14,11 +14,11 @@ module ReVIEW
|
|
14
14
|
def self.mkpart_from_namelistfile(book, path)
|
15
15
|
chaps = []
|
16
16
|
File.read(path, mode: 'rt:BOM|utf-8').split.each_with_index do |name, number|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
chaps << if /PREDEF/.match?(path)
|
18
|
+
Chapter.mkchap(book, name)
|
19
|
+
else
|
20
|
+
Chapter.mkchap(book, name, number + 1)
|
21
|
+
end
|
22
22
|
end
|
23
23
|
Part.mkpart(chaps)
|
24
24
|
end
|
@@ -47,11 +47,11 @@ module ReVIEW
|
|
47
47
|
else
|
48
48
|
@content = ''
|
49
49
|
end
|
50
|
-
if file?
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
50
|
+
@title = if file?
|
51
|
+
nil
|
52
|
+
else
|
53
|
+
name
|
54
|
+
end
|
55
55
|
@volume = nil
|
56
56
|
|
57
57
|
super()
|
@@ -78,11 +78,10 @@ module ReVIEW
|
|
78
78
|
|
79
79
|
def volume
|
80
80
|
if @number && file?
|
81
|
-
|
81
|
+
Volume.count_file(File.join(@book.config['contentdir'], @path))
|
82
82
|
else
|
83
|
-
|
83
|
+
Volume.new(0, 0, 0)
|
84
84
|
end
|
85
|
-
vol
|
86
85
|
end
|
87
86
|
|
88
87
|
def file?
|
data/lib/review/book/volume.rb
CHANGED
data/lib/review/builder.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2002-
|
1
|
+
# Copyright (c) 2002-2022 Minero Aoki, Kenshi Muto
|
2
2
|
#
|
3
3
|
# This program is free software.
|
4
4
|
# You can distribute or modify this program under the terms of
|
@@ -42,6 +42,7 @@ module ReVIEW
|
|
42
42
|
@doc_status = {}
|
43
43
|
@dictionary = {}
|
44
44
|
@img_math = img_math
|
45
|
+
@shown_endnotes = true
|
45
46
|
end
|
46
47
|
|
47
48
|
def bind(compiler, chapter, location)
|
@@ -61,11 +62,11 @@ module ReVIEW
|
|
61
62
|
if @book && @book.config
|
62
63
|
@img_math ||= ReVIEW::ImgMath.new(@book.config)
|
63
64
|
if words_file_path = @book.config['words_file']
|
64
|
-
if words_file_path.is_a?(String)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
65
|
+
words_files = if words_file_path.is_a?(String)
|
66
|
+
[words_file_path]
|
67
|
+
else
|
68
|
+
words_file_path
|
69
|
+
end
|
69
70
|
words_files.each do |f|
|
70
71
|
load_words(f)
|
71
72
|
end
|
@@ -103,11 +104,18 @@ module ReVIEW
|
|
103
104
|
|
104
105
|
def check_nest
|
105
106
|
if @children && !@children.empty?
|
106
|
-
app_error "//beginchild of #{@children.reverse.join(',')} misses //endchild"
|
107
|
+
app_error "#{@location}: //beginchild of #{@children.reverse.join(',')} misses //endchild"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def check_printendnotes
|
112
|
+
if @shown_endnotes.nil?
|
113
|
+
app_error "#{@location}: //endnote is found but //printendnotes is not found."
|
107
114
|
end
|
108
115
|
end
|
109
116
|
|
110
117
|
def result
|
118
|
+
check_printendnotes
|
111
119
|
solve_nest(@output.string)
|
112
120
|
end
|
113
121
|
|
@@ -126,11 +134,9 @@ module ReVIEW
|
|
126
134
|
end
|
127
135
|
|
128
136
|
def load_words(file)
|
129
|
-
if File.exist?(file)
|
130
|
-
|
131
|
-
|
132
|
-
@dictionary[row[0]] = row[1]
|
133
|
-
end
|
137
|
+
if File.exist?(file) && /\.csv\Z/i.match?(file)
|
138
|
+
CSV.foreach(file) do |row|
|
139
|
+
@dictionary[row[0]] = row[1]
|
134
140
|
end
|
135
141
|
end
|
136
142
|
end
|
@@ -273,17 +279,28 @@ module ReVIEW
|
|
273
279
|
table(lines, nil, caption)
|
274
280
|
end
|
275
281
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
282
|
+
def printendnotes
|
283
|
+
@shown_endnotes = true
|
284
|
+
endnote_begin
|
285
|
+
@chapter.endnotes.each do |en|
|
286
|
+
endnote_item(en.id)
|
287
|
+
end
|
288
|
+
endnote_end
|
289
|
+
end
|
290
|
+
|
291
|
+
def endnote(_id, _str)
|
292
|
+
@shown_endnotes = nil
|
293
|
+
end
|
294
|
+
|
295
|
+
def endnote_begin
|
296
|
+
end
|
297
|
+
|
298
|
+
def endnote_end
|
299
|
+
end
|
300
|
+
|
301
|
+
def endnote_item(id)
|
302
|
+
puts "(#{@chapter.endnote(id).number}) #{compile_inline(@chapter.endnote(id).content)}"
|
303
|
+
end
|
287
304
|
|
288
305
|
def blankline
|
289
306
|
puts ''
|
@@ -371,6 +388,12 @@ module ReVIEW
|
|
371
388
|
app_error "unknown footnote: #{id}"
|
372
389
|
end
|
373
390
|
|
391
|
+
def inline_endnote(id)
|
392
|
+
"(#{@chapter.endnote(id).number})"
|
393
|
+
rescue KeyError
|
394
|
+
app_error "unknown endnote: #{id}"
|
395
|
+
end
|
396
|
+
|
374
397
|
def inline_bou(str)
|
375
398
|
text(str)
|
376
399
|
end
|
@@ -427,6 +450,27 @@ module ReVIEW
|
|
427
450
|
app_error "unknown headline: #{id}"
|
428
451
|
end
|
429
452
|
|
453
|
+
alias_method :inline_secref, :inline_hd
|
454
|
+
|
455
|
+
def inline_sec(id)
|
456
|
+
chapter, id = extract_chapter_id(id)
|
457
|
+
n = chapter.headline_index.number(id)
|
458
|
+
if n.present? && chapter.number && over_secnolevel?(n)
|
459
|
+
n
|
460
|
+
else
|
461
|
+
app_error "the target headline doesn't have a number: #{id}"
|
462
|
+
end
|
463
|
+
rescue KeyError
|
464
|
+
app_error "unknown headline: #{id}"
|
465
|
+
end
|
466
|
+
|
467
|
+
def inline_sectitle(id)
|
468
|
+
chapter, id = extract_chapter_id(id)
|
469
|
+
compile_inline(chapter.headline(id).caption)
|
470
|
+
rescue KeyError
|
471
|
+
app_error "unknown headline: #{id}"
|
472
|
+
end
|
473
|
+
|
430
474
|
def inline_column(id)
|
431
475
|
m = /\A([^|]+)\|(.+)/.match(id)
|
432
476
|
if m && m[1]
|
@@ -512,8 +556,8 @@ module ReVIEW
|
|
512
556
|
params = metric.split(/,\s*/)
|
513
557
|
results = []
|
514
558
|
params.each do |param|
|
515
|
-
if
|
516
|
-
next unless
|
559
|
+
if /\A.+?::/.match?(param)
|
560
|
+
next unless /\A#{type}::/.match?(param)
|
517
561
|
|
518
562
|
param.sub!(/\A#{type}::/, '')
|
519
563
|
end
|
@@ -644,7 +688,17 @@ EOTGNUPLOT
|
|
644
688
|
ext = 'eps'
|
645
689
|
file_path.sub!(/\.pdf\Z/, '.eps')
|
646
690
|
end
|
647
|
-
|
691
|
+
plant_path = nil
|
692
|
+
if File.exist?('plantuml.jar')
|
693
|
+
plant_path = 'plantuml.jar'
|
694
|
+
elsif File.exist?('/usr/share/plantuml/plantuml.jar')
|
695
|
+
plant_path = '/usr/share/plantuml/plantuml.jar'
|
696
|
+
elsif File.exist?('/usr/share/java/plantuml.jar')
|
697
|
+
plant_path = '/usr/share/java/plantuml.jar'
|
698
|
+
else
|
699
|
+
error!('missing plantuml.jar. Please put plantuml.jar at the working folder.')
|
700
|
+
end
|
701
|
+
system_graph(id, 'java', '-jar', plant_path, "-t#{ext}", '-charset', 'UTF-8', tf_path)
|
648
702
|
FileUtils.mv("#{tf_path}.#{ext}", file_path)
|
649
703
|
file_path
|
650
704
|
end
|
@@ -729,7 +783,7 @@ EOTGNUPLOT
|
|
729
783
|
def beginchild
|
730
784
|
@children ||= []
|
731
785
|
unless previous_list_type
|
732
|
-
app_error "//beginchild is shown, but previous element isn't ul, ol, or dl"
|
786
|
+
app_error "#{@location}: //beginchild is shown, but previous element isn't ul, ol, or dl"
|
733
787
|
end
|
734
788
|
puts "\x01→#{previous_list_type}←\x01"
|
735
789
|
@children.push(previous_list_type)
|
@@ -737,7 +791,7 @@ EOTGNUPLOT
|
|
737
791
|
|
738
792
|
def endchild
|
739
793
|
if @children.nil? || @children.empty?
|
740
|
-
app_error "//endchild is shown, but any opened //beginchild doesn't exist"
|
794
|
+
app_error "#{@location}: //endchild is shown, but any opened //beginchild doesn't exist"
|
741
795
|
else
|
742
796
|
puts "\x01→/#{@children.pop}←\x01"
|
743
797
|
end
|
data/lib/review/catalog.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'date'
|
2
3
|
|
3
4
|
module ReVIEW
|
4
5
|
class Catalog
|
5
6
|
def initialize(file)
|
6
|
-
if file.respond_to?(:read)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
@yaml = if file.respond_to?(:read)
|
8
|
+
YAMLLoader.safe_load(file.read)
|
9
|
+
else ## as Object
|
10
|
+
file
|
11
|
+
end
|
11
12
|
@yaml ||= {}
|
12
13
|
end
|
13
14
|
|
data/lib/review/compiler.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2009-
|
1
|
+
# Copyright (c) 2009-2022 Minero Aoki, Kenshi Muto
|
2
2
|
# Copyright (c) 2002-2007 Minero Aoki
|
3
3
|
#
|
4
4
|
# This program is free software.
|
@@ -44,7 +44,7 @@ module ReVIEW
|
|
44
44
|
|
45
45
|
def non_escaped_commands
|
46
46
|
if @builder.highlight?
|
47
|
-
%i[list emlist listnum emlistnum cmd]
|
47
|
+
%i[list emlist listnum emlistnum cmd source]
|
48
48
|
else
|
49
49
|
[]
|
50
50
|
end
|
@@ -71,7 +71,7 @@ module ReVIEW
|
|
71
71
|
attr_reader :name
|
72
72
|
|
73
73
|
def check_args(args)
|
74
|
-
unless @argc_spec === args.size
|
74
|
+
unless @argc_spec === args.size # rubocop:disable Style/CaseEquality
|
75
75
|
raise CompileError, "wrong # of parameters (block command //#{@name}, expect #{@argc_spec} but #{args.size})"
|
76
76
|
end
|
77
77
|
|
@@ -196,6 +196,8 @@ module ReVIEW
|
|
196
196
|
defminicolumn :notice, 0..1
|
197
197
|
|
198
198
|
defsingle :footnote, 2
|
199
|
+
defsingle :endnote, 2
|
200
|
+
defsingle :printendnotes, 0
|
199
201
|
defsingle :noindent, 0
|
200
202
|
defsingle :blankline, 0
|
201
203
|
defsingle :pagebreak, 0
|
@@ -220,6 +222,7 @@ module ReVIEW
|
|
220
222
|
definline :table
|
221
223
|
definline :eq
|
222
224
|
definline :fn
|
225
|
+
definline :endnote
|
223
226
|
definline :kw
|
224
227
|
definline :ruby
|
225
228
|
definline :bou
|
@@ -229,6 +232,9 @@ module ReVIEW
|
|
229
232
|
definline :code
|
230
233
|
definline :bib
|
231
234
|
definline :hd
|
235
|
+
definline :secref
|
236
|
+
definline :sec
|
237
|
+
definline :sectitle
|
232
238
|
definline :href
|
233
239
|
definline :recipe
|
234
240
|
definline :column
|
@@ -464,7 +470,7 @@ module ReVIEW
|
|
464
470
|
def compile_ulist(f)
|
465
471
|
level = 0
|
466
472
|
f.while_match(/\A\s+\*|\A\#@/) do |line|
|
467
|
-
next if
|
473
|
+
next if /\A\#@/.match?(line)
|
468
474
|
|
469
475
|
buf = [text(line.sub(/\*+/, '').strip)]
|
470
476
|
f.while_match(/\A\s+(?!\*)\S/) do |cont|
|
@@ -507,7 +513,7 @@ module ReVIEW
|
|
507
513
|
def compile_olist(f)
|
508
514
|
@builder.ol_begin
|
509
515
|
f.while_match(/\A\s+\d+\.|\A\#@/) do |line|
|
510
|
-
next if
|
516
|
+
next if /\A\#@/.match?(line)
|
511
517
|
|
512
518
|
num = line.match(/(\d+)\./)[1]
|
513
519
|
buf = [text(line.sub(/\d+\./, '').strip)]
|
@@ -569,7 +575,7 @@ module ReVIEW
|
|
569
575
|
f.until_match(%r{\A//\}}) do |line|
|
570
576
|
if ignore_inline
|
571
577
|
buf.push(line.chomp)
|
572
|
-
elsif line
|
578
|
+
elsif !/\A\#@/.match?(line)
|
573
579
|
buf.push(text(line.rstrip, true))
|
574
580
|
end
|
575
581
|
end
|
@@ -640,7 +646,7 @@ module ReVIEW
|
|
640
646
|
str.gsub(/@<(\w+)>([$|])(.+?)(\2)/) do
|
641
647
|
op = $1
|
642
648
|
arg = $3
|
643
|
-
if
|
649
|
+
if /[\x01\x02\x03\x04]/.match?(arg)
|
644
650
|
error "invalid character in '#{str}'", location: location
|
645
651
|
end
|
646
652
|
replaced = arg.tr('@', "\x01").tr('\\', "\x02").tr('{', "\x03").tr('}', "\x04")
|
@@ -668,17 +674,17 @@ module ReVIEW
|
|
668
674
|
end
|
669
675
|
result = ''
|
670
676
|
until words.empty?
|
671
|
-
if in_non_escaped_command? && block_mode
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
677
|
+
result << if in_non_escaped_command? && block_mode
|
678
|
+
revert_replace_fence(words.shift)
|
679
|
+
else
|
680
|
+
@builder.nofunc_text(revert_replace_fence(words.shift))
|
681
|
+
end
|
676
682
|
break if words.empty?
|
677
683
|
|
678
684
|
result << compile_inline(revert_replace_fence(words.shift.gsub(/\\\}/, '}').gsub(/\\\\/, '\\')))
|
679
685
|
end
|
680
686
|
result
|
681
|
-
rescue => e
|
687
|
+
rescue StandardError => e
|
682
688
|
error e.message, location: location
|
683
689
|
end
|
684
690
|
public :text # called from builder
|
@@ -693,7 +699,7 @@ module ReVIEW
|
|
693
699
|
end
|
694
700
|
|
695
701
|
@builder.__send__("inline_#{op}", arg)
|
696
|
-
rescue => e
|
702
|
+
rescue StandardError => e
|
697
703
|
error e.message, location: location
|
698
704
|
@builder.nofunc_text(str)
|
699
705
|
end
|
data/lib/review/configure.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2012-
|
2
|
+
# Copyright (c) 2012-2022 Masanori Kado, Masayoshi Takahashi, Kenshi Muto
|
3
3
|
#
|
4
4
|
# This program is free software.
|
5
5
|
# You can distribute or modify this program under the terms of
|
@@ -141,6 +141,9 @@ module ReVIEW
|
|
141
141
|
'force_include_images' => [],
|
142
142
|
'cover_linear' => nil,
|
143
143
|
'back_footnote' => nil
|
144
|
+
},
|
145
|
+
'textmaker' => {
|
146
|
+
'th_bold' => nil
|
144
147
|
}
|
145
148
|
]
|
146
149
|
conf.maker = nil
|
@@ -155,7 +158,7 @@ module ReVIEW
|
|
155
158
|
begin
|
156
159
|
loader = ReVIEW::YAMLLoader.new
|
157
160
|
conf.deep_merge!(loader.load_file(yamlfile))
|
158
|
-
rescue => e
|
161
|
+
rescue StandardError => e
|
159
162
|
raise ReVIEW::ConfigError, "yaml error #{e.message}"
|
160
163
|
end
|
161
164
|
end
|
data/lib/review/epub2html.rb
CHANGED
@@ -13,7 +13,7 @@ require 'review/version'
|
|
13
13
|
|
14
14
|
begin
|
15
15
|
require 'cgi/escape'
|
16
|
-
rescue
|
16
|
+
rescue StandardError
|
17
17
|
require 'cgi/util'
|
18
18
|
end
|
19
19
|
|
@@ -62,10 +62,10 @@ EOT
|
|
62
62
|
def parse_epub(epubname)
|
63
63
|
Zip::File.open(epubname) do |zio|
|
64
64
|
zio.each do |entry|
|
65
|
-
if
|
65
|
+
if /.+\.opf\Z/.match?(entry.name)
|
66
66
|
opf = entry.get_input_stream.read
|
67
67
|
@opfxml = REXML::Document.new(opf)
|
68
|
-
elsif
|
68
|
+
elsif /.+\.x?html\Z/.match?(entry.name)
|
69
69
|
@htmls[entry.name.sub('OEBPS/', '')] = entry.get_input_stream.read.force_encoding('utf-8')
|
70
70
|
end
|
71
71
|
end
|
@@ -107,15 +107,15 @@ EOT
|
|
107
107
|
end
|
108
108
|
|
109
109
|
file, anc = href.split('#', 2)
|
110
|
-
if anc
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
110
|
+
anc = if anc
|
111
|
+
if file.empty?
|
112
|
+
"#{sanitize(fname)}_#{sanitize(anc)}"
|
113
|
+
else
|
114
|
+
"#{sanitize(file)}_#{sanitize(anc)}"
|
115
|
+
end
|
116
|
+
else
|
117
|
+
sanitize(file)
|
118
|
+
end
|
119
119
|
|
120
120
|
e.attributes['href'] = "##{anc}"
|
121
121
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# = epubcommon.rb -- super class for EPUBv2 and EPUBv3
|
2
2
|
#
|
3
|
-
# Copyright (c) 2010-
|
3
|
+
# Copyright (c) 2010-2022 Kenshi Muto and Masayoshi Takahashi
|
4
4
|
#
|
5
5
|
# This program is free software.
|
6
6
|
# You can distribute or modify this program under the terms of
|
@@ -27,6 +27,7 @@ module ReVIEW
|
|
27
27
|
@contents = producer.contents
|
28
28
|
@body_ext = nil
|
29
29
|
@logger = ReVIEW.logger
|
30
|
+
@workdir = nil
|
30
31
|
end
|
31
32
|
|
32
33
|
attr_reader :config
|
@@ -36,7 +37,8 @@ module ReVIEW
|
|
36
37
|
CGI.escapeHTML(str)
|
37
38
|
end
|
38
39
|
|
39
|
-
def produce(
|
40
|
+
def produce(_epubfile, _basedir, _tmpdir, base_dir:)
|
41
|
+
@workdir = base_dir
|
40
42
|
raise NotImplementedError # should be overridden
|
41
43
|
end
|
42
44
|
|
@@ -70,7 +72,7 @@ module ReVIEW
|
|
70
72
|
item = contents.find { |content| content.coverimage?(config['coverimage']) }
|
71
73
|
|
72
74
|
unless item
|
73
|
-
raise "coverimage #{config['coverimage']} not found. Abort."
|
75
|
+
raise ApplicationError, "coverimage #{config['coverimage']} not found. Abort."
|
74
76
|
end
|
75
77
|
|
76
78
|
%Q( <meta name="cover" content="#{item.id}"/>\n)
|
@@ -99,27 +101,43 @@ module ReVIEW
|
|
99
101
|
end
|
100
102
|
end
|
101
103
|
|
104
|
+
def template_name(localfile: 'layout.html.erb', systemfile: nil)
|
105
|
+
if @workdir
|
106
|
+
layoutfile = File.join(@workdir, 'layouts', localfile)
|
107
|
+
if File.exist?(layoutfile)
|
108
|
+
return layoutfile
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
if systemfile
|
113
|
+
return systemfile
|
114
|
+
end
|
115
|
+
|
116
|
+
if config['htmlversion'].to_i == 5
|
117
|
+
'./html/layout-html5.html.erb'
|
118
|
+
else
|
119
|
+
'./html/layout-xhtml1.html.erb'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
102
123
|
# Return cover content.
|
103
124
|
# If Producer#config["coverimage"] is defined, it will be used for
|
104
125
|
# the cover image.
|
105
126
|
def cover
|
106
|
-
@body_ext = config['epubversion'] >= 3 ? %Q( epub:type="cover") :
|
127
|
+
@body_ext = config['epubversion'] >= 3 ? %Q( epub:type="cover") : nil
|
107
128
|
|
108
129
|
if config['coverimage']
|
109
130
|
@coverimage_src = coverimage
|
110
|
-
raise "coverimage #{config['coverimage']} not found. Abort." unless @coverimage_src
|
131
|
+
raise ApplicationError, "coverimage #{config['coverimage']} not found. Abort." unless @coverimage_src
|
111
132
|
end
|
112
|
-
@body = ReVIEW::Template.generate(path: '
|
133
|
+
@body = ReVIEW::Template.generate(path: template_name(localfile: '_cover.html.erb', systemfile: 'html/_cover.html.erb'), binding: binding)
|
113
134
|
|
114
135
|
@title = h(config.name_of('title'))
|
115
136
|
@language = config['language']
|
116
137
|
@stylesheets = config['stylesheet']
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
'./html/layout-xhtml1.html.erb'
|
121
|
-
end
|
122
|
-
ReVIEW::Template.generate(path: template_path, binding: binding)
|
138
|
+
ret = ReVIEW::Template.generate(path: template_name, binding: binding)
|
139
|
+
@body_ext = nil
|
140
|
+
ret
|
123
141
|
end
|
124
142
|
|
125
143
|
# Return title (copying) content.
|
@@ -138,16 +156,11 @@ module ReVIEW
|
|
138
156
|
if config.names_of('pbl')
|
139
157
|
@publisher_str = join_with_separator(config.names_of('pbl'), ReVIEW::I18n.t('names_splitter'))
|
140
158
|
end
|
141
|
-
@body = ReVIEW::Template.generate(path: './html/_titlepage.html.erb', binding: binding)
|
159
|
+
@body = ReVIEW::Template.generate(path: template_name(localfile: '_titlepage.html.erb', systemfile: './html/_titlepage.html.erb'), binding: binding)
|
142
160
|
|
143
161
|
@language = config['language']
|
144
162
|
@stylesheets = config['stylesheet']
|
145
|
-
|
146
|
-
'./html/layout-html5.html.erb'
|
147
|
-
else
|
148
|
-
'./html/layout-xhtml1.html.erb'
|
149
|
-
end
|
150
|
-
ReVIEW::Template.generate(path: template_path, binding: binding)
|
163
|
+
ReVIEW::Template.generate(path: template_name, binding: binding)
|
151
164
|
end
|
152
165
|
|
153
166
|
# Return colophon content.
|
@@ -155,24 +168,19 @@ module ReVIEW
|
|
155
168
|
@title = h(ReVIEW::I18n.t('colophontitle'))
|
156
169
|
@isbn_hyphen = isbn_hyphen
|
157
170
|
|
158
|
-
@body = ReVIEW::Template.generate(path: './html/_colophon.html.erb', binding: binding)
|
171
|
+
@body = ReVIEW::Template.generate(path: template_name(localfile: '_colophon.html.erb', systemfile: './html/_colophon.html.erb'), binding: binding)
|
159
172
|
|
160
173
|
@language = config['language']
|
161
174
|
@stylesheets = config['stylesheet']
|
162
|
-
|
163
|
-
'./html/layout-html5.html.erb'
|
164
|
-
else
|
165
|
-
'./html/layout-xhtml1.html.erb'
|
166
|
-
end
|
167
|
-
ReVIEW::Template.generate(path: template_path, binding: binding)
|
175
|
+
ReVIEW::Template.generate(path: template_name, binding: binding)
|
168
176
|
end
|
169
177
|
|
170
178
|
def isbn_hyphen
|
171
179
|
str = config['isbn'].to_s
|
172
180
|
|
173
|
-
if
|
181
|
+
if /\A\d{10}\Z/.match?(str)
|
174
182
|
"#{str[0..0]}-#{str[1..5]}-#{str[6..8]}-#{str[9..9]}"
|
175
|
-
elsif
|
183
|
+
elsif /\A\d{13}\Z/.match?(str)
|
176
184
|
"#{str[0..2]}-#{str[3..3]}-#{str[4..8]}-#{str[9..11]}-#{str[12..12]}"
|
177
185
|
end
|
178
186
|
end
|
@@ -184,9 +192,9 @@ module ReVIEW
|
|
184
192
|
items.each_with_index do |item, rev|
|
185
193
|
editstr = edit == 0 ? ReVIEW::I18n.t('first_edition') : ReVIEW::I18n.t('nth_edition', (edit + 1).to_s)
|
186
194
|
revstr = ReVIEW::I18n.t('nth_impression', (rev + 1).to_s)
|
187
|
-
if
|
195
|
+
if /\A\d+-\d+-\d+\Z/.match?(item)
|
188
196
|
@col_history << ReVIEW::I18n.t('published_by1', [date_to_s(item), editstr + revstr])
|
189
|
-
elsif
|
197
|
+
elsif /\A(\d+-\d+-\d+)[\s ](.+)/.match?(item)
|
190
198
|
# custom date with string
|
191
199
|
item.match(/\A(\d+-\d+-\d+)[\s ](.+)/) do |m|
|
192
200
|
@col_history << ReVIEW::I18n.t('published_by3', [date_to_s(m[1]), m[2]])
|
@@ -199,7 +207,7 @@ module ReVIEW
|
|
199
207
|
end
|
200
208
|
end
|
201
209
|
|
202
|
-
ReVIEW::Template.generate(path: './html/_colophon_history.html.erb', binding: binding)
|
210
|
+
ReVIEW::Template.generate(path: template_name(localfile: '_colophon_history.html.erb', systemfile: './html/_colophon_history.html.erb'), binding: binding)
|
203
211
|
end
|
204
212
|
|
205
213
|
def date_to_s(date)
|
@@ -211,22 +219,16 @@ module ReVIEW
|
|
211
219
|
# Return own toc content.
|
212
220
|
def mytoc
|
213
221
|
@title = h(ReVIEW::I18n.t('toctitle'))
|
214
|
-
|
215
222
|
@body = %Q( <h1 class="toc-title">#{h(ReVIEW::I18n.t('toctitle'))}</h1>\n)
|
216
|
-
if config['epubmaker']['flattoc'].nil?
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
223
|
+
@body << if config['epubmaker']['flattoc'].nil?
|
224
|
+
hierarchy_ncx('ul')
|
225
|
+
else
|
226
|
+
flat_ncx('ul', config['epubmaker']['flattocindent'])
|
227
|
+
end
|
221
228
|
|
222
229
|
@language = config['language']
|
223
230
|
@stylesheets = config['stylesheet']
|
224
|
-
|
225
|
-
'./html/layout-html5.html.erb'
|
226
|
-
else
|
227
|
-
'./html/layout-xhtml1.html.erb'
|
228
|
-
end
|
229
|
-
ReVIEW::Template.generate(path: template_path, binding: binding)
|
231
|
+
ReVIEW::Template.generate(path: template_name, binding: binding)
|
230
232
|
end
|
231
233
|
|
232
234
|
def hierarchy_ncx(type)
|
@@ -334,11 +336,11 @@ module ReVIEW
|
|
334
336
|
end
|
335
337
|
|
336
338
|
contents.each do |item|
|
337
|
-
next if item.file
|
339
|
+
next if /#/.match?(item.file) # skip subgroup
|
338
340
|
|
339
341
|
fname = "#{basedir}/#{item.file}"
|
340
342
|
unless File.exist?(fname)
|
341
|
-
raise "#{fname} is not found."
|
343
|
+
raise ApplicationError, "#{fname} is not found."
|
342
344
|
end
|
343
345
|
|
344
346
|
FileUtils.mkdir_p(File.dirname("#{tmpdir}/OEBPS/#{item.file}"))
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# = epubv2.rb -- EPUB version 2 producer.
|
2
2
|
#
|
3
|
-
# Copyright (c) 2010-
|
3
|
+
# Copyright (c) 2010-2022 Kenshi Muto and Masayoshi Takahashi
|
4
4
|
#
|
5
5
|
# This program is free software.
|
6
6
|
# You can distribute or modify this program under the terms of
|
@@ -159,6 +159,7 @@ EOT
|
|
159
159
|
# +basedir+ points the directory has contents.
|
160
160
|
# +tmpdir+ defines temporary directory.
|
161
161
|
def produce(epubfile, work_dir, tmpdir, base_dir:)
|
162
|
+
@workdir = base_dir
|
162
163
|
produce_write_common(work_dir, tmpdir)
|
163
164
|
|
164
165
|
ncx_file = "#{tmpdir}/OEBPS/#{config['bookname']}.ncx"
|