review 4.0.0 → 5.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (268) 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 +141 -38
  6. data/Dockerfile +21 -5
  7. data/NEWS.ja.md +338 -1
  8. data/NEWS.md +339 -2
  9. data/README.md +11 -7
  10. data/Rakefile +7 -2
  11. data/appveyor.yml +0 -20
  12. data/bin/review +2 -4
  13. data/bin/review-catalog-converter +4 -4
  14. data/bin/review-check +8 -12
  15. data/bin/review-checkdep +2 -5
  16. data/bin/review-compile +11 -20
  17. data/bin/review-epub2html +1 -4
  18. data/bin/review-epubmaker +3 -4
  19. data/bin/review-idgxmlmaker +1 -3
  20. data/bin/review-index +5 -86
  21. data/bin/review-init +1 -4
  22. data/bin/review-pdfmaker +1 -3
  23. data/bin/review-preproc +3 -5
  24. data/bin/review-textmaker +1 -3
  25. data/bin/review-update +1 -4
  26. data/bin/review-validate +5 -5
  27. data/bin/review-vol +5 -82
  28. data/bin/review-webmaker +1 -3
  29. data/doc/config.yml.sample +55 -12
  30. data/doc/config.yml.sample-simple +4 -3
  31. data/doc/format.ja.md +119 -17
  32. data/doc/format.md +106 -17
  33. data/doc/makeindex.ja.md +2 -2
  34. data/doc/pdfmaker.ja.md +42 -0
  35. data/doc/pdfmaker.md +41 -0
  36. data/doc/quickstart.ja.md +55 -25
  37. data/doc/quickstart.md +47 -17
  38. data/lib/review.rb +1 -1
  39. data/lib/review/book.rb +2 -2
  40. data/lib/review/book/base.rb +69 -30
  41. data/lib/review/book/bib.rb +21 -0
  42. data/lib/review/book/book_unit.rb +158 -0
  43. data/lib/review/book/chapter.rb +33 -26
  44. data/lib/review/book/index.rb +39 -206
  45. data/lib/review/book/index/item.rb +8 -2
  46. data/lib/review/book/page_metric.rb +7 -7
  47. data/lib/review/book/part.rb +26 -11
  48. data/lib/review/book/volume.rb +5 -5
  49. data/lib/review/builder.rb +124 -27
  50. data/lib/review/call_hook.rb +20 -0
  51. data/lib/review/catalog.rb +3 -2
  52. data/lib/review/compiler.rb +197 -91
  53. data/lib/review/configure.rb +95 -9
  54. data/lib/review/converter.rb +1 -1
  55. data/lib/review/epub2html.rb +6 -1
  56. data/lib/review/epubmaker.rb +116 -117
  57. data/lib/review/epubmaker/content.rb +113 -0
  58. data/lib/review/epubmaker/epubcommon.rb +372 -0
  59. data/lib/review/epubmaker/epubv2.rb +178 -0
  60. data/lib/review/epubmaker/epubv3.rb +231 -0
  61. data/lib/review/epubmaker/producer.rb +168 -0
  62. data/lib/review/epubmaker/reviewheaderlistener.rb +12 -2
  63. data/lib/review/epubmaker/zip_exporter.rb +84 -0
  64. data/lib/review/exception.rb +6 -0
  65. data/lib/review/extentions/string.rb +0 -4
  66. data/lib/review/htmlbuilder.rb +132 -87
  67. data/lib/review/htmlutils.rb +8 -11
  68. data/lib/review/i18n.rb +2 -1
  69. data/lib/review/idgxmlbuilder.rb +156 -76
  70. data/lib/review/idgxmlmaker.rb +22 -18
  71. data/lib/review/img_math.rb +245 -0
  72. data/lib/review/index_builder.rb +654 -0
  73. data/lib/review/init.rb +17 -18
  74. data/lib/review/latexbox.rb +58 -0
  75. data/lib/review/latexbuilder.rb +173 -43
  76. data/lib/review/latexutils.rb +9 -1
  77. data/lib/review/lineinput.rb +112 -2
  78. data/lib/review/logger.rb +42 -3
  79. data/lib/review/makerhelper.rb +12 -187
  80. data/lib/review/markdownbuilder.rb +51 -2
  81. data/lib/review/pdfmaker.rb +78 -73
  82. data/lib/review/plaintextbuilder.rb +98 -14
  83. data/lib/review/preprocessor.rb +18 -12
  84. data/lib/review/rstbuilder.rb +28 -9
  85. data/lib/review/sec_counter.rb +14 -0
  86. data/lib/review/template.rb +6 -0
  87. data/lib/review/textmaker.rb +21 -19
  88. data/lib/review/textutils.rb +3 -12
  89. data/lib/review/tocprinter.rb +242 -97
  90. data/lib/review/topbuilder.rb +91 -24
  91. data/lib/review/update.rb +12 -13
  92. data/lib/review/version.rb +1 -1
  93. data/lib/review/volumeprinter.rb +97 -0
  94. data/lib/review/webmaker.rb +34 -33
  95. data/lib/review/webtocprinter.rb +39 -35
  96. data/lib/review/yamlloader.rb +2 -1
  97. data/review.gemspec +5 -3
  98. data/samples/sample-book/src/.gitignore +1 -0
  99. data/samples/sample-book/src/config-ebook.yml +4 -0
  100. data/samples/sample-book/src/config-epub2.yml +1 -1
  101. data/samples/sample-book/src/config-jlreq-ebook.yml +4 -0
  102. data/samples/sample-book/src/config.yml +3 -3
  103. data/samples/sample-book/src/lib/tasks/review.rake +26 -6
  104. data/samples/syntax-book/Gemfile +1 -1
  105. data/samples/syntax-book/ch01.re +3 -1
  106. data/samples/syntax-book/ch02.re +28 -21
  107. data/samples/syntax-book/ch03.re +1 -1
  108. data/samples/syntax-book/config-jlreq-lualatex.yml +4 -0
  109. data/samples/syntax-book/config-print.yml +3 -0
  110. data/samples/syntax-book/config.yml +1 -1
  111. data/samples/syntax-book/images/img3-2.png +0 -0
  112. data/samples/syntax-book/lib/tasks/review.rake +23 -8
  113. data/templates/html/_colophon.html.erb +23 -0
  114. data/templates/html/_colophon_history.html.erb +9 -0
  115. data/templates/html/_cover.html.erb +10 -0
  116. data/templates/html/_part_body.html.erb +6 -0
  117. data/templates/html/_titlepage.html.erb +20 -0
  118. data/templates/html/layout-html5.html.erb +6 -0
  119. data/templates/html/layout-xhtml1.html.erb +6 -0
  120. data/templates/latex/config.erb +41 -29
  121. data/templates/latex/review-jlreq/README.md +3 -1
  122. data/templates/latex/review-jlreq/review-base.sty +47 -22
  123. data/templates/latex/review-jlreq/review-jlreq.cls +25 -24
  124. data/templates/latex/review-jlreq/review-style.sty +6 -1
  125. data/templates/latex/review-jlreq/review-tcbox.sty +348 -0
  126. data/templates/latex/review-jlreq/reviewmacro.sty +5 -0
  127. data/templates/latex/review-jsbook/README.md +7 -5
  128. data/templates/latex/review-jsbook/review-base.sty +47 -21
  129. data/templates/latex/review-jsbook/review-jsbook.cls +12 -2
  130. data/templates/latex/review-jsbook/review-style.sty +6 -1
  131. data/templates/latex/review-jsbook/review-tcbox.sty +348 -0
  132. data/templates/latex/review-jsbook/reviewmacro.sty +5 -0
  133. data/templates/opf/epubv2.opf.erb +7 -7
  134. data/templates/opf/epubv3.opf.erb +7 -7
  135. data/templates/opf/opf_manifest_epubv2.opf.erb +10 -0
  136. data/templates/opf/opf_manifest_epubv3.opf.erb +10 -0
  137. data/templates/opf/opf_metainfo_epubv2.opf.erb +17 -0
  138. data/templates/opf/opf_metainfo_epubv3.opf.erb +49 -0
  139. data/templates/opf/opf_tocx_epubv2.opf.erb +9 -0
  140. data/templates/opf/opf_tocx_epubv3.opf.erb +17 -0
  141. data/templates/web/html/layout-html5.html.erb +9 -8
  142. data/templates/web/html/layout-xhtml1.html.erb +6 -0
  143. data/test/assets/header_listener.html +35 -0
  144. data/test/assets/img_math/img1.png +0 -0
  145. data/test/assets/img_math/img2.png +0 -0
  146. data/test/assets/img_math/img3.png +0 -0
  147. data/test/assets/syntax_book_index_detail.txt +58 -0
  148. data/test/assets/test_template.tex +12 -9
  149. data/test/assets/test_template_backmatter.tex +12 -9
  150. data/test/book_test_helper.rb +11 -5
  151. data/test/run_test.rb +1 -1
  152. data/test/test_book.rb +62 -63
  153. data/test/test_book_chapter.rb +99 -56
  154. data/test/test_book_part.rb +3 -3
  155. data/test/test_builder.rb +24 -15
  156. data/test/test_catalog.rb +1 -0
  157. data/test/test_catalog_converter_cmd.rb +1 -1
  158. data/test/test_converter.rb +1 -0
  159. data/test/test_epub3maker.rb +170 -126
  160. data/test/test_epubmaker.rb +249 -129
  161. data/test/test_epubmaker_cmd.rb +14 -7
  162. data/test/test_helper.rb +23 -11
  163. data/test/test_htmlbuilder.rb +956 -76
  164. data/test/test_htmlutils.rb +0 -12
  165. data/test/test_i18n.rb +33 -33
  166. data/test/test_idgxmlbuilder.rb +568 -10
  167. data/test/test_idgxmlmaker_cmd.rb +50 -0
  168. data/test/test_image_finder.rb +52 -70
  169. data/test/test_img_math.rb +111 -0
  170. data/test/test_index.rb +62 -52
  171. data/test/test_indexbuilder.rb +52 -0
  172. data/test/test_latexbuilder.rb +1056 -30
  173. data/test/test_latexbuilder_v2.rb +52 -12
  174. data/test/test_lineinput.rb +20 -93
  175. data/test/test_logger.rb +7 -7
  176. data/test/test_makerhelper.rb +0 -12
  177. data/test/test_markdownbuilder.rb +32 -0
  178. data/test/test_pdfmaker.rb +100 -11
  179. data/test/test_pdfmaker_cmd.rb +101 -7
  180. data/test/test_plaintextbuilder.rb +531 -25
  181. data/test/test_review_ext.rb +2 -1
  182. data/test/test_reviewheaderlistener.rb +49 -0
  183. data/test/test_rstbuilder.rb +25 -1
  184. data/test/test_sec_counter.rb +156 -0
  185. data/test/test_template.rb +12 -2
  186. data/test/test_textmaker_cmd.rb +58 -0
  187. data/test/test_tocprinter.rb +46 -0
  188. data/test/test_topbuilder.rb +365 -10
  189. data/test/test_update.rb +44 -44
  190. data/test/test_webtocprinter.rb +75 -43
  191. data/test/test_zip_exporter.rb +5 -6
  192. data/vendor/gentombow/LICENSE +1 -1
  193. data/vendor/gentombow/Makefile +0 -1
  194. data/vendor/gentombow/bounddvi-en.pdf +0 -0
  195. data/vendor/gentombow/bounddvi-en.tex +1 -0
  196. data/vendor/gentombow/bounddvi.pdf +0 -0
  197. data/vendor/gentombow/bounddvi.sty +30 -7
  198. data/vendor/gentombow/bounddvi.tex +1 -0
  199. data/vendor/gentombow/create_archive.sh +1 -0
  200. data/vendor/gentombow/gentombow-ja.pdf +0 -0
  201. data/vendor/gentombow/gentombow-ja.tex +9 -0
  202. data/vendor/gentombow/gentombow.pdf +0 -0
  203. data/vendor/gentombow/gentombow.sty +32 -10
  204. data/vendor/gentombow/gentombow.tex +8 -0
  205. data/vendor/gentombow/tests/gentombow-01-pdfx.tex +8 -0
  206. data/vendor/gentombow/tests/gentombow-02-pdfx.tex +8 -0
  207. data/vendor/jsclasses/LICENSE +1 -1
  208. data/vendor/jsclasses/Makefile +3 -2
  209. data/vendor/jsclasses/create_archive.sh +5 -5
  210. data/vendor/jsclasses/jis/Makefile +3 -2
  211. data/vendor/jsclasses/jis/jsarticle.cls +74 -31
  212. data/vendor/jsclasses/jis/jsbook.cls +74 -31
  213. data/vendor/jsclasses/jis/jsclasses.dtx +176 -36
  214. data/vendor/jsclasses/jis/jsclasses.ins +15 -5
  215. data/vendor/jsclasses/jis/jslogo.dtx +4 -4
  216. data/vendor/jsclasses/jis/jslogo.ins +9 -0
  217. data/vendor/jsclasses/jis/jslogo.sty +4 -16
  218. data/vendor/jsclasses/jis/jspf.cls +73 -30
  219. data/vendor/jsclasses/jis/jsreport.cls +74 -31
  220. data/vendor/jsclasses/jis/jsverb.ins +9 -0
  221. data/vendor/jsclasses/jis/jsverb.sty +1 -13
  222. data/vendor/jsclasses/jis/kiyou.cls +74 -31
  223. data/vendor/jsclasses/jis/minijs.sty +65 -22
  224. data/vendor/jsclasses/jis/okumacro.dtx +4 -5
  225. data/vendor/jsclasses/jis/okumacro.ins +9 -0
  226. data/vendor/jsclasses/jis/okumacro.sty +4 -17
  227. data/vendor/jsclasses/jis/okuverb.ins +9 -0
  228. data/vendor/jsclasses/jis/okuverb.sty +1 -13
  229. data/vendor/jsclasses/jis/winjis.sty +23 -19
  230. data/vendor/jsclasses/jsarticle.cls +74 -31
  231. data/vendor/jsclasses/jsbook.cls +74 -31
  232. data/vendor/jsclasses/jsclasses.dtx +176 -36
  233. data/vendor/jsclasses/jsclasses.ins +15 -5
  234. data/vendor/jsclasses/jsclasses.pdf +0 -0
  235. data/vendor/jsclasses/jslogo.dtx +4 -4
  236. data/vendor/jsclasses/jslogo.ins +9 -0
  237. data/vendor/jsclasses/jslogo.pdf +0 -0
  238. data/vendor/jsclasses/jslogo.sty +4 -16
  239. data/vendor/jsclasses/jspf.cls +73 -30
  240. data/vendor/jsclasses/jsreport.cls +74 -31
  241. data/vendor/jsclasses/jsverb.ins +9 -0
  242. data/vendor/jsclasses/jsverb.pdf +0 -0
  243. data/vendor/jsclasses/jsverb.sty +1 -13
  244. data/vendor/jsclasses/kiyou.cls +74 -31
  245. data/vendor/jsclasses/minijs.sty +68 -22
  246. data/vendor/jsclasses/okumacro.dtx +4 -5
  247. data/vendor/jsclasses/okumacro.ins +9 -0
  248. data/vendor/jsclasses/okumacro.pdf +0 -0
  249. data/vendor/jsclasses/okumacro.sty +4 -17
  250. data/vendor/jsclasses/okuverb.ins +9 -0
  251. data/vendor/jsclasses/okuverb.pdf +0 -0
  252. data/vendor/jsclasses/okuverb.sty +1 -13
  253. data/vendor/jsclasses/tests/relfont.tex +10 -0
  254. data/vendor/jsclasses/winjis.sty +23 -19
  255. metadata +109 -20
  256. data/.rubocop_todo.yml +0 -7
  257. data/lib/epubmaker.rb +0 -23
  258. data/lib/epubmaker/content.rb +0 -110
  259. data/lib/epubmaker/epubcommon.rb +0 -441
  260. data/lib/epubmaker/epubv2.rb +0 -143
  261. data/lib/epubmaker/epubv3.rb +0 -233
  262. data/lib/epubmaker/producer.rb +0 -375
  263. data/lib/epubmaker/zip_exporter.rb +0 -81
  264. data/lib/lineinput.rb +0 -155
  265. data/lib/review/book/compilable.rb +0 -178
  266. data/lib/review/tocparser.rb +0 -271
  267. data/samples/syntax-book/review-ext.rb +0 -14
  268. data/test/test_tocparser.rb +0 -25
@@ -7,6 +7,15 @@
7
7
  #
8
8
  module ReVIEW
9
9
  class EPUBMaker
10
+ # Listener class to scan HTML and get heading information
11
+ #
12
+ # The heading information this listener will retrieve is as follows:
13
+ #
14
+ # * level: Heading level (1..6)
15
+ # * id: HTMl ID attribute. Basically the `id` attribute of the h(1-6) element, but if there is an `a` element within the h(1-6) element, it will be its `id` attribute.
16
+ # * title: The title string of the headline. Usually, it is the text within the h(1-6) element, but if there is an `img` element, it will be the text with its `alt` attribute.
17
+ # * notoc: The `notoc` attribute of the headline element.
18
+ #
10
19
  class ReVIEWHeaderListener
11
20
  include REXML::StreamListener
12
21
  def initialize(headlines)
@@ -18,10 +27,11 @@ module ReVIEW
18
27
  def tag_start(name, attrs)
19
28
  if name =~ /\Ah(\d+)/
20
29
  raise "#{name}, #{attrs}" if @level.present?
30
+
21
31
  @level = $1.to_i
22
32
  @id = attrs['id'] if attrs['id'].present?
23
33
  @notoc = attrs['notoc'] if attrs['notoc'].present?
24
- elsif !@level.nil?
34
+ elsif @level.present? # if in <hN> tag
25
35
  if name == 'img' && attrs['alt'].present?
26
36
  @content << attrs['alt']
27
37
  elsif name == 'a' && attrs['id'].present?
@@ -49,7 +59,7 @@ module ReVIEW
49
59
 
50
60
  def text(text)
51
61
  if @level.present?
52
- @content << text.gsub("\t", ' ')
62
+ @content << text.tr("\t", ' ')
53
63
  end
54
64
  end
55
65
  end
@@ -0,0 +1,84 @@
1
+ # Copyright (c) 2010-2017 Kenshi Muto and Masayoshi Takahashi
2
+ #
3
+ # This program is free software.
4
+ # You can distribute or modify this program under the terms of
5
+ # the GNU LGPL, Lesser General Public License version 2.1.
6
+ # For details of the GNU LGPL, see the file "COPYING".
7
+ #
8
+
9
+ require 'pathname'
10
+ begin
11
+ require 'zip'
12
+ rescue LoadError
13
+ ## I cannot find rubyzip library, so I use external zip command.
14
+ warn 'rubyzip not found, so use external zip command'
15
+ end
16
+
17
+ module ReVIEW
18
+ class EPUBMaker
19
+ ##
20
+ # Export into zip file for EPUB producer.
21
+ #
22
+ class ZipExporter
23
+ attr_reader :tmpdir
24
+
25
+ def initialize(tmpdir, config)
26
+ @tmpdir = tmpdir
27
+ @config = config
28
+ end
29
+
30
+ def export_zip(epubfile)
31
+ if defined?(Zip)
32
+ export_zip_rubyzip(epubfile)
33
+ else
34
+ export_zip_extcmd(epubfile)
35
+ end
36
+ end
37
+
38
+ def export_zip_extcmd(epubfile)
39
+ stage1 = @config['epubmaker']['zip_stage1'].to_s.split
40
+ path1 = stage1[0] || 'zip'
41
+ opt1 = stage1[1] || '-0Xq'
42
+ stage2 = @config['epubmaker']['zip_stage2'].to_s.split
43
+ path2 = stage2[0] || 'zip'
44
+ opt2 = stage2[1] || '-Xr9Dq'
45
+
46
+ Dir.chdir(tmpdir) do
47
+ system(path1, opt1, epubfile, 'mimetype')
48
+ addpath = @config['epubmaker']['zip_addpath']
49
+ if addpath
50
+ system(path2, opt2, epubfile, 'META-INF', 'OEBPS', addpath)
51
+ else
52
+ system(path2, opt2, epubfile, 'META-INF', 'OEBPS')
53
+ end
54
+ end
55
+ end
56
+
57
+ def export_zip_rubyzip(epubfile)
58
+ Dir.chdir(tmpdir) do
59
+ Zip::OutputStream.open(epubfile) do |epub|
60
+ root_pathname = Pathname.new(tmpdir)
61
+ epub.put_next_entry('mimetype', nil, nil, Zip::Entry::STORED)
62
+ epub << 'application/epub+zip'
63
+
64
+ export_zip_rubyzip_addpath(epub, File.join(tmpdir, 'META-INF'), root_pathname)
65
+ export_zip_rubyzip_addpath(epub, File.join(tmpdir, 'OEBPS'), root_pathname)
66
+ if @config['zip_addpath'].present?
67
+ export_zip_rubyzip_addpath(epub, File.join(tmpdir, @config['zip_addpath']), root_pathname)
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ def export_zip_rubyzip_addpath(epub, dirname, rootdir)
74
+ Dir[File.join(dirname, '**', '**')].each do |path|
75
+ next if File.directory?(path)
76
+
77
+ relpath = Pathname.new(path).relative_path_from(rootdir)
78
+ epub.put_next_entry(relpath)
79
+ epub << File.binread(path)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -10,10 +10,16 @@
10
10
 
11
11
  module ReVIEW
12
12
  class Error < ::StandardError; end
13
+
13
14
  class ApplicationError < Error; end
15
+
14
16
  class ConfigError < ApplicationError; end
17
+
15
18
  class CompileError < ApplicationError; end
19
+
16
20
  class SyntaxError < CompileError; end
21
+
17
22
  class FileNotFound < ApplicationError; end
23
+
18
24
  class KeyError < CompileError; end
19
25
  end
@@ -2,7 +2,3 @@ if defined?(Encoding) && Encoding.respond_to?('default_external') &&
2
2
  Encoding.default_external != Encoding::UTF_8
3
3
  Encoding.default_external = 'UTF-8'
4
4
  end
5
-
6
- class String
7
- alias_method :each, :each_line
8
- end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2008-2019 Minero Aoki, Kenshi Muto, Masayoshi Takahashi,
1
+ # Copyright (c) 2008-2020 Minero Aoki, Kenshi Muto, Masayoshi Takahashi,
2
2
  # KADO Masanori
3
3
  # 2002-2007 Minero Aoki
4
4
  #
@@ -41,10 +41,6 @@ module ReVIEW
41
41
  ".#{@book.config['htmlext']}"
42
42
  end
43
43
 
44
- def builder_init
45
- end
46
- private :builder_init
47
-
48
44
  def builder_init_file
49
45
  @noindent = nil
50
46
  @ol_num = nil
@@ -57,6 +53,7 @@ module ReVIEW
57
53
  @first_line_num = nil
58
54
  @body_ext = nil
59
55
  @toc = nil
56
+ @javascripts = []
60
57
  end
61
58
  private :builder_init_file
62
59
 
@@ -78,6 +75,7 @@ module ReVIEW
78
75
  if !File.exist?(layout_file) && File.exist?(File.join(@book.basedir, 'layouts', 'layout.erb'))
79
76
  raise ReVIEW::ConfigError, 'layout.erb is obsoleted. Please use layout.html.erb.'
80
77
  end
78
+
81
79
  if File.exist?(layout_file)
82
80
  if ENV['REVIEW_SAFE_MODE'].to_i & 4 > 0
83
81
  warn %Q(user's layout is prohibited in safe mode. ignored.)
@@ -92,7 +90,7 @@ module ReVIEW
92
90
  def result
93
91
  # default XHTML header/footer
94
92
  @title = strip_html(compile_inline(@chapter.title))
95
- @body = @output.string
93
+ @body = solve_nest(@output.string)
96
94
  @language = @book.config['language']
97
95
  @stylesheets = @book.config['stylesheet']
98
96
  @next = @chapter.next_chapter
@@ -104,9 +102,28 @@ module ReVIEW
104
102
  @toc = ReVIEW::WEBTOCPrinter.book_to_string(@book)
105
103
  end
106
104
 
105
+ if @book.config['math_format'] == 'mathjax'
106
+ @javascripts.push(%Q(<script>MathJax = { tex: { inlineMath: [['\\\\(', '\\\\)']] }, svg: { fontCache: 'global' } };</script>))
107
+ @javascripts.push(%Q(<script type="text/javascript" id="MathJax-script" async="true" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>))
108
+ end
109
+
107
110
  ReVIEW::Template.load(layoutfile).result(binding)
108
111
  end
109
112
 
113
+ def solve_nest(s)
114
+ check_nest
115
+ s.gsub("</dd>\n</dl>\n\x01→dl←\x01", '').
116
+ gsub("\x01→/dl←\x01", "</dd>\n</dl>←END\x01").
117
+ gsub("</li>\n</ul>\n\x01→ul←\x01", '').
118
+ gsub("\x01→/ul←\x01", "</li>\n</ul>←END\x01").
119
+ gsub("</li>\n</ol>\n\x01→ol←\x01", '').
120
+ gsub("\x01→/ol←\x01", "</li>\n</ol>←END\x01").
121
+ gsub("</dl>←END\x01\n<dl>", '').
122
+ gsub("</ul>←END\x01\n<ul>", '').
123
+ gsub("</ol>←END\x01\n<ol>", '').
124
+ gsub("←END\x01", '')
125
+ end
126
+
110
127
  def xmlns_ops_prefix
111
128
  if @book.config['epubversion'].to_i == 3
112
129
  'epub'
@@ -139,6 +156,7 @@ module ReVIEW
139
156
  @nonum_counter += 1
140
157
  puts if level > 1
141
158
  return unless caption.present?
159
+
142
160
  if label
143
161
  puts %Q(<h#{level} id="#{normalize_id(label)}">#{compile_inline(caption)}</h#{level}>)
144
162
  else
@@ -154,6 +172,7 @@ module ReVIEW
154
172
  @nonum_counter += 1
155
173
  puts if level > 1
156
174
  return unless caption.present?
175
+
157
176
  if label
158
177
  puts %Q(<h#{level} id="#{normalize_id(label)}" notoc="true">#{compile_inline(caption)}</h#{level}>)
159
178
  else
@@ -169,6 +188,7 @@ module ReVIEW
169
188
  @nonum_counter += 1
170
189
  puts '' if level > 1
171
190
  return unless caption.present?
191
+
172
192
  if label
173
193
  puts %Q(<a id="#{normalize_id(label)}" /><h#{level} id="#{normalize_id(label)}" hidden="true">#{compile_inline(caption)}</h#{level}>)
174
194
  else
@@ -228,6 +248,7 @@ module ReVIEW
228
248
  end
229
249
 
230
250
  def captionblock(type, lines, caption)
251
+ check_nested_minicolumn
231
252
  puts %Q(<div class="#{type}">)
232
253
  if caption.present?
233
254
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
@@ -286,15 +307,25 @@ module ReVIEW
286
307
  end
287
308
 
288
309
  def box(lines, caption = nil)
289
- puts %Q(<div class="syntax">)
310
+ captionstr = nil
290
311
  if caption.present?
291
- puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
312
+ captionstr = %Q(<p class="caption">#{compile_inline(caption)}</p>)
313
+ end
314
+ puts %Q(<div class="syntax">)
315
+
316
+ if caption_top?('list') && caption.present?
317
+ puts captionstr
292
318
  end
319
+
293
320
  print %Q(<pre class="syntax">)
294
321
  lines.each do |line|
295
322
  puts detab(line)
296
323
  end
297
324
  puts '</pre>'
325
+
326
+ if !caption_top?('list') && caption.present?
327
+ puts captionstr
328
+ end
298
329
  puts '</div>'
299
330
  end
300
331
 
@@ -302,6 +333,24 @@ module ReVIEW
302
333
  captionblock('note', lines, caption)
303
334
  end
304
335
 
336
+ CAPTION_TITLES.each do |name|
337
+ class_eval %Q(
338
+ def #{name}_begin(caption = nil)
339
+ check_nested_minicolumn
340
+ @doc_status[:minicolumn] = '#{name}'
341
+ puts %Q(<div class="#{name}">)
342
+ if caption.present?
343
+ puts %Q(<p class="caption">\#{compile_inline(caption)}</p>)
344
+ end
345
+ end
346
+
347
+ def #{name}_end
348
+ puts '</div>'
349
+ @doc_status[:minicolumn] = nil
350
+ end
351
+ ), __FILE__, __LINE__ - 14
352
+ end
353
+
305
354
  def ul_begin
306
355
  puts '<ul>'
307
356
  end
@@ -373,12 +422,7 @@ module ReVIEW
373
422
 
374
423
  def list(lines, id, caption, lang = nil)
375
424
  puts %Q(<div id="#{normalize_id(id)}" class="caption-code">)
376
- begin
377
- list_header(id, caption, lang)
378
- rescue KeyError
379
- error "no such list: #{id}"
380
- end
381
- list_body(id, lines, lang)
425
+ super(lines, id, caption, lang)
382
426
  puts '</div>'
383
427
  end
384
428
 
@@ -403,8 +447,7 @@ module ReVIEW
403
447
 
404
448
  def source(lines, caption = nil, lang = nil)
405
449
  puts %Q(<div class="source-code">)
406
- source_header(caption)
407
- source_body(caption, lines, lang)
450
+ super(lines, caption, lang)
408
451
  puts '</div>'
409
452
  end
410
453
 
@@ -414,7 +457,7 @@ module ReVIEW
414
457
  end
415
458
  end
416
459
 
417
- def source_body(_id, lines, lang)
460
+ def source_body(lines, lang)
418
461
  print %Q(<pre class="source">)
419
462
  body = lines.inject('') { |i, j| i + detab(j) + "\n" }
420
463
  lexer = lang
@@ -424,12 +467,7 @@ module ReVIEW
424
467
 
425
468
  def listnum(lines, id, caption, lang = nil)
426
469
  puts %Q(<div id="#{normalize_id(id)}" class="code">)
427
- begin
428
- list_header(id, caption, lang)
429
- rescue KeyError
430
- error "no such list: #{id}"
431
- end
432
- listnum_body(lines, lang)
470
+ super(lines, id, caption, lang)
433
471
  puts '</div>'
434
472
  end
435
473
 
@@ -455,7 +493,7 @@ module ReVIEW
455
493
 
456
494
  def emlist(lines, caption = nil, lang = nil)
457
495
  puts %Q(<div class="emlist-code">)
458
- if caption.present?
496
+ if caption_top?('list') && caption.present?
459
497
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
460
498
  end
461
499
  class_names = ['emlist']
@@ -466,12 +504,15 @@ module ReVIEW
466
504
  lexer = lang
467
505
  puts highlight(body: body, lexer: lexer, format: 'html')
468
506
  puts '</pre>'
507
+ if !caption_top?('list') && caption.present?
508
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
509
+ end
469
510
  puts '</div>'
470
511
  end
471
512
 
472
513
  def emlistnum(lines, caption = nil, lang = nil)
473
514
  puts %Q(<div class="emlistnum-code">)
474
- if caption.present?
515
+ if caption_top?('list') && caption.present?
475
516
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
476
517
  end
477
518
 
@@ -493,19 +534,29 @@ module ReVIEW
493
534
  puts '</pre>'
494
535
  end
495
536
 
537
+ if !caption_top?('list') && caption.present?
538
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
539
+ end
540
+
496
541
  puts '</div>'
497
542
  end
498
543
 
499
544
  def cmd(lines, caption = nil)
500
545
  puts %Q(<div class="cmd-code">)
501
- if caption.present?
546
+ if caption_top?('list') && caption.present?
502
547
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
503
548
  end
549
+
504
550
  print %Q(<pre class="cmd">)
505
551
  body = lines.inject('') { |i, j| i + detab(j) + "\n" }
506
552
  lexer = 'shell-session'
507
553
  puts highlight(body: body, lexer: lexer, format: 'html')
508
554
  puts '</pre>'
555
+
556
+ if !caption_top?('list') && caption.present?
557
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
558
+ end
559
+
509
560
  puts '</div>'
510
561
  end
511
562
 
@@ -541,12 +592,13 @@ module ReVIEW
541
592
  def texequation(lines, id = nil, caption = '')
542
593
  if id
543
594
  puts %Q(<div id="#{normalize_id(id)}" class="caption-equation">)
544
- texequation_header(id, caption)
595
+ texequation_header(id, caption) if caption_top?('equation')
545
596
  end
546
597
 
547
598
  texequation_body(lines)
548
599
 
549
600
  if id
601
+ texequation_header(id, caption) unless caption_top?('equation')
550
602
  puts '</div>'
551
603
  end
552
604
  end
@@ -561,24 +613,27 @@ module ReVIEW
561
613
 
562
614
  def texequation_body(lines)
563
615
  puts %Q(<div class="equation">)
564
- if @book.config['mathml']
565
- require 'math_ml'
566
- require 'math_ml/symbol/character_reference'
616
+ if @book.config['math_format'] == 'mathml'
617
+ begin
618
+ require 'math_ml'
619
+ require 'math_ml/symbol/character_reference'
620
+ rescue LoadError
621
+ error 'not found math_ml'
622
+ end
567
623
  p = MathML::LaTeX::Parser.new(symbol: MathML::Symbol::CharacterReference)
568
624
  print p.parse(lines.join("\n") + "\n", true)
569
- elsif @book.config['imgmath']
625
+ elsif @book.config['math_format'] == 'mathjax'
626
+ puts "$$#{lines.join("\n")}$$"
627
+ elsif @book.config['math_format'] == 'imgmath'
570
628
  fontsize = @book.config['imgmath_options']['fontsize'].to_f
571
629
  lineheight = @book.config['imgmath_options']['lineheight'].to_f
572
630
  math_str = "\\begin{equation*}\n\\fontsize{#{fontsize}}{#{lineheight}}\\selectfont\n#{lines.join("\n")}\n\\end{equation*}\n"
573
631
  key = Digest::SHA256.hexdigest(math_str)
574
- math_dir = File.join(@book.config['imagedir'], '_review_math')
575
- Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
576
- img_path = File.join(math_dir, "_gen_#{key}.#{@book.config['imgmath_options']['format']}")
577
632
  if @book.config.check_version('2', exception: false)
578
- make_math_image(math_str, img_path)
633
+ img_path = @img_math.make_math_image(math_str, key)
579
634
  puts %Q(<img src="#{img_path}" />)
580
635
  else
581
- defer_math_image(math_str, img_path, key)
636
+ img_path = @img_math.defer_math_image(math_str, key)
582
637
  puts %Q(<img src="#{img_path}" class="math_gen_#{key}" alt="#{escape(lines.join(' '))}" />)
583
638
  end
584
639
  else
@@ -614,20 +669,22 @@ module ReVIEW
614
669
  def image_image(id, caption, metric)
615
670
  metrics = parse_metric('html', metric)
616
671
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
672
+ image_header(id, caption) if caption_top?('image')
617
673
  puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
618
- image_header(id, caption)
674
+ image_header(id, caption) unless caption_top?('image')
619
675
  puts '</div>'
620
676
  end
621
677
 
622
678
  def image_dummy(id, caption, lines)
623
679
  warn "image not bound: #{id}"
624
680
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
681
+ image_header(id, caption) if caption_top?('image')
625
682
  puts %Q(<pre class="dummyimage">)
626
683
  lines.each do |line|
627
684
  puts detab(line)
628
685
  end
629
686
  puts '</pre>'
630
- image_header(id, caption)
687
+ image_header(id, caption) unless caption_top?('image')
631
688
  puts '</div>'
632
689
  end
633
690
 
@@ -690,15 +747,19 @@ module ReVIEW
690
747
 
691
748
  puts %Q(<div id="#{normalize_id(id)}" class="imgtable image">)
692
749
  begin
693
- if caption.present?
750
+ if caption_top?('table') && caption.present?
751
+ table_header(id, caption)
752
+ end
753
+
754
+ imgtable_image(id, caption, metric)
755
+
756
+ if !caption_top?('table') && caption.present?
694
757
  table_header(id, caption)
695
758
  end
696
759
  rescue KeyError
697
760
  error "no such table: #{id}"
698
761
  end
699
762
 
700
- imgtable_image(id, caption, metric)
701
-
702
763
  puts '</div>'
703
764
  end
704
765
 
@@ -713,6 +774,7 @@ module ReVIEW
713
774
 
714
775
  def comment(lines, comment = nil)
715
776
  return unless @book.config['draft']
777
+
716
778
  lines ||= []
717
779
  lines.unshift(escape(comment)) unless comment.blank?
718
780
  str = lines.join('<br />')
@@ -735,7 +797,19 @@ module ReVIEW
735
797
  def indepimage(lines, id, caption = '', metric = nil)
736
798
  metrics = parse_metric('html', metric)
737
799
  caption = '' unless caption.present?
800
+ caption_str = nil
801
+ if caption.present?
802
+ caption_str = <<-EOS
803
+ <p class="caption">
804
+ #{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)}
805
+ </p>
806
+ EOS
807
+ end
808
+
738
809
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
810
+ if caption_top?('image') && caption.present?
811
+ puts caption_str
812
+ end
739
813
  begin
740
814
  puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
741
815
  rescue
@@ -749,10 +823,8 @@ module ReVIEW
749
823
  end
750
824
  end
751
825
 
752
- if caption.present?
753
- puts %Q(<p class="caption">)
754
- puts %Q(#{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)})
755
- puts '</p>'
826
+ if !caption_top?('image') && caption.present?
827
+ puts caption_str
756
828
  end
757
829
  puts '</div>'
758
830
  end
@@ -913,22 +985,25 @@ module ReVIEW
913
985
  end
914
986
 
915
987
  def inline_m(str)
916
- if @book.config['mathml']
917
- require 'math_ml'
918
- require 'math_ml/symbol/character_reference'
988
+ if @book.config['math_format'] == 'mathml'
989
+ begin
990
+ require 'math_ml'
991
+ require 'math_ml/symbol/character_reference'
992
+ rescue LoadError
993
+ error 'not found math_ml'
994
+ end
919
995
  parser = MathML::LaTeX::Parser.new(symbol: MathML::Symbol::CharacterReference)
920
996
  %Q(<span class="equation">#{parser.parse(str, nil)}</span>)
921
- elsif @book.config['imgmath']
997
+ elsif @book.config['math_format'] == 'mathjax'
998
+ %Q(<span class="equation">\\( #{str} \\)</span>)
999
+ elsif @book.config['math_format'] == 'imgmath'
922
1000
  math_str = '$' + str + '$'
923
1001
  key = Digest::SHA256.hexdigest(str)
924
- math_dir = File.join(@book.config['imagedir'], '_review_math')
925
- Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
926
- img_path = File.join(math_dir, "_gen_#{key}.#{@book.config['imgmath_options']['format']}")
927
1002
  if @book.config.check_version('2', exception: false)
928
- make_math_image(math_str, img_path)
1003
+ img_path = @img_math.make_math_image(math_str, key)
929
1004
  %Q(<span class="equation"><img src="#{img_path}" /></span>)
930
1005
  else
931
- defer_math_image(math_str, img_path, key)
1006
+ img_path = @img_math.defer_math_image(math_str, key)
932
1007
  %Q(<span class="equation"><img src="#{img_path}" class="math_gen_#{key}" alt="#{escape(str)}" /></span>)
933
1008
  end
934
1009
  else
@@ -972,7 +1047,7 @@ module ReVIEW
972
1047
  str = I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
973
1048
  end
974
1049
  if @book.config['chapterlink']
975
- anchor = 'h' + n.gsub('.', '-')
1050
+ anchor = 'h' + n.tr('.', '-')
976
1051
  %Q(<a href="#{chap.id}#{extname}##{anchor}">#{str}</a>)
977
1052
  else
978
1053
  str
@@ -989,7 +1064,7 @@ module ReVIEW
989
1064
 
990
1065
  def inline_column_chap(chapter, id)
991
1066
  if @book.config['chapterlink']
992
- %Q(<a href="\##{column_label(id, chapter)}" class="columnref">#{I18n.t('column', compile_inline(chapter.column(id).caption))}</a>)
1067
+ %Q(<a href="#{chapter.id}#{extname}##{column_label(id, chapter)}" class="columnref">#{I18n.t('column', compile_inline(chapter.column(id).caption))}</a>)
993
1068
  else
994
1069
  I18n.t('column', compile_inline(chapter.column(id).caption))
995
1070
  end
@@ -1151,7 +1226,7 @@ module ReVIEW
1151
1226
  %Q(<span class="balloon">#{escape_html(str)}</span>)
1152
1227
  end
1153
1228
 
1154
- def inline_raw(str)
1229
+ def inline_raw(str) # rubocop:disable Lint/UselessMethodDefinition
1155
1230
  super(str)
1156
1231
  end
1157
1232
 
@@ -1182,35 +1257,5 @@ module ReVIEW
1182
1257
  def olnum(num)
1183
1258
  @ol_num = num.to_i
1184
1259
  end
1185
-
1186
- def make_math_image(str, path, fontsize = 12)
1187
- # Re:VIEW 2 compatibility
1188
- fontsize2 = (fontsize * 1.2).round.to_i
1189
- texsrc = <<-EOB
1190
- \\documentclass[12pt]{article}
1191
- \\usepackage[utf8]{inputenc}
1192
- \\usepackage{amsmath}
1193
- \\usepackage{amsthm}
1194
- \\usepackage{amssymb}
1195
- \\usepackage{amsfonts}
1196
- \\usepackage{anyfontsize}
1197
- \\usepackage{bm}
1198
- \\pagestyle{empty}
1199
-
1200
- \\begin{document}
1201
- \\fontsize{#{fontsize}}{#{fontsize2}}\\selectfont #{str}
1202
- \\end{document}
1203
- EOB
1204
- Dir.mktmpdir do |tmpdir|
1205
- tex_path = File.join(tmpdir, 'tmpmath.tex')
1206
- dvi_path = File.join(tmpdir, 'tmpmath.dvi')
1207
- File.write(tex_path, texsrc)
1208
- cmd = "latex --interaction=nonstopmode --output-directory=#{tmpdir} #{tex_path} && dvipng -T tight -z9 -o #{path} #{dvi_path}"
1209
- out, status = Open3.capture2e(cmd)
1210
- unless status.success?
1211
- error "latex compile error\n\nError log:\n" + out
1212
- end
1213
- end
1214
- end
1215
1260
  end
1216
1261
  end # module ReVIEW