review 3.2.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (282) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-tex.yml +31 -0
  3. data/.github/workflows/ruby-win.yml +45 -0
  4. data/.github/workflows/ruby.yml +27 -0
  5. data/.rubocop.yml +167 -42
  6. data/.travis.yml +1 -1
  7. data/Dockerfile +21 -5
  8. data/NEWS.ja.md +428 -1
  9. data/NEWS.md +429 -2
  10. data/README.md +11 -7
  11. data/Rakefile +7 -2
  12. data/appveyor.yml +0 -20
  13. data/bin/review +2 -4
  14. data/bin/review-catalog-converter +5 -5
  15. data/bin/review-check +13 -17
  16. data/bin/review-checkdep +3 -6
  17. data/bin/review-compile +13 -22
  18. data/bin/review-epub2html +1 -4
  19. data/bin/review-epubmaker +3 -4
  20. data/bin/review-idgxmlmaker +14 -0
  21. data/bin/review-index +5 -86
  22. data/bin/review-init +1 -4
  23. data/bin/review-pdfmaker +1 -3
  24. data/bin/review-preproc +11 -13
  25. data/bin/review-textmaker +1 -3
  26. data/bin/review-update +1 -4
  27. data/bin/review-validate +7 -7
  28. data/bin/review-vol +5 -82
  29. data/bin/review-webmaker +1 -3
  30. data/doc/config.yml.sample +67 -16
  31. data/doc/config.yml.sample-simple +4 -3
  32. data/doc/format.ja.md +133 -21
  33. data/doc/format.md +135 -34
  34. data/doc/makeindex.ja.md +2 -2
  35. data/doc/pdfmaker.ja.md +43 -1
  36. data/doc/pdfmaker.md +42 -1
  37. data/doc/quickstart.ja.md +55 -25
  38. data/doc/quickstart.md +47 -17
  39. data/lib/review.rb +1 -1
  40. data/lib/review/book.rb +2 -2
  41. data/lib/review/book/base.rb +89 -90
  42. data/lib/review/book/bib.rb +21 -0
  43. data/lib/review/book/book_unit.rb +158 -0
  44. data/lib/review/book/chapter.rb +51 -29
  45. data/lib/review/book/index.rb +42 -248
  46. data/lib/review/book/index/item.rb +46 -0
  47. data/lib/review/book/page_metric.rb +7 -7
  48. data/lib/review/book/part.rb +45 -10
  49. data/lib/review/book/volume.rb +5 -5
  50. data/lib/review/builder.rb +171 -54
  51. data/lib/review/call_hook.rb +20 -0
  52. data/lib/review/catalog.rb +15 -17
  53. data/lib/review/compiler.rb +240 -102
  54. data/lib/review/configure.rb +101 -12
  55. data/lib/review/converter.rb +1 -1
  56. data/lib/review/epub2html.rb +6 -1
  57. data/lib/review/epubmaker.rb +120 -118
  58. data/lib/review/epubmaker/content.rb +113 -0
  59. data/lib/review/epubmaker/epubcommon.rb +372 -0
  60. data/lib/review/epubmaker/epubv2.rb +178 -0
  61. data/lib/review/epubmaker/epubv3.rb +231 -0
  62. data/lib/review/epubmaker/producer.rb +168 -0
  63. data/lib/review/epubmaker/reviewheaderlistener.rb +12 -2
  64. data/lib/review/epubmaker/zip_exporter.rb +84 -0
  65. data/lib/review/exception.rb +6 -0
  66. data/lib/review/extentions/string.rb +0 -4
  67. data/lib/review/htmlbuilder.rb +147 -149
  68. data/lib/review/htmlutils.rb +10 -14
  69. data/lib/review/i18n.rb +4 -3
  70. data/lib/review/idgxmlbuilder.rb +229 -103
  71. data/lib/review/idgxmlmaker.rb +188 -0
  72. data/lib/review/img_math.rb +245 -0
  73. data/lib/review/index_builder.rb +654 -0
  74. data/lib/review/init-web/finish.html +10 -0
  75. data/lib/review/init-web/index.html +190 -0
  76. data/lib/review/init-web/review-layout-design.js +691 -0
  77. data/lib/review/init.rb +124 -41
  78. data/lib/review/latexbox.rb +58 -0
  79. data/lib/review/latexbuilder.rb +249 -97
  80. data/lib/review/latexutils.rb +9 -1
  81. data/lib/review/lineinput.rb +113 -3
  82. data/lib/review/logger.rb +43 -8
  83. data/lib/review/makerhelper.rb +13 -186
  84. data/lib/review/markdownbuilder.rb +75 -39
  85. data/lib/review/md2inaobuilder.rb +3 -5
  86. data/lib/review/pdfmaker.rb +88 -83
  87. data/lib/review/plaintextbuilder.rb +158 -83
  88. data/lib/review/preprocessor.rb +30 -24
  89. data/lib/review/rstbuilder.rb +58 -39
  90. data/lib/review/sec_counter.rb +14 -0
  91. data/lib/review/template.rb +6 -0
  92. data/lib/review/textmaker.rb +29 -17
  93. data/lib/review/textutils.rb +68 -2
  94. data/lib/review/tocprinter.rb +242 -97
  95. data/lib/review/topbuilder.rb +147 -61
  96. data/lib/review/update.rb +27 -28
  97. data/lib/review/version.rb +1 -1
  98. data/lib/review/volumeprinter.rb +97 -0
  99. data/lib/review/webmaker.rb +36 -35
  100. data/lib/review/webtocprinter.rb +39 -35
  101. data/lib/review/yamlloader.rb +4 -0
  102. data/review.gemspec +8 -5
  103. data/samples/sample-book/README.md +7 -2
  104. data/samples/sample-book/src/.gitignore +154 -0
  105. data/samples/sample-book/src/config-ebook.yml +4 -0
  106. data/samples/sample-book/src/config-epub2.yml +1 -1
  107. data/samples/sample-book/src/config-jlreq-ebook.yml +4 -0
  108. data/samples/sample-book/src/config-jlreq.yml +6 -0
  109. data/samples/sample-book/src/config.yml +3 -3
  110. data/samples/sample-book/src/lib/tasks/review.rake +45 -14
  111. data/samples/sample-book/src/lib/tasks/z01_copy_sty.rake +14 -8
  112. data/samples/syntax-book/Gemfile +1 -1
  113. data/samples/syntax-book/ch01.re +3 -1
  114. data/samples/syntax-book/ch02.re +28 -21
  115. data/samples/syntax-book/ch03.re +4 -7
  116. data/samples/syntax-book/config-jlreq-lualatex.yml +4 -0
  117. data/samples/syntax-book/config-jlreq.yml +5 -0
  118. data/samples/syntax-book/config-print.yml +3 -0
  119. data/samples/syntax-book/config.yml +1 -1
  120. data/samples/syntax-book/images/img3-2.png +0 -0
  121. data/samples/syntax-book/lib/tasks/review.rake +30 -15
  122. data/samples/syntax-book/lib/tasks/z01_copy_sty.rake +14 -8
  123. data/templates/html/_colophon.html.erb +23 -0
  124. data/templates/html/_colophon_history.html.erb +9 -0
  125. data/templates/html/_cover.html.erb +10 -0
  126. data/templates/html/_part_body.html.erb +6 -0
  127. data/templates/html/_titlepage.html.erb +20 -0
  128. data/templates/html/layout-html5.html.erb +6 -0
  129. data/templates/html/layout-xhtml1.html.erb +6 -0
  130. data/templates/latex/config.erb +45 -27
  131. data/templates/latex/layout.tex.erb +1 -0
  132. data/templates/latex/review-jlreq/README.md +3 -1
  133. data/templates/latex/review-jlreq/review-base.sty +124 -37
  134. data/templates/latex/review-jlreq/review-jlreq.cls +29 -22
  135. data/templates/latex/review-jlreq/review-style.sty +9 -1
  136. data/templates/latex/review-jlreq/review-tcbox.sty +348 -0
  137. data/templates/latex/review-jlreq/reviewmacro.sty +5 -0
  138. data/templates/latex/review-jsbook/README.md +46 -5
  139. data/templates/latex/review-jsbook/review-base.sty +111 -30
  140. data/templates/latex/review-jsbook/review-jsbook.cls +16 -2
  141. data/templates/latex/review-jsbook/review-style.sty +10 -2
  142. data/templates/latex/review-jsbook/review-tcbox.sty +348 -0
  143. data/templates/latex/review-jsbook/reviewmacro.sty +5 -0
  144. data/templates/opf/epubv2.opf.erb +7 -7
  145. data/templates/opf/epubv3.opf.erb +7 -7
  146. data/templates/opf/opf_manifest_epubv2.opf.erb +10 -0
  147. data/templates/opf/opf_manifest_epubv3.opf.erb +10 -0
  148. data/templates/opf/opf_metainfo_epubv2.opf.erb +17 -0
  149. data/templates/opf/opf_metainfo_epubv3.opf.erb +49 -0
  150. data/templates/opf/opf_tocx_epubv2.opf.erb +9 -0
  151. data/templates/opf/opf_tocx_epubv3.opf.erb +17 -0
  152. data/templates/web/html/layout-html5.html.erb +9 -8
  153. data/templates/web/html/layout-xhtml1.html.erb +6 -0
  154. data/test/assets/header_listener.html +35 -0
  155. data/test/assets/img_math/img1.png +0 -0
  156. data/test/assets/img_math/img2.png +0 -0
  157. data/test/assets/img_math/img3.png +0 -0
  158. data/test/assets/syntax_book_index_detail.txt +58 -0
  159. data/test/assets/test_template.tex +20 -9
  160. data/test/assets/test_template_backmatter.tex +20 -9
  161. data/test/book_test_helper.rb +11 -5
  162. data/test/run_test.rb +1 -1
  163. data/test/test_book.rb +123 -78
  164. data/test/test_book_chapter.rb +99 -56
  165. data/test/test_book_part.rb +3 -3
  166. data/test/test_builder.rb +24 -15
  167. data/test/test_catalog.rb +19 -42
  168. data/test/test_catalog_converter_cmd.rb +1 -1
  169. data/test/test_converter.rb +1 -0
  170. data/test/test_epub3maker.rb +170 -126
  171. data/test/test_epubmaker.rb +249 -129
  172. data/test/test_epubmaker_cmd.rb +16 -9
  173. data/test/test_helper.rb +23 -11
  174. data/test/test_htmlbuilder.rb +1083 -114
  175. data/test/test_htmlutils.rb +0 -12
  176. data/test/test_i18n.rb +37 -37
  177. data/test/test_idgxmlbuilder.rb +627 -27
  178. data/test/test_idgxmlmaker_cmd.rb +50 -0
  179. data/test/test_image_finder.rb +52 -70
  180. data/test/test_img_math.rb +111 -0
  181. data/test/test_index.rb +62 -52
  182. data/test/test_indexbuilder.rb +52 -0
  183. data/test/test_latexbuilder.rb +1189 -59
  184. data/test/test_latexbuilder_v2.rb +74 -34
  185. data/test/test_lineinput.rb +20 -93
  186. data/test/test_logger.rb +17 -4
  187. data/test/test_makerhelper.rb +2 -14
  188. data/test/test_markdownbuilder.rb +77 -4
  189. data/test/test_md2inaobuilder.rb +12 -2
  190. data/test/test_pdfmaker.rb +101 -12
  191. data/test/test_pdfmaker_cmd.rb +102 -8
  192. data/test/test_plaintextbuilder.rb +562 -31
  193. data/test/test_review_ext.rb +2 -1
  194. data/test/test_reviewheaderlistener.rb +49 -0
  195. data/test/test_rstbuilder.rb +58 -5
  196. data/test/test_sec_counter.rb +156 -0
  197. data/test/test_template.rb +12 -2
  198. data/test/test_textmaker_cmd.rb +58 -0
  199. data/test/test_textutils.rb +109 -2
  200. data/test/test_tocprinter.rb +46 -0
  201. data/test/test_topbuilder.rb +400 -17
  202. data/test/test_update.rb +53 -44
  203. data/test/test_webtocprinter.rb +75 -43
  204. data/test/test_yamlloader.rb +13 -0
  205. data/test/test_zip_exporter.rb +5 -6
  206. data/vendor/gentombow/LICENSE +1 -1
  207. data/vendor/gentombow/Makefile +0 -1
  208. data/vendor/gentombow/bounddvi-en.pdf +0 -0
  209. data/vendor/gentombow/bounddvi-en.tex +1 -0
  210. data/vendor/gentombow/bounddvi.pdf +0 -0
  211. data/vendor/gentombow/bounddvi.sty +30 -7
  212. data/vendor/gentombow/bounddvi.tex +1 -0
  213. data/vendor/gentombow/create_archive.sh +1 -0
  214. data/vendor/gentombow/gentombow-ja.pdf +0 -0
  215. data/vendor/gentombow/gentombow-ja.tex +9 -0
  216. data/vendor/gentombow/gentombow.pdf +0 -0
  217. data/vendor/gentombow/gentombow.sty +32 -10
  218. data/vendor/gentombow/gentombow.tex +8 -0
  219. data/vendor/gentombow/tests/gentombow-01-pdfx.tex +8 -0
  220. data/vendor/gentombow/tests/gentombow-02-pdfx.tex +8 -0
  221. data/vendor/jsclasses/LICENSE +1 -1
  222. data/vendor/jsclasses/Makefile +3 -2
  223. data/vendor/jsclasses/create_archive.sh +5 -5
  224. data/vendor/jsclasses/jis/Makefile +3 -2
  225. data/vendor/jsclasses/jis/jsarticle.cls +74 -31
  226. data/vendor/jsclasses/jis/jsbook.cls +74 -31
  227. data/vendor/jsclasses/jis/jsclasses.dtx +176 -36
  228. data/vendor/jsclasses/jis/jsclasses.ins +15 -5
  229. data/vendor/jsclasses/jis/jslogo.dtx +4 -4
  230. data/vendor/jsclasses/jis/jslogo.ins +9 -0
  231. data/vendor/jsclasses/jis/jslogo.sty +4 -16
  232. data/vendor/jsclasses/jis/jspf.cls +73 -30
  233. data/vendor/jsclasses/jis/jsreport.cls +74 -31
  234. data/vendor/jsclasses/jis/jsverb.ins +9 -0
  235. data/vendor/jsclasses/jis/jsverb.sty +1 -13
  236. data/vendor/jsclasses/jis/kiyou.cls +74 -31
  237. data/vendor/jsclasses/jis/minijs.sty +65 -22
  238. data/vendor/jsclasses/jis/okumacro.dtx +4 -5
  239. data/vendor/jsclasses/jis/okumacro.ins +9 -0
  240. data/vendor/jsclasses/jis/okumacro.sty +4 -17
  241. data/vendor/jsclasses/jis/okuverb.ins +9 -0
  242. data/vendor/jsclasses/jis/okuverb.sty +1 -13
  243. data/vendor/jsclasses/jis/winjis.sty +23 -19
  244. data/vendor/jsclasses/jsarticle.cls +74 -31
  245. data/vendor/jsclasses/jsbook.cls +74 -31
  246. data/vendor/jsclasses/jsclasses.dtx +176 -36
  247. data/vendor/jsclasses/jsclasses.ins +15 -5
  248. data/vendor/jsclasses/jsclasses.pdf +0 -0
  249. data/vendor/jsclasses/jslogo.dtx +4 -4
  250. data/vendor/jsclasses/jslogo.ins +9 -0
  251. data/vendor/jsclasses/jslogo.pdf +0 -0
  252. data/vendor/jsclasses/jslogo.sty +4 -16
  253. data/vendor/jsclasses/jspf.cls +73 -30
  254. data/vendor/jsclasses/jsreport.cls +74 -31
  255. data/vendor/jsclasses/jsverb.ins +9 -0
  256. data/vendor/jsclasses/jsverb.pdf +0 -0
  257. data/vendor/jsclasses/jsverb.sty +1 -13
  258. data/vendor/jsclasses/kiyou.cls +74 -31
  259. data/vendor/jsclasses/minijs.sty +68 -22
  260. data/vendor/jsclasses/okumacro.dtx +4 -5
  261. data/vendor/jsclasses/okumacro.ins +9 -0
  262. data/vendor/jsclasses/okumacro.pdf +0 -0
  263. data/vendor/jsclasses/okumacro.sty +4 -17
  264. data/vendor/jsclasses/okuverb.ins +9 -0
  265. data/vendor/jsclasses/okuverb.pdf +0 -0
  266. data/vendor/jsclasses/okuverb.sty +1 -13
  267. data/vendor/jsclasses/tests/relfont.tex +10 -0
  268. data/vendor/jsclasses/winjis.sty +23 -19
  269. metadata +136 -23
  270. data/.rubocop_todo.yml +0 -7
  271. data/lib/epubmaker.rb +0 -23
  272. data/lib/epubmaker/content.rb +0 -110
  273. data/lib/epubmaker/epubcommon.rb +0 -441
  274. data/lib/epubmaker/epubv2.rb +0 -143
  275. data/lib/epubmaker/epubv3.rb +0 -233
  276. data/lib/epubmaker/producer.rb +0 -375
  277. data/lib/epubmaker/zip_exporter.rb +0 -81
  278. data/lib/lineinput.rb +0 -155
  279. data/lib/review/book/compilable.rb +0 -173
  280. data/lib/review/tocparser.rb +0 -271
  281. data/samples/syntax-book/review-ext.rb +0 -14
  282. 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,168 @@
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
+
29
+ module ReVIEW
30
+ class EPUBMaker
31
+ # EPUBMaker produces EPUB file.
32
+ class Producer
33
+ # Array of content objects.
34
+ attr_accessor :contents
35
+ # Parameter hash.
36
+ attr_accessor :config
37
+ # Message resource object.
38
+ attr_reader :res
39
+
40
+ def warn(msg)
41
+ @logger.warn(msg)
42
+ end
43
+
44
+ # Construct producer object.
45
+ # +config+ takes initial parameter hash.
46
+ def initialize(config)
47
+ @contents = []
48
+ @config = config
49
+ @config.maker = 'epubmaker'
50
+ @epub = nil
51
+ @res = ReVIEW::I18n
52
+ @logger = ReVIEW.logger
53
+ modify_config
54
+ end
55
+
56
+ # Modify parameters for EPUB specific.
57
+ def modify_config
58
+ if @config['epubversion'] >= 3
59
+ @config['htmlversion'] = 5
60
+ end
61
+
62
+ @config['title'] ||= @config['booktitle']
63
+ @config['cover'] ||= "#{@config['bookname']}.#{@config['htmlext']}"
64
+
65
+ %w[bookname title].each do |k|
66
+ unless @config[k]
67
+ raise "Key #{k} must have a value. Abort."
68
+ end
69
+ end
70
+
71
+ case @config['epubversion'].to_i
72
+ when 2
73
+ @epub = ReVIEW::EPUBMaker::EPUBv2.new(self)
74
+ when 3
75
+ @epub = ReVIEW::EPUBMaker::EPUBv3.new(self)
76
+ else
77
+ raise "Invalid EPUB version (#{@config['epubversion']}.)"
78
+ end
79
+
80
+ ReVIEW::I18n.locale = @config['language']
81
+ support_legacy_maker
82
+ end
83
+
84
+ # Add informations of figure files in +path+ to contents array.
85
+ # +base+ defines a string to remove from path name.
86
+ def import_imageinfo(path, base = nil, allow_exts = nil)
87
+ return nil unless File.exist?(path)
88
+
89
+ allow_exts ||= @config['image_ext']
90
+ Dir.foreach(path) do |f|
91
+ next if f.start_with?('.')
92
+
93
+ if f =~ /\.(#{allow_exts.join('|')})\Z/i
94
+ path.chop! if path =~ %r{/\Z}
95
+ if base.nil?
96
+ @contents.push(ReVIEW::EPUBMaker::Content.new(file: "#{path}/#{f}"))
97
+ else
98
+ @contents.push(ReVIEW::EPUBMaker::Content.new(file: "#{path.sub(base + '/', '')}/#{f}"))
99
+ end
100
+ end
101
+ if FileTest.directory?("#{path}/#{f}")
102
+ import_imageinfo("#{path}/#{f}", base)
103
+ end
104
+ end
105
+ end
106
+
107
+ alias_method :importImageInfo, :import_imageinfo
108
+
109
+ # Produce EPUB file +epubfile+.
110
+ # +work_dir+ points the directory has contents (default: current directory.)
111
+ # +tmpdir+ defines temporary directory.
112
+ # +base_dir+ is original root dir.
113
+ def produce(epubfile, work_dir, tmpdir = nil, base_dir: nil)
114
+ current = Dir.pwd
115
+ base_dir ||= current
116
+
117
+ # use Dir to solve a path for Windows (see #1011)
118
+ new_tmpdir = Dir[File.join(tmpdir.nil? ? Dir.mktmpdir : tmpdir)][0]
119
+ if epubfile !~ %r{\A/}
120
+ epubfile = "#{current}/#{epubfile}"
121
+ end
122
+
123
+ # FIXME: error check
124
+ File.unlink(epubfile) if File.exist?(epubfile)
125
+
126
+ begin
127
+ @epub.produce(epubfile, work_dir, new_tmpdir, base_dir: base_dir)
128
+ ensure
129
+ FileUtils.rm_r(new_tmpdir) if tmpdir.nil?
130
+ end
131
+ end
132
+
133
+ private
134
+
135
+ def support_legacy_maker
136
+ # legacy review-epubmaker support
137
+ if @config['flag_legacy_coverfile'].nil? && !@config['coverfile'].nil? && File.exist?(@config['coverfile'])
138
+ @config['cover'] = "#{@config['bookname']}-cover.#{@config['htmlext']}"
139
+ @epub.legacy_cover_and_title_file(@config['coverfile'], @config['cover'])
140
+ @config['flag_legacy_coverfile'] = true
141
+ warn %Q(Parameter 'coverfile' is obsolete. Please use 'cover' and make complete html file with header and footer.)
142
+ end
143
+
144
+ if @config['flag_legacy_titlepagefile'].nil? && !@config['titlepagefile'].nil? && File.exist?(@config['titlepagefile'])
145
+ @config['titlefile'] = "#{@config['bookname']}-title.#{@config['htmlext']}"
146
+ @config['titlepage'] = true
147
+ @epub.legacy_cover_and_title_file(@config['titlepagefile'], @config['titlefile'])
148
+ @config['flag_legacy_titlepagefile'] = true
149
+ warn %Q(Parameter 'titlepagefile' is obsolete. Please use 'titlefile' and make complete html file with header and footer.)
150
+ end
151
+
152
+ if @config['flag_legacy_backcoverfile'].nil? && !@config['backcoverfile'].nil? && File.exist?(@config['backcoverfile'])
153
+ @config['backcover'] = "#{@config['bookname']}-backcover.#{@config['htmlext']}"
154
+ @epub.legacy_cover_and_title_file(@config['backcoverfile'], @config['backcover'])
155
+ @config['flag_legacy_backcoverfile'] = true
156
+ warn %Q(Parameter 'backcoverfile' is obsolete. Please use 'backcover' and make complete html file with header and footer.)
157
+ end
158
+
159
+ if @config['flag_legacy_pubhistory'].nil? && @config['pubhistory']
160
+ @config['history'] = [[]]
161
+ @config['pubhistory'].split("\n").each { |date| @config['history'][0].push(date.sub(/(\d+)年(\d+)月(\d+)日/, '\1-\2-\3')) }
162
+ @config['flag_legacy_pubhistory'] = true
163
+ warn %Q(Parameter 'pubhistory' is obsolete. Please use 'history' array.)
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end