review 4.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (259) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-tex.yml +35 -0
  3. data/.github/workflows/ruby-win.yml +19 -9
  4. data/.github/workflows/ruby.yml +7 -3
  5. data/.rubocop.yml +138 -34
  6. data/NEWS.ja.md +285 -0
  7. data/NEWS.md +285 -1
  8. data/README.md +7 -6
  9. data/Rakefile +7 -2
  10. data/bin/review +2 -4
  11. data/bin/review-catalog-converter +4 -4
  12. data/bin/review-check +8 -12
  13. data/bin/review-checkdep +2 -5
  14. data/bin/review-compile +18 -34
  15. data/bin/review-epub2html +1 -4
  16. data/bin/review-epubmaker +3 -4
  17. data/bin/review-idgxmlmaker +1 -3
  18. data/bin/review-index +5 -86
  19. data/bin/review-init +1 -4
  20. data/bin/review-pdfmaker +1 -3
  21. data/bin/review-preproc +30 -38
  22. data/bin/review-textmaker +1 -3
  23. data/bin/review-update +1 -4
  24. data/bin/review-validate +4 -4
  25. data/bin/review-vol +5 -82
  26. data/bin/review-webmaker +1 -3
  27. data/doc/config.yml.sample +45 -11
  28. data/doc/config.yml.sample-simple +3 -3
  29. data/doc/format.ja.md +103 -13
  30. data/doc/format.md +104 -16
  31. data/doc/makeindex.ja.md +2 -2
  32. data/doc/pdfmaker.ja.md +42 -0
  33. data/doc/pdfmaker.md +41 -0
  34. data/doc/quickstart.ja.md +19 -6
  35. data/doc/quickstart.md +18 -6
  36. data/doc/writing_vertical.ja.md +6 -0
  37. data/lib/review.rb +1 -1
  38. data/lib/review/book.rb +2 -2
  39. data/lib/review/book/base.rb +67 -29
  40. data/lib/review/book/bib.rb +21 -0
  41. data/lib/review/book/book_unit.rb +158 -0
  42. data/lib/review/book/chapter.rb +33 -26
  43. data/lib/review/book/index.rb +24 -185
  44. data/lib/review/book/index/item.rb +7 -1
  45. data/lib/review/book/page_metric.rb +7 -7
  46. data/lib/review/book/part.rb +26 -11
  47. data/lib/review/book/volume.rb +5 -5
  48. data/lib/review/builder.rb +121 -52
  49. data/lib/review/call_hook.rb +20 -0
  50. data/lib/review/catalog.rb +3 -2
  51. data/lib/review/compiler.rb +230 -111
  52. data/lib/review/configure.rb +91 -7
  53. data/lib/review/converter.rb +1 -1
  54. data/lib/review/epub2html.rb +6 -1
  55. data/lib/review/epubmaker.rb +124 -152
  56. data/lib/review/epubmaker/content.rb +113 -0
  57. data/lib/review/epubmaker/epubcommon.rb +372 -0
  58. data/lib/review/epubmaker/epubv2.rb +178 -0
  59. data/lib/review/epubmaker/epubv3.rb +231 -0
  60. data/lib/review/epubmaker/producer.rb +167 -0
  61. data/lib/review/epubmaker/reviewheaderlistener.rb +12 -2
  62. data/lib/review/epubmaker/zip_exporter.rb +84 -0
  63. data/lib/review/exception.rb +13 -0
  64. data/lib/review/htmlbuilder.rb +176 -89
  65. data/lib/review/htmlutils.rb +8 -11
  66. data/lib/review/i18n.rb +2 -1
  67. data/lib/review/idgxmlbuilder.rb +165 -75
  68. data/lib/review/idgxmlmaker.rb +24 -28
  69. data/lib/review/img_math.rb +238 -0
  70. data/lib/review/index_builder.rb +645 -0
  71. data/lib/review/init.rb +9 -17
  72. data/lib/review/latexbox.rb +58 -0
  73. data/lib/review/latexbuilder.rb +193 -75
  74. data/lib/review/latexutils.rb +9 -1
  75. data/lib/review/lineinput.rb +112 -2
  76. data/lib/review/loggable.rb +27 -0
  77. data/lib/review/logger.rb +90 -3
  78. data/lib/review/makerhelper.rb +17 -188
  79. data/lib/review/markdownbuilder.rb +54 -4
  80. data/lib/review/pdfmaker.rb +76 -84
  81. data/lib/review/plaintextbuilder.rb +106 -22
  82. data/lib/review/preprocessor.rb +107 -303
  83. data/lib/review/preprocessor/directive.rb +35 -0
  84. data/lib/review/preprocessor/line.rb +34 -0
  85. data/lib/review/preprocessor/repository.rb +177 -0
  86. data/lib/review/rstbuilder.rb +27 -8
  87. data/lib/review/sec_counter.rb +14 -0
  88. data/lib/review/template.rb +11 -1
  89. data/lib/review/textmaker.rb +27 -32
  90. data/lib/review/textutils.rb +3 -12
  91. data/lib/review/tocprinter.rb +242 -97
  92. data/lib/review/topbuilder.rb +98 -31
  93. data/lib/review/update.rb +12 -13
  94. data/lib/review/version.rb +1 -1
  95. data/lib/review/volumeprinter.rb +97 -0
  96. data/lib/review/webmaker.rb +40 -47
  97. data/lib/review/webtocprinter.rb +39 -35
  98. data/lib/review/yamlloader.rb +2 -1
  99. data/review.gemspec +5 -3
  100. data/samples/sample-book/src/config-epub2.yml +1 -1
  101. data/samples/sample-book/src/config.yml +3 -3
  102. data/samples/sample-book/src/lib/tasks/review.rake +19 -1
  103. data/samples/sample-book/src/lib/tasks/z01_copy_sty.rake +2 -1
  104. data/samples/syntax-book/Gemfile +1 -1
  105. data/samples/syntax-book/ch01.re +1 -1
  106. data/samples/syntax-book/ch02.re +21 -6
  107. data/samples/syntax-book/ch03.re +1 -1
  108. data/samples/syntax-book/config.yml +1 -1
  109. data/samples/syntax-book/images/img3-2.png +0 -0
  110. data/samples/syntax-book/lib/tasks/z01_copy_sty.rake +2 -1
  111. data/templates/html/_colophon.html.erb +23 -0
  112. data/templates/html/_colophon_history.html.erb +9 -0
  113. data/templates/html/_cover.html.erb +10 -0
  114. data/templates/html/_part_body.html.erb +6 -0
  115. data/templates/html/_titlepage.html.erb +20 -0
  116. data/templates/html/layout-html5.html.erb +6 -0
  117. data/templates/html/layout-xhtml1.html.erb +6 -0
  118. data/templates/latex/config.erb +35 -23
  119. data/templates/latex/review-jlreq/README.md +3 -1
  120. data/templates/latex/review-jlreq/review-base.sty +36 -23
  121. data/templates/latex/review-jlreq/review-jlreq.cls +18 -25
  122. data/templates/latex/review-jlreq/review-style.sty +6 -1
  123. data/templates/latex/review-jlreq/review-tcbox.sty +348 -0
  124. data/templates/latex/review-jlreq/reviewmacro.sty +5 -0
  125. data/templates/latex/review-jsbook/README.md +7 -5
  126. data/templates/latex/review-jsbook/review-base.sty +40 -24
  127. data/templates/latex/review-jsbook/review-jsbook.cls +13 -3
  128. data/templates/latex/review-jsbook/review-style.sty +6 -1
  129. data/templates/latex/review-jsbook/review-tcbox.sty +348 -0
  130. data/templates/latex/review-jsbook/reviewmacro.sty +5 -0
  131. data/templates/opf/epubv2.opf.erb +7 -7
  132. data/templates/opf/epubv3.opf.erb +7 -7
  133. data/templates/opf/opf_manifest_epubv2.opf.erb +10 -0
  134. data/templates/opf/opf_manifest_epubv3.opf.erb +10 -0
  135. data/templates/opf/opf_metainfo_epubv2.opf.erb +17 -0
  136. data/templates/opf/opf_metainfo_epubv3.opf.erb +49 -0
  137. data/templates/opf/opf_tocx_epubv2.opf.erb +9 -0
  138. data/templates/opf/opf_tocx_epubv3.opf.erb +17 -0
  139. data/templates/web/html/layout-html5.html.erb +9 -8
  140. data/templates/web/html/layout-xhtml1.html.erb +6 -0
  141. data/test/assets/header_listener.html +35 -0
  142. data/test/assets/img_math/img1.png +0 -0
  143. data/test/assets/img_math/img2.png +0 -0
  144. data/test/assets/img_math/img3.png +0 -0
  145. data/test/assets/syntax_book_index_detail.txt +58 -0
  146. data/test/assets/test_template.tex +6 -3
  147. data/test/assets/test_template_backmatter.tex +6 -3
  148. data/test/book_test_helper.rb +11 -5
  149. data/test/run_test.rb +1 -1
  150. data/test/test_book.rb +54 -63
  151. data/test/test_book_chapter.rb +95 -54
  152. data/test/test_book_part.rb +3 -3
  153. data/test/test_builder.rb +29 -20
  154. data/test/test_catalog_converter_cmd.rb +1 -1
  155. data/test/test_converter.rb +1 -0
  156. data/test/test_epub3maker.rb +170 -126
  157. data/test/test_epubmaker.rb +254 -129
  158. data/test/test_epubmaker_cmd.rb +15 -4
  159. data/test/test_helper.rb +12 -5
  160. data/test/test_htmlbuilder.rb +926 -76
  161. data/test/test_htmlutils.rb +0 -12
  162. data/test/test_i18n.rb +33 -33
  163. data/test/test_idgxmlbuilder.rb +531 -20
  164. data/test/test_idgxmlmaker_cmd.rb +7 -3
  165. data/test/test_img_math.rb +111 -0
  166. data/test/test_index.rb +62 -52
  167. data/test/test_indexbuilder.rb +52 -0
  168. data/test/test_latexbuilder.rb +891 -20
  169. data/test/test_latexbuilder_v2.rb +56 -10
  170. data/test/test_lineinput.rb +20 -93
  171. data/test/test_logger.rb +7 -7
  172. data/test/test_makerhelper.rb +0 -12
  173. data/test/test_markdownbuilder.rb +32 -0
  174. data/test/test_pdfmaker.rb +100 -11
  175. data/test/test_pdfmaker_cmd.rb +3 -3
  176. data/test/test_plaintextbuilder.rb +546 -32
  177. data/test/test_preprocessor.rb +188 -1
  178. data/test/test_review_ext.rb +2 -1
  179. data/test/test_reviewheaderlistener.rb +49 -0
  180. data/test/test_rstbuilder.rb +25 -1
  181. data/test/test_sec_counter.rb +156 -0
  182. data/test/test_template.rb +12 -2
  183. data/test/test_textmaker_cmd.rb +5 -1
  184. data/test/test_tocprinter.rb +46 -0
  185. data/test/test_topbuilder.rb +324 -20
  186. data/test/test_update.rb +44 -44
  187. data/test/test_webtocprinter.rb +75 -43
  188. data/test/test_zip_exporter.rb +5 -6
  189. data/vendor/gentombow/LICENSE +1 -1
  190. data/vendor/gentombow/Makefile +0 -1
  191. data/vendor/gentombow/bounddvi-en.pdf +0 -0
  192. data/vendor/gentombow/bounddvi-en.tex +1 -0
  193. data/vendor/gentombow/bounddvi.pdf +0 -0
  194. data/vendor/gentombow/bounddvi.sty +30 -7
  195. data/vendor/gentombow/bounddvi.tex +1 -0
  196. data/vendor/gentombow/create_archive.sh +1 -0
  197. data/vendor/gentombow/gentombow-ja.pdf +0 -0
  198. data/vendor/gentombow/gentombow-ja.tex +9 -0
  199. data/vendor/gentombow/gentombow.pdf +0 -0
  200. data/vendor/gentombow/gentombow.sty +32 -10
  201. data/vendor/gentombow/gentombow.tex +8 -0
  202. data/vendor/gentombow/tests/gentombow-01-pdfx.tex +8 -0
  203. data/vendor/gentombow/tests/gentombow-02-pdfx.tex +8 -0
  204. data/vendor/jsclasses/Makefile +3 -2
  205. data/vendor/jsclasses/create_archive.sh +5 -5
  206. data/vendor/jsclasses/jis/Makefile +3 -2
  207. data/vendor/jsclasses/jis/jsarticle.cls +22 -18
  208. data/vendor/jsclasses/jis/jsbook.cls +22 -18
  209. data/vendor/jsclasses/jis/jsclasses.dtx +94 -13
  210. data/vendor/jsclasses/jis/jsclasses.ins +15 -5
  211. data/vendor/jsclasses/jis/jslogo.ins +9 -0
  212. data/vendor/jsclasses/jis/jslogo.sty +1 -13
  213. data/vendor/jsclasses/jis/jspf.cls +22 -18
  214. data/vendor/jsclasses/jis/jsreport.cls +22 -18
  215. data/vendor/jsclasses/jis/jsverb.ins +9 -0
  216. data/vendor/jsclasses/jis/jsverb.sty +1 -13
  217. data/vendor/jsclasses/jis/kiyou.cls +22 -18
  218. data/vendor/jsclasses/jis/minijs.sty +65 -22
  219. data/vendor/jsclasses/jis/okumacro.ins +9 -0
  220. data/vendor/jsclasses/jis/okumacro.sty +1 -13
  221. data/vendor/jsclasses/jis/okuverb.ins +9 -0
  222. data/vendor/jsclasses/jis/okuverb.sty +1 -13
  223. data/vendor/jsclasses/jis/winjis.sty +23 -19
  224. data/vendor/jsclasses/jsarticle.cls +22 -18
  225. data/vendor/jsclasses/jsbook.cls +22 -18
  226. data/vendor/jsclasses/jsclasses.dtx +94 -13
  227. data/vendor/jsclasses/jsclasses.ins +15 -5
  228. data/vendor/jsclasses/jsclasses.pdf +0 -0
  229. data/vendor/jsclasses/jslogo.ins +9 -0
  230. data/vendor/jsclasses/jslogo.pdf +0 -0
  231. data/vendor/jsclasses/jslogo.sty +1 -13
  232. data/vendor/jsclasses/jspf.cls +22 -18
  233. data/vendor/jsclasses/jsreport.cls +22 -18
  234. data/vendor/jsclasses/jsverb.ins +9 -0
  235. data/vendor/jsclasses/jsverb.pdf +0 -0
  236. data/vendor/jsclasses/jsverb.sty +1 -13
  237. data/vendor/jsclasses/kiyou.cls +22 -18
  238. data/vendor/jsclasses/minijs.sty +68 -22
  239. data/vendor/jsclasses/okumacro.ins +9 -0
  240. data/vendor/jsclasses/okumacro.pdf +0 -0
  241. data/vendor/jsclasses/okumacro.sty +1 -13
  242. data/vendor/jsclasses/okuverb.ins +9 -0
  243. data/vendor/jsclasses/okuverb.pdf +0 -0
  244. data/vendor/jsclasses/okuverb.sty +1 -13
  245. data/vendor/jsclasses/tests/relfont.tex +10 -0
  246. data/vendor/jsclasses/winjis.sty +23 -19
  247. metadata +106 -22
  248. data/.rubocop_todo.yml +0 -7
  249. data/lib/epubmaker.rb +0 -23
  250. data/lib/epubmaker/content.rb +0 -110
  251. data/lib/epubmaker/epubcommon.rb +0 -441
  252. data/lib/epubmaker/epubv2.rb +0 -143
  253. data/lib/epubmaker/epubv3.rb +0 -233
  254. data/lib/epubmaker/producer.rb +0 -375
  255. data/lib/epubmaker/zip_exporter.rb +0 -81
  256. data/lib/lineinput.rb +0 -155
  257. data/lib/review/book/compilable.rb +0 -178
  258. data/lib/review/tocparser.rb +0 -275
  259. 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