review 4.1.0 → 5.2.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 +35 -0
- data/.github/workflows/ruby-win.yml +19 -9
- data/.github/workflows/ruby.yml +7 -3
- data/.rubocop.yml +138 -34
- data/NEWS.ja.md +285 -0
- data/NEWS.md +285 -1
- data/README.md +7 -6
- data/Rakefile +7 -2
- data/bin/review +2 -4
- data/bin/review-catalog-converter +4 -4
- data/bin/review-check +8 -12
- data/bin/review-checkdep +2 -5
- data/bin/review-compile +18 -34
- data/bin/review-epub2html +1 -4
- data/bin/review-epubmaker +3 -4
- data/bin/review-idgxmlmaker +1 -3
- data/bin/review-index +5 -86
- data/bin/review-init +1 -4
- data/bin/review-pdfmaker +1 -3
- data/bin/review-preproc +30 -38
- data/bin/review-textmaker +1 -3
- data/bin/review-update +1 -4
- data/bin/review-validate +4 -4
- data/bin/review-vol +5 -82
- data/bin/review-webmaker +1 -3
- data/doc/config.yml.sample +45 -11
- data/doc/config.yml.sample-simple +3 -3
- data/doc/format.ja.md +103 -13
- data/doc/format.md +104 -16
- data/doc/makeindex.ja.md +2 -2
- data/doc/pdfmaker.ja.md +42 -0
- data/doc/pdfmaker.md +41 -0
- data/doc/quickstart.ja.md +19 -6
- data/doc/quickstart.md +18 -6
- data/doc/writing_vertical.ja.md +6 -0
- data/lib/review.rb +1 -1
- data/lib/review/book.rb +2 -2
- data/lib/review/book/base.rb +67 -29
- data/lib/review/book/bib.rb +21 -0
- data/lib/review/book/book_unit.rb +158 -0
- data/lib/review/book/chapter.rb +33 -26
- data/lib/review/book/index.rb +24 -185
- data/lib/review/book/index/item.rb +7 -1
- data/lib/review/book/page_metric.rb +7 -7
- data/lib/review/book/part.rb +26 -11
- data/lib/review/book/volume.rb +5 -5
- data/lib/review/builder.rb +121 -52
- data/lib/review/call_hook.rb +20 -0
- data/lib/review/catalog.rb +3 -2
- data/lib/review/compiler.rb +230 -111
- data/lib/review/configure.rb +91 -7
- data/lib/review/converter.rb +1 -1
- data/lib/review/epub2html.rb +6 -1
- data/lib/review/epubmaker.rb +124 -152
- data/lib/review/epubmaker/content.rb +113 -0
- data/lib/review/epubmaker/epubcommon.rb +372 -0
- data/lib/review/epubmaker/epubv2.rb +178 -0
- data/lib/review/epubmaker/epubv3.rb +231 -0
- data/lib/review/epubmaker/producer.rb +167 -0
- data/lib/review/epubmaker/reviewheaderlistener.rb +12 -2
- data/lib/review/epubmaker/zip_exporter.rb +84 -0
- data/lib/review/exception.rb +13 -0
- data/lib/review/htmlbuilder.rb +176 -89
- data/lib/review/htmlutils.rb +8 -11
- data/lib/review/i18n.rb +2 -1
- data/lib/review/idgxmlbuilder.rb +165 -75
- data/lib/review/idgxmlmaker.rb +24 -28
- data/lib/review/img_math.rb +238 -0
- data/lib/review/index_builder.rb +645 -0
- data/lib/review/init.rb +9 -17
- data/lib/review/latexbox.rb +58 -0
- data/lib/review/latexbuilder.rb +193 -75
- data/lib/review/latexutils.rb +9 -1
- data/lib/review/lineinput.rb +112 -2
- data/lib/review/loggable.rb +27 -0
- data/lib/review/logger.rb +90 -3
- data/lib/review/makerhelper.rb +17 -188
- data/lib/review/markdownbuilder.rb +54 -4
- data/lib/review/pdfmaker.rb +76 -84
- data/lib/review/plaintextbuilder.rb +106 -22
- data/lib/review/preprocessor.rb +107 -303
- data/lib/review/preprocessor/directive.rb +35 -0
- data/lib/review/preprocessor/line.rb +34 -0
- data/lib/review/preprocessor/repository.rb +177 -0
- data/lib/review/rstbuilder.rb +27 -8
- data/lib/review/sec_counter.rb +14 -0
- data/lib/review/template.rb +11 -1
- data/lib/review/textmaker.rb +27 -32
- data/lib/review/textutils.rb +3 -12
- data/lib/review/tocprinter.rb +242 -97
- data/lib/review/topbuilder.rb +98 -31
- data/lib/review/update.rb +12 -13
- data/lib/review/version.rb +1 -1
- data/lib/review/volumeprinter.rb +97 -0
- data/lib/review/webmaker.rb +40 -47
- data/lib/review/webtocprinter.rb +39 -35
- data/lib/review/yamlloader.rb +2 -1
- data/review.gemspec +5 -3
- data/samples/sample-book/src/config-epub2.yml +1 -1
- data/samples/sample-book/src/config.yml +3 -3
- data/samples/sample-book/src/lib/tasks/review.rake +19 -1
- data/samples/sample-book/src/lib/tasks/z01_copy_sty.rake +2 -1
- data/samples/syntax-book/Gemfile +1 -1
- data/samples/syntax-book/ch01.re +1 -1
- data/samples/syntax-book/ch02.re +21 -6
- data/samples/syntax-book/ch03.re +1 -1
- data/samples/syntax-book/config.yml +1 -1
- data/samples/syntax-book/images/img3-2.png +0 -0
- data/samples/syntax-book/lib/tasks/z01_copy_sty.rake +2 -1
- data/templates/html/_colophon.html.erb +23 -0
- data/templates/html/_colophon_history.html.erb +9 -0
- data/templates/html/_cover.html.erb +10 -0
- data/templates/html/_part_body.html.erb +6 -0
- data/templates/html/_titlepage.html.erb +20 -0
- data/templates/html/layout-html5.html.erb +6 -0
- data/templates/html/layout-xhtml1.html.erb +6 -0
- data/templates/latex/config.erb +35 -23
- data/templates/latex/review-jlreq/README.md +3 -1
- data/templates/latex/review-jlreq/review-base.sty +36 -23
- data/templates/latex/review-jlreq/review-jlreq.cls +18 -25
- data/templates/latex/review-jlreq/review-style.sty +6 -1
- data/templates/latex/review-jlreq/review-tcbox.sty +348 -0
- data/templates/latex/review-jlreq/reviewmacro.sty +5 -0
- data/templates/latex/review-jsbook/README.md +7 -5
- data/templates/latex/review-jsbook/review-base.sty +40 -24
- data/templates/latex/review-jsbook/review-jsbook.cls +13 -3
- data/templates/latex/review-jsbook/review-style.sty +6 -1
- data/templates/latex/review-jsbook/review-tcbox.sty +348 -0
- data/templates/latex/review-jsbook/reviewmacro.sty +5 -0
- data/templates/opf/epubv2.opf.erb +7 -7
- data/templates/opf/epubv3.opf.erb +7 -7
- data/templates/opf/opf_manifest_epubv2.opf.erb +10 -0
- data/templates/opf/opf_manifest_epubv3.opf.erb +10 -0
- data/templates/opf/opf_metainfo_epubv2.opf.erb +17 -0
- data/templates/opf/opf_metainfo_epubv3.opf.erb +49 -0
- data/templates/opf/opf_tocx_epubv2.opf.erb +9 -0
- data/templates/opf/opf_tocx_epubv3.opf.erb +17 -0
- data/templates/web/html/layout-html5.html.erb +9 -8
- data/templates/web/html/layout-xhtml1.html.erb +6 -0
- data/test/assets/header_listener.html +35 -0
- data/test/assets/img_math/img1.png +0 -0
- data/test/assets/img_math/img2.png +0 -0
- data/test/assets/img_math/img3.png +0 -0
- data/test/assets/syntax_book_index_detail.txt +58 -0
- data/test/assets/test_template.tex +6 -3
- data/test/assets/test_template_backmatter.tex +6 -3
- data/test/book_test_helper.rb +11 -5
- data/test/run_test.rb +1 -1
- data/test/test_book.rb +54 -63
- data/test/test_book_chapter.rb +95 -54
- data/test/test_book_part.rb +3 -3
- data/test/test_builder.rb +29 -20
- data/test/test_catalog_converter_cmd.rb +1 -1
- data/test/test_converter.rb +1 -0
- data/test/test_epub3maker.rb +170 -126
- data/test/test_epubmaker.rb +254 -129
- data/test/test_epubmaker_cmd.rb +15 -4
- data/test/test_helper.rb +12 -5
- data/test/test_htmlbuilder.rb +926 -76
- data/test/test_htmlutils.rb +0 -12
- data/test/test_i18n.rb +33 -33
- data/test/test_idgxmlbuilder.rb +531 -20
- data/test/test_idgxmlmaker_cmd.rb +7 -3
- data/test/test_img_math.rb +111 -0
- data/test/test_index.rb +62 -52
- data/test/test_indexbuilder.rb +52 -0
- data/test/test_latexbuilder.rb +891 -20
- data/test/test_latexbuilder_v2.rb +56 -10
- data/test/test_lineinput.rb +20 -93
- data/test/test_logger.rb +7 -7
- data/test/test_makerhelper.rb +0 -12
- data/test/test_markdownbuilder.rb +32 -0
- data/test/test_pdfmaker.rb +100 -11
- data/test/test_pdfmaker_cmd.rb +3 -3
- data/test/test_plaintextbuilder.rb +546 -32
- data/test/test_preprocessor.rb +188 -1
- data/test/test_review_ext.rb +2 -1
- data/test/test_reviewheaderlistener.rb +49 -0
- data/test/test_rstbuilder.rb +25 -1
- data/test/test_sec_counter.rb +156 -0
- data/test/test_template.rb +12 -2
- data/test/test_textmaker_cmd.rb +5 -1
- data/test/test_tocprinter.rb +46 -0
- data/test/test_topbuilder.rb +324 -20
- data/test/test_update.rb +44 -44
- data/test/test_webtocprinter.rb +75 -43
- data/test/test_zip_exporter.rb +5 -6
- data/vendor/gentombow/LICENSE +1 -1
- data/vendor/gentombow/Makefile +0 -1
- data/vendor/gentombow/bounddvi-en.pdf +0 -0
- data/vendor/gentombow/bounddvi-en.tex +1 -0
- data/vendor/gentombow/bounddvi.pdf +0 -0
- data/vendor/gentombow/bounddvi.sty +30 -7
- data/vendor/gentombow/bounddvi.tex +1 -0
- data/vendor/gentombow/create_archive.sh +1 -0
- data/vendor/gentombow/gentombow-ja.pdf +0 -0
- data/vendor/gentombow/gentombow-ja.tex +9 -0
- data/vendor/gentombow/gentombow.pdf +0 -0
- data/vendor/gentombow/gentombow.sty +32 -10
- data/vendor/gentombow/gentombow.tex +8 -0
- data/vendor/gentombow/tests/gentombow-01-pdfx.tex +8 -0
- data/vendor/gentombow/tests/gentombow-02-pdfx.tex +8 -0
- data/vendor/jsclasses/Makefile +3 -2
- data/vendor/jsclasses/create_archive.sh +5 -5
- data/vendor/jsclasses/jis/Makefile +3 -2
- data/vendor/jsclasses/jis/jsarticle.cls +22 -18
- data/vendor/jsclasses/jis/jsbook.cls +22 -18
- data/vendor/jsclasses/jis/jsclasses.dtx +94 -13
- data/vendor/jsclasses/jis/jsclasses.ins +15 -5
- data/vendor/jsclasses/jis/jslogo.ins +9 -0
- data/vendor/jsclasses/jis/jslogo.sty +1 -13
- data/vendor/jsclasses/jis/jspf.cls +22 -18
- data/vendor/jsclasses/jis/jsreport.cls +22 -18
- data/vendor/jsclasses/jis/jsverb.ins +9 -0
- data/vendor/jsclasses/jis/jsverb.sty +1 -13
- data/vendor/jsclasses/jis/kiyou.cls +22 -18
- data/vendor/jsclasses/jis/minijs.sty +65 -22
- data/vendor/jsclasses/jis/okumacro.ins +9 -0
- data/vendor/jsclasses/jis/okumacro.sty +1 -13
- data/vendor/jsclasses/jis/okuverb.ins +9 -0
- data/vendor/jsclasses/jis/okuverb.sty +1 -13
- data/vendor/jsclasses/jis/winjis.sty +23 -19
- data/vendor/jsclasses/jsarticle.cls +22 -18
- data/vendor/jsclasses/jsbook.cls +22 -18
- data/vendor/jsclasses/jsclasses.dtx +94 -13
- data/vendor/jsclasses/jsclasses.ins +15 -5
- data/vendor/jsclasses/jsclasses.pdf +0 -0
- data/vendor/jsclasses/jslogo.ins +9 -0
- data/vendor/jsclasses/jslogo.pdf +0 -0
- data/vendor/jsclasses/jslogo.sty +1 -13
- data/vendor/jsclasses/jspf.cls +22 -18
- data/vendor/jsclasses/jsreport.cls +22 -18
- data/vendor/jsclasses/jsverb.ins +9 -0
- data/vendor/jsclasses/jsverb.pdf +0 -0
- data/vendor/jsclasses/jsverb.sty +1 -13
- data/vendor/jsclasses/kiyou.cls +22 -18
- data/vendor/jsclasses/minijs.sty +68 -22
- data/vendor/jsclasses/okumacro.ins +9 -0
- data/vendor/jsclasses/okumacro.pdf +0 -0
- data/vendor/jsclasses/okumacro.sty +1 -13
- data/vendor/jsclasses/okuverb.ins +9 -0
- data/vendor/jsclasses/okuverb.pdf +0 -0
- data/vendor/jsclasses/okuverb.sty +1 -13
- data/vendor/jsclasses/tests/relfont.tex +10 -0
- data/vendor/jsclasses/winjis.sty +23 -19
- metadata +106 -22
- data/.rubocop_todo.yml +0 -7
- data/lib/epubmaker.rb +0 -23
- data/lib/epubmaker/content.rb +0 -110
- data/lib/epubmaker/epubcommon.rb +0 -441
- data/lib/epubmaker/epubv2.rb +0 -143
- data/lib/epubmaker/epubv3.rb +0 -233
- data/lib/epubmaker/producer.rb +0 -375
- data/lib/epubmaker/zip_exporter.rb +0 -81
- data/lib/lineinput.rb +0 -155
- data/lib/review/book/compilable.rb +0 -178
- data/lib/review/tocparser.rb +0 -275
- data/test/test_tocparser.rb +0 -25
@@ -0,0 +1,178 @@
|
|
1
|
+
# = epubv2.rb -- EPUB version 2 producer.
|
2
|
+
#
|
3
|
+
# Copyright (c) 2010-2017 Kenshi Muto and Masayoshi Takahashi
|
4
|
+
#
|
5
|
+
# This program is free software.
|
6
|
+
# You can distribute or modify this program under the terms of
|
7
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
8
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'review/epubmaker/epubcommon'
|
12
|
+
require 'review/epubmaker/zip_exporter'
|
13
|
+
require 'review/call_hook'
|
14
|
+
|
15
|
+
module ReVIEW
|
16
|
+
class EPUBMaker
|
17
|
+
# EPUBv2 is EPUB version 2 producer.
|
18
|
+
class EPUBv2 < EPUBCommon
|
19
|
+
include ReVIEW::CallHook
|
20
|
+
|
21
|
+
DC_ITEMS = %w[title language date type format source description relation coverage subject rights]
|
22
|
+
CREATOR_ATTRIBUTES = %w[aut a-adp a-ann a-arr a-art a-asn a-aqt a-aft a-aui a-ant a-bkp a-clb a-cmm a-dsr a-edt a-ill a-lyr a-mdc a-mus a-nrt a-oth a-pht a-prt a-red a-rev a-spn a-ths a-trc a-trl]
|
23
|
+
CONTRIBUTER_ATTRIBUTES = %w[adp ann arr art asn aqt aft aui ant bkp clb cmm dsr edt ill lyr mdc mus nrt oth pht prt red rev spn ths trc trl]
|
24
|
+
|
25
|
+
# Construct object with parameter hash +config+ and message resource hash +res+.
|
26
|
+
def initialize(producer) # rubocop:disable Lint/UselessMethodDefinition
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return opf file content.
|
31
|
+
def opf
|
32
|
+
@opf_metainfo = opf_metainfo
|
33
|
+
@opf_coverimage = opf_coverimage
|
34
|
+
@opf_manifest = opf_manifest
|
35
|
+
@opf_toc = opf_tocx
|
36
|
+
|
37
|
+
ReVIEW::Template.generate(path: './opf/epubv2.opf.erb', binding: binding)
|
38
|
+
end
|
39
|
+
|
40
|
+
def opf_metainfo
|
41
|
+
@dc_items = DC_ITEMS.map do |item|
|
42
|
+
if config[item]
|
43
|
+
if config[item].is_a?(Array)
|
44
|
+
config.names_of(item).map { |_v| { tag: "dc:#{item}", val: item_sub } }
|
45
|
+
else
|
46
|
+
{ tag: "dc:#{item}", val: config.name_of(item).to_s }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end.flatten.compact
|
50
|
+
|
51
|
+
# creator (should be array)
|
52
|
+
@creators = CREATOR_ATTRIBUTES.map do |role|
|
53
|
+
if config[role]
|
54
|
+
config.names_of(role).map { |v| { role: role, val: v } }
|
55
|
+
end
|
56
|
+
end.flatten.compact
|
57
|
+
|
58
|
+
# contributor (should be array)
|
59
|
+
@contributers = CONTRIBUTER_ATTRIBUTES.map do |role|
|
60
|
+
if config[role]
|
61
|
+
config.names_of(role).map { |v| { role: role, val: v } }
|
62
|
+
end
|
63
|
+
end.flatten.compact
|
64
|
+
|
65
|
+
ReVIEW::Template.generate(path: './opf/opf_metainfo_epubv2.opf.erb', binding: binding)
|
66
|
+
end
|
67
|
+
|
68
|
+
def opf_manifest
|
69
|
+
@items = contents.find_all { |item| item.file !~ /#/ } # skip subgroup
|
70
|
+
|
71
|
+
ReVIEW::Template.generate(path: './opf/opf_manifest_epubv2.opf.erb', binding: binding)
|
72
|
+
end
|
73
|
+
|
74
|
+
def opf_tocx
|
75
|
+
@cover_linear = if config['epubmaker']['cover_linear'] && config['epubmaker']['cover_linear'] != 'no'
|
76
|
+
'yes'
|
77
|
+
else
|
78
|
+
'no'
|
79
|
+
end
|
80
|
+
@ncx_contents = contents.find_all { |content| content.media =~ /xhtml\+xml/ } # skip non XHTML
|
81
|
+
|
82
|
+
ReVIEW::Template.generate(path: './opf/opf_tocx_epubv2.opf.erb', binding: binding)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Return ncx content. +indentarray+ has prefix marks for each level.
|
86
|
+
def ncx(indentarray)
|
87
|
+
@ncx_isbn = ncx_isbn
|
88
|
+
@ncx_doctitle = ncx_doctitle
|
89
|
+
@ncx_navmap = ncx_navmap(indentarray)
|
90
|
+
|
91
|
+
ReVIEW::Template.generate(path: './ncx/epubv2.ncx.erb', binding: binding)
|
92
|
+
end
|
93
|
+
|
94
|
+
def ncx_isbn
|
95
|
+
uid = config['isbn'] || config['urnid']
|
96
|
+
%Q( <meta name="dtb:uid" content="#{uid}"/>\n)
|
97
|
+
end
|
98
|
+
|
99
|
+
def ncx_doctitle
|
100
|
+
<<-EOT
|
101
|
+
<docTitle>
|
102
|
+
<text>#{h(config['title'])}</text>
|
103
|
+
</docTitle>
|
104
|
+
<docAuthor>
|
105
|
+
<text>#{config['aut'].nil? ? '' : h(join_with_separator(config['aut'], ReVIEW::I18n.t('names_splitter')))}</text>
|
106
|
+
</docAuthor>
|
107
|
+
EOT
|
108
|
+
end
|
109
|
+
|
110
|
+
def ncx_navmap(indentarray)
|
111
|
+
s = <<EOT
|
112
|
+
<navMap>
|
113
|
+
<navPoint id="top" playOrder="1">
|
114
|
+
<navLabel>
|
115
|
+
<text>#{h(config['title'])}</text>
|
116
|
+
</navLabel>
|
117
|
+
<content src="#{config['cover']}"/>
|
118
|
+
</navPoint>
|
119
|
+
EOT
|
120
|
+
|
121
|
+
nav_count = 2
|
122
|
+
|
123
|
+
unless config['mytoc'].nil?
|
124
|
+
s << <<EOT
|
125
|
+
<navPoint id="toc" playOrder="#{nav_count}">
|
126
|
+
<navLabel>
|
127
|
+
<text>#{h(ReVIEW::I18n.t('toctitle'))}</text>
|
128
|
+
</navLabel>
|
129
|
+
<content src="#{config['bookname']}-toc.#{config['htmlext']}"/>
|
130
|
+
</navPoint>
|
131
|
+
EOT
|
132
|
+
nav_count += 1
|
133
|
+
end
|
134
|
+
|
135
|
+
contents.each do |item|
|
136
|
+
next if item.title.nil?
|
137
|
+
|
138
|
+
indent = indentarray.nil? ? [''] : indentarray
|
139
|
+
level = item.level.nil? ? 0 : (item.level - 1)
|
140
|
+
level = indent.size - 1 if level >= indent.size
|
141
|
+
s << <<EOT
|
142
|
+
<navPoint id="nav-#{nav_count}" playOrder="#{nav_count}">
|
143
|
+
<navLabel>
|
144
|
+
<text>#{indent[level]}#{h(item.title)}</text>
|
145
|
+
</navLabel>
|
146
|
+
<content src="#{item.file}"/>
|
147
|
+
</navPoint>
|
148
|
+
EOT
|
149
|
+
nav_count += 1
|
150
|
+
end
|
151
|
+
|
152
|
+
s << <<EOT
|
153
|
+
</navMap>
|
154
|
+
EOT
|
155
|
+
s
|
156
|
+
end
|
157
|
+
|
158
|
+
# Produce EPUB file +epubfile+.
|
159
|
+
# +basedir+ points the directory has contents.
|
160
|
+
# +tmpdir+ defines temporary directory.
|
161
|
+
def produce(epubfile, work_dir, tmpdir, base_dir:)
|
162
|
+
produce_write_common(work_dir, tmpdir)
|
163
|
+
|
164
|
+
ncx_file = "#{tmpdir}/OEBPS/#{config['bookname']}.ncx"
|
165
|
+
File.write(ncx_file, ncx(config['epubmaker']['ncxindent']))
|
166
|
+
|
167
|
+
if config['mytoc']
|
168
|
+
toc_file = "#{tmpdir}/OEBPS/#{config['bookname']}-toc.#{config['htmlext']}"
|
169
|
+
File.write(toc_file, mytoc)
|
170
|
+
end
|
171
|
+
|
172
|
+
call_hook('hook_prepack', tmpdir, base_dir: base_dir)
|
173
|
+
expoter = ReVIEW::EPUBMaker::ZipExporter.new(tmpdir, config)
|
174
|
+
expoter.export_zip(epubfile)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
# = epubv3.rb -- EPUB version 3 producer.
|
2
|
+
#
|
3
|
+
# Copyright (c) 2010-2017 Kenshi Muto
|
4
|
+
#
|
5
|
+
# This program is free software.
|
6
|
+
# You can distribute or modify this program under the terms of
|
7
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
8
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'review/epubmaker/epubcommon'
|
12
|
+
require 'review/epubmaker/zip_exporter'
|
13
|
+
require 'review/call_hook'
|
14
|
+
|
15
|
+
module ReVIEW
|
16
|
+
class EPUBMaker
|
17
|
+
# EPUBv3 is EPUB version 3 producer.
|
18
|
+
class EPUBv3 < EPUBCommon
|
19
|
+
include ReVIEW::CallHook
|
20
|
+
|
21
|
+
DC_ITEMS = %w[title language date type format source description relation coverage subject rights]
|
22
|
+
CREATOR_ATTRIBUTES = %w[a-adp a-ann a-arr a-art a-asn a-aqt a-aft a-aui a-ant a-bkp a-clb a-cmm a-csl a-dsr a-edt a-ill a-lyr a-mdc a-mus a-nrt a-oth a-pht a-prt a-red a-rev a-spn a-ths a-trc a-trl aut]
|
23
|
+
CONTRIBUTER_ATTRIBUTES = %w[adp ann arr art asn aqt aft aui ant bkp clb cmm csl dsr edt ill lyr mdc mus nrt oth pbd pbl pht prt red rev spn ths trc trl]
|
24
|
+
|
25
|
+
# Construct object with parameter hash +config+ and message resource hash +res+.
|
26
|
+
def initialize(producer)
|
27
|
+
super
|
28
|
+
@opf_prefix = {}
|
29
|
+
if config['opf_prefix'].present?
|
30
|
+
config['opf_prefix'].each { |k, v| @opf_prefix[k] = v }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Return opf file content.
|
35
|
+
def opf
|
36
|
+
@opf_metainfo = opf_metainfo
|
37
|
+
@opf_coverimage = opf_coverimage
|
38
|
+
@opf_manifest = opf_manifest
|
39
|
+
@opf_toc = opf_tocx
|
40
|
+
@package_attrs = ''
|
41
|
+
|
42
|
+
if @opf_prefix && @opf_prefix.size > 0
|
43
|
+
prefixes_str = @opf_prefix.map { |k, v| %Q(#{k}: #{v}) }.join(' ')
|
44
|
+
@package_attrs << %Q( prefix="#{prefixes_str}")
|
45
|
+
end
|
46
|
+
|
47
|
+
ReVIEW::Template.generate(path: './opf/epubv3.opf.erb', binding: binding)
|
48
|
+
end
|
49
|
+
|
50
|
+
def opf_metainfo
|
51
|
+
@dc_items = opf_dc_items
|
52
|
+
|
53
|
+
# creator (should be array)
|
54
|
+
@creators = opf_creators
|
55
|
+
|
56
|
+
# contributor (should be array)
|
57
|
+
@contributers = opf_contributers
|
58
|
+
|
59
|
+
ReVIEW::Template.generate(path: './opf/opf_metainfo_epubv3.opf.erb', binding: binding)
|
60
|
+
end
|
61
|
+
|
62
|
+
def opf_dc_items
|
63
|
+
DC_ITEMS.map do |item|
|
64
|
+
next unless config[item]
|
65
|
+
|
66
|
+
case config[item]
|
67
|
+
when Array
|
68
|
+
config[item].map.with_index do |v, i|
|
69
|
+
if v.is_a?(Hash)
|
70
|
+
{ tag: "dc:#{item}",
|
71
|
+
id: "#{item}-#{i}",
|
72
|
+
val: v['name'],
|
73
|
+
refines: v.map { |name, val| { name: name, val: val } }.delete_if { |h| h[:name] == 'name' } }
|
74
|
+
else
|
75
|
+
{ tag: "dc:#{item}", id: "#{item}-#{i}", val: v.to_s, refines: [] }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
when Hash
|
79
|
+
{ tag: "dc:#{item}",
|
80
|
+
id: item.to_s,
|
81
|
+
val: config[item]['name'],
|
82
|
+
refines: config[item].map { |name, val| { name: name, val: val } }.delete_if { |h| h[:name] == 'name' } }
|
83
|
+
else
|
84
|
+
{ tag: "dc:#{item}",
|
85
|
+
id: item.to_s,
|
86
|
+
val: config[item].to_s,
|
87
|
+
refines: [] }
|
88
|
+
end
|
89
|
+
end.flatten.compact
|
90
|
+
end
|
91
|
+
|
92
|
+
def opf_creators
|
93
|
+
CREATOR_ATTRIBUTES.map do |role|
|
94
|
+
next unless config[role]
|
95
|
+
|
96
|
+
config[role].map.with_index do |v, i|
|
97
|
+
case v
|
98
|
+
when Hash
|
99
|
+
refines = v.map { |name, val| { id: "#{role.sub('a-', '')}-#{i}", property: name.to_s, scheme: nil, val: val } }.delete_if { |h| h[:property] == 'name' }
|
100
|
+
|
101
|
+
{
|
102
|
+
id: "#{role}-#{i}",
|
103
|
+
val: v['name'],
|
104
|
+
refines: [
|
105
|
+
{ id: "#{role}-#{i}", property: 'role', scheme: 'marc:relators', val: role.sub('a-', '') }
|
106
|
+
].concat(refines)
|
107
|
+
}
|
108
|
+
else
|
109
|
+
{
|
110
|
+
id: "#{role}-#{i}",
|
111
|
+
val: v,
|
112
|
+
refines: [
|
113
|
+
{ id: "#{role}-#{i}", property: 'role', scheme: 'marc:relators', val: role.sub('a-', '') }
|
114
|
+
]
|
115
|
+
}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end.flatten.compact
|
119
|
+
end
|
120
|
+
|
121
|
+
def opf_contributers
|
122
|
+
CONTRIBUTER_ATTRIBUTES.map do |role|
|
123
|
+
next unless config[role]
|
124
|
+
|
125
|
+
config[role].map.with_index do |v, i|
|
126
|
+
case v
|
127
|
+
when Hash
|
128
|
+
refines = v.map { |name, val| { id: "#{role}-#{i}", property: name, scheme: nil, val: val } }.delete_if { |h| h[:property] == 'name' }
|
129
|
+
contributer = {
|
130
|
+
id: "#{role}-#{i}",
|
131
|
+
val: v['name'],
|
132
|
+
refines: [
|
133
|
+
{ id: "#{role}-#{i}", property: 'role', scheme: 'marc:relators', val: role }
|
134
|
+
].concat(refines)
|
135
|
+
}
|
136
|
+
else
|
137
|
+
contributer = {
|
138
|
+
id: "#{role}-#{i}",
|
139
|
+
val: v,
|
140
|
+
refines: [
|
141
|
+
{ id: "#{role}-#{i}", property: 'role', scheme: 'marc:relators', val: role }
|
142
|
+
]
|
143
|
+
}
|
144
|
+
end
|
145
|
+
if %w[prt pbl].include?(role)
|
146
|
+
contributer[:pub_id] = "pub-#{role}-#{i}"
|
147
|
+
case v
|
148
|
+
when Hash
|
149
|
+
contributer[:pub_val] = v['name']
|
150
|
+
pub_refines = v.map { |name, val| { id: "pub-#{role}-#{i}", property: name, scheme: nil, val: val } }.delete_if { |h| h[:property] == 'name' }
|
151
|
+
contributer[:pub_refines] = [
|
152
|
+
{ id: "pub-#{role}-#{i}", property: 'role', scheme: 'marc:relators', val: role }
|
153
|
+
].concat(pub_refines)
|
154
|
+
else
|
155
|
+
contributer[:pub_val] = v
|
156
|
+
contributer[:pub_refines] = [
|
157
|
+
{ id: "pub-#{role}-#{i}", property: 'role', scheme: 'marc:relators', val: 'prt' }
|
158
|
+
]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
contributer
|
163
|
+
end
|
164
|
+
end.flatten.compact
|
165
|
+
end
|
166
|
+
|
167
|
+
def opf_manifest
|
168
|
+
if config['coverimage']
|
169
|
+
@coverimage = contents.find { |content| content.coverimage?(config['coverimage']) } # @coverimage can be nil
|
170
|
+
end
|
171
|
+
@items = if @coverimage
|
172
|
+
contents.find_all { |content| content.file !~ /#/ && content.id != @coverimage.id } # skip subgroup, or @coverimage
|
173
|
+
else
|
174
|
+
contents.find_all { |content| content.file !~ /#/ }
|
175
|
+
end
|
176
|
+
|
177
|
+
ReVIEW::Template.generate(path: './opf/opf_manifest_epubv3.opf.erb', binding: binding)
|
178
|
+
end
|
179
|
+
|
180
|
+
def opf_tocx
|
181
|
+
@cover_linear = if config['epubmaker']['cover_linear'] && config['epubmaker']['cover_linear'] != 'no'
|
182
|
+
'yes'
|
183
|
+
else
|
184
|
+
'no'
|
185
|
+
end
|
186
|
+
@tocx_contents = []
|
187
|
+
toc = nil
|
188
|
+
contents.each do |item|
|
189
|
+
next if item.media !~ /xhtml\+xml/ # skip non XHTML
|
190
|
+
|
191
|
+
@tocx_contents << item
|
192
|
+
end
|
193
|
+
|
194
|
+
ReVIEW::Template.generate(path: './opf/opf_tocx_epubv3.opf.erb', binding: binding)
|
195
|
+
end
|
196
|
+
|
197
|
+
def ncx(indentarray)
|
198
|
+
ncx_main = if config['epubmaker']['flattoc'].nil?
|
199
|
+
hierarchy_ncx('ol')
|
200
|
+
else
|
201
|
+
flat_ncx('ol', config['epubmaker']['flattocindent'])
|
202
|
+
end
|
203
|
+
|
204
|
+
@body = <<-EOT
|
205
|
+
<nav xmlns:epub="http://www.idpf.org/2007/ops" epub:type="toc" id="toc">
|
206
|
+
<h1 class="toc-title">#{h(ReVIEW::I18n.t('toctitle'))}</h1>
|
207
|
+
#{ncx_main} </nav>
|
208
|
+
EOT
|
209
|
+
|
210
|
+
@title = h(ReVIEW::I18n.t('toctitle'))
|
211
|
+
@language = config['language']
|
212
|
+
@stylesheets = config['stylesheet']
|
213
|
+
ReVIEW::Template.generate(path: './html/layout-html5.html.erb', binding: binding)
|
214
|
+
end
|
215
|
+
|
216
|
+
# Produce EPUB file +epubfile+.
|
217
|
+
# +work_dir+ points the directory has contents.
|
218
|
+
# +tmpdir+ defines temporary directory.
|
219
|
+
def produce(epubfile, work_dir, tmpdir, base_dir:)
|
220
|
+
produce_write_common(work_dir, tmpdir)
|
221
|
+
|
222
|
+
toc_file = "#{tmpdir}/OEBPS/#{config['bookname']}-toc.#{config['htmlext']}"
|
223
|
+
File.write(toc_file, ncx(config['epubmaker']['ncxindent']))
|
224
|
+
|
225
|
+
call_hook('hook_prepack', tmpdir, base_dir: base_dir)
|
226
|
+
expoter = ReVIEW::EPUBMaker::ZipExporter.new(tmpdir, config)
|
227
|
+
expoter.export_zip(epubfile)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# = producer.rb -- EPUB producer.
|
2
|
+
#
|
3
|
+
# Copyright (c) 2010-2021 Kenshi Muto
|
4
|
+
#
|
5
|
+
# This program is free software.
|
6
|
+
# You can distribute or modify this program under the terms of
|
7
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
8
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
9
|
+
#
|
10
|
+
# == Quick usage
|
11
|
+
# require 'review/epubmaker'
|
12
|
+
# producer = ReVIEW::EPUBMaker::Producer.new(config)
|
13
|
+
# producer.contents.push(ReVIEW::EPUBMaker::Content.new(file: 'ch01.xhtml'))
|
14
|
+
# producer.contents.push(ReVIEW::EPUBMaker::Content.new(file: 'ch02.xhtml'))
|
15
|
+
# ...
|
16
|
+
# producer.import_imageinfo('images')
|
17
|
+
# producer.produce(epub_filename)
|
18
|
+
|
19
|
+
require 'tmpdir'
|
20
|
+
require 'fileutils'
|
21
|
+
require 'review/yamlloader'
|
22
|
+
require 'review/epubmaker/content'
|
23
|
+
require 'review/epubmaker/epubv2'
|
24
|
+
require 'review/epubmaker/epubv3'
|
25
|
+
require 'review/i18n'
|
26
|
+
require 'review/configure'
|
27
|
+
require 'review/extentions/hash'
|
28
|
+
require 'review/loggable'
|
29
|
+
|
30
|
+
module ReVIEW
|
31
|
+
class EPUBMaker
|
32
|
+
# EPUBMaker produces EPUB file.
|
33
|
+
class Producer
|
34
|
+
include Loggable
|
35
|
+
|
36
|
+
# Array of content objects.
|
37
|
+
attr_accessor :contents
|
38
|
+
# Parameter hash.
|
39
|
+
attr_accessor :config
|
40
|
+
# Message resource object.
|
41
|
+
attr_reader :res
|
42
|
+
|
43
|
+
# Construct producer object.
|
44
|
+
# +config+ takes initial parameter hash.
|
45
|
+
def initialize(config)
|
46
|
+
@contents = []
|
47
|
+
@config = config
|
48
|
+
@config.maker = 'epubmaker'
|
49
|
+
@epub = nil
|
50
|
+
@res = ReVIEW::I18n
|
51
|
+
@logger = ReVIEW.logger
|
52
|
+
modify_config
|
53
|
+
end
|
54
|
+
|
55
|
+
# Modify parameters for EPUB specific.
|
56
|
+
def modify_config
|
57
|
+
if @config['epubversion'] >= 3
|
58
|
+
@config['htmlversion'] = 5
|
59
|
+
end
|
60
|
+
|
61
|
+
@config['title'] ||= @config['booktitle']
|
62
|
+
@config['cover'] ||= "#{@config['bookname']}.#{@config['htmlext']}"
|
63
|
+
|
64
|
+
%w[bookname title].each do |k|
|
65
|
+
unless @config[k]
|
66
|
+
raise "Key #{k} must have a value. Abort."
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
case @config['epubversion'].to_i
|
71
|
+
when 2
|
72
|
+
@epub = ReVIEW::EPUBMaker::EPUBv2.new(self)
|
73
|
+
when 3
|
74
|
+
@epub = ReVIEW::EPUBMaker::EPUBv3.new(self)
|
75
|
+
else
|
76
|
+
raise "Invalid EPUB version (#{@config['epubversion']}.)"
|
77
|
+
end
|
78
|
+
|
79
|
+
ReVIEW::I18n.locale = @config['language']
|
80
|
+
support_legacy_maker
|
81
|
+
end
|
82
|
+
|
83
|
+
# Add informations of figure files in +path+ to contents array.
|
84
|
+
# +base+ defines a string to remove from path name.
|
85
|
+
def import_imageinfo(path, base = nil, allow_exts = nil)
|
86
|
+
return nil unless File.exist?(path)
|
87
|
+
|
88
|
+
allow_exts ||= @config['image_ext']
|
89
|
+
Dir.foreach(path) do |f|
|
90
|
+
next if f.start_with?('.')
|
91
|
+
|
92
|
+
if f =~ /\.(#{allow_exts.join('|')})\Z/i
|
93
|
+
path.chop! if path =~ %r{/\Z}
|
94
|
+
if base.nil?
|
95
|
+
@contents.push(ReVIEW::EPUBMaker::Content.new(file: "#{path}/#{f}"))
|
96
|
+
else
|
97
|
+
@contents.push(ReVIEW::EPUBMaker::Content.new(file: "#{path.sub(base + '/', '')}/#{f}"))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
if FileTest.directory?("#{path}/#{f}")
|
101
|
+
import_imageinfo("#{path}/#{f}", base)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
alias_method :importImageInfo, :import_imageinfo
|
107
|
+
|
108
|
+
# Produce EPUB file +epubfile+.
|
109
|
+
# +work_dir+ points the directory has contents (default: current directory.)
|
110
|
+
# +tmpdir+ defines temporary directory.
|
111
|
+
# +base_dir+ is original root dir.
|
112
|
+
def produce(epubfile, work_dir, tmpdir = nil, base_dir: nil)
|
113
|
+
current = Dir.pwd
|
114
|
+
base_dir ||= current
|
115
|
+
|
116
|
+
# use Dir to solve a path for Windows (see #1011)
|
117
|
+
new_tmpdir = Dir[File.join(tmpdir.nil? ? Dir.mktmpdir : tmpdir)][0]
|
118
|
+
if epubfile !~ %r{\A/}
|
119
|
+
epubfile = "#{current}/#{epubfile}"
|
120
|
+
end
|
121
|
+
|
122
|
+
# FIXME: error check
|
123
|
+
File.unlink(epubfile) if File.exist?(epubfile)
|
124
|
+
|
125
|
+
begin
|
126
|
+
@epub.produce(epubfile, work_dir, new_tmpdir, base_dir: base_dir)
|
127
|
+
ensure
|
128
|
+
FileUtils.rm_r(new_tmpdir) if tmpdir.nil?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def support_legacy_maker
|
135
|
+
# legacy review-epubmaker support
|
136
|
+
if @config['flag_legacy_coverfile'].nil? && !@config['coverfile'].nil? && File.exist?(@config['coverfile'])
|
137
|
+
@config['cover'] = "#{@config['bookname']}-cover.#{@config['htmlext']}"
|
138
|
+
@epub.legacy_cover_and_title_file(@config['coverfile'], @config['cover'])
|
139
|
+
@config['flag_legacy_coverfile'] = true
|
140
|
+
warn %Q(Parameter 'coverfile' is obsolete. Please use 'cover' and make complete html file with header and footer.)
|
141
|
+
end
|
142
|
+
|
143
|
+
if @config['flag_legacy_titlepagefile'].nil? && !@config['titlepagefile'].nil? && File.exist?(@config['titlepagefile'])
|
144
|
+
@config['titlefile'] = "#{@config['bookname']}-title.#{@config['htmlext']}"
|
145
|
+
@config['titlepage'] = true
|
146
|
+
@epub.legacy_cover_and_title_file(@config['titlepagefile'], @config['titlefile'])
|
147
|
+
@config['flag_legacy_titlepagefile'] = true
|
148
|
+
warn %Q(Parameter 'titlepagefile' is obsolete. Please use 'titlefile' and make complete html file with header and footer.)
|
149
|
+
end
|
150
|
+
|
151
|
+
if @config['flag_legacy_backcoverfile'].nil? && !@config['backcoverfile'].nil? && File.exist?(@config['backcoverfile'])
|
152
|
+
@config['backcover'] = "#{@config['bookname']}-backcover.#{@config['htmlext']}"
|
153
|
+
@epub.legacy_cover_and_title_file(@config['backcoverfile'], @config['backcover'])
|
154
|
+
@config['flag_legacy_backcoverfile'] = true
|
155
|
+
warn %Q(Parameter 'backcoverfile' is obsolete. Please use 'backcover' and make complete html file with header and footer.)
|
156
|
+
end
|
157
|
+
|
158
|
+
if @config['flag_legacy_pubhistory'].nil? && @config['pubhistory']
|
159
|
+
@config['history'] = [[]]
|
160
|
+
@config['pubhistory'].split("\n").each { |date| @config['history'][0].push(date.sub(/(\d+)年(\d+)月(\d+)日/, '\1-\2-\3')) }
|
161
|
+
@config['flag_legacy_pubhistory'] = true
|
162
|
+
warn %Q(Parameter 'pubhistory' is obsolete. Please use 'history' array.)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|