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
@@ -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
  #
@@ -12,7 +12,6 @@ require 'review/htmlutils'
12
12
  require 'review/template'
13
13
  require 'review/textutils'
14
14
  require 'review/webtocprinter'
15
- require 'digest'
16
15
  require 'tmpdir'
17
16
  require 'open3'
18
17
 
@@ -42,10 +41,6 @@ module ReVIEW
42
41
  ".#{@book.config['htmlext']}"
43
42
  end
44
43
 
45
- def builder_init
46
- end
47
- private :builder_init
48
-
49
44
  def builder_init_file
50
45
  @noindent = nil
51
46
  @ol_num = nil
@@ -58,6 +53,7 @@ module ReVIEW
58
53
  @first_line_num = nil
59
54
  @body_ext = nil
60
55
  @toc = nil
56
+ @javascripts = []
61
57
  end
62
58
  private :builder_init_file
63
59
 
@@ -79,6 +75,7 @@ module ReVIEW
79
75
  if !File.exist?(layout_file) && File.exist?(File.join(@book.basedir, 'layouts', 'layout.erb'))
80
76
  raise ReVIEW::ConfigError, 'layout.erb is obsoleted. Please use layout.html.erb.'
81
77
  end
78
+
82
79
  if File.exist?(layout_file)
83
80
  if ENV['REVIEW_SAFE_MODE'].to_i & 4 > 0
84
81
  warn %Q(user's layout is prohibited in safe mode. ignored.)
@@ -93,7 +90,7 @@ module ReVIEW
93
90
  def result
94
91
  # default XHTML header/footer
95
92
  @title = strip_html(compile_inline(@chapter.title))
96
- @body = @output.string
93
+ @body = solve_nest(@output.string)
97
94
  @language = @book.config['language']
98
95
  @stylesheets = @book.config['stylesheet']
99
96
  @next = @chapter.next_chapter
@@ -105,9 +102,28 @@ module ReVIEW
105
102
  @toc = ReVIEW::WEBTOCPrinter.book_to_string(@book)
106
103
  end
107
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
+
108
110
  ReVIEW::Template.load(layoutfile).result(binding)
109
111
  end
110
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
+
111
127
  def xmlns_ops_prefix
112
128
  if @book.config['epubversion'].to_i == 3
113
129
  'epub'
@@ -140,6 +156,7 @@ module ReVIEW
140
156
  @nonum_counter += 1
141
157
  puts if level > 1
142
158
  return unless caption.present?
159
+
143
160
  if label
144
161
  puts %Q(<h#{level} id="#{normalize_id(label)}">#{compile_inline(caption)}</h#{level}>)
145
162
  else
@@ -155,6 +172,7 @@ module ReVIEW
155
172
  @nonum_counter += 1
156
173
  puts if level > 1
157
174
  return unless caption.present?
175
+
158
176
  if label
159
177
  puts %Q(<h#{level} id="#{normalize_id(label)}" notoc="true">#{compile_inline(caption)}</h#{level}>)
160
178
  else
@@ -170,6 +188,7 @@ module ReVIEW
170
188
  @nonum_counter += 1
171
189
  puts '' if level > 1
172
190
  return unless caption.present?
191
+
173
192
  if label
174
193
  puts %Q(<a id="#{normalize_id(label)}" /><h#{level} id="#{normalize_id(label)}" hidden="true">#{compile_inline(caption)}</h#{level}>)
175
194
  else
@@ -229,6 +248,7 @@ module ReVIEW
229
248
  end
230
249
 
231
250
  def captionblock(type, lines, caption)
251
+ check_nested_minicolumn
232
252
  puts %Q(<div class="#{type}">)
233
253
  if caption.present?
234
254
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
@@ -287,15 +307,25 @@ module ReVIEW
287
307
  end
288
308
 
289
309
  def box(lines, caption = nil)
290
- puts %Q(<div class="syntax">)
310
+ captionstr = nil
291
311
  if caption.present?
292
- puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
312
+ captionstr = %Q(<p class="caption">#{compile_inline(caption)}</p>)
293
313
  end
314
+ puts %Q(<div class="syntax">)
315
+
316
+ if caption_top?('list') && caption.present?
317
+ puts captionstr
318
+ end
319
+
294
320
  print %Q(<pre class="syntax">)
295
321
  lines.each do |line|
296
322
  puts detab(line)
297
323
  end
298
324
  puts '</pre>'
325
+
326
+ if !caption_top?('list') && caption.present?
327
+ puts captionstr
328
+ end
299
329
  puts '</div>'
300
330
  end
301
331
 
@@ -303,12 +333,30 @@ module ReVIEW
303
333
  captionblock('note', lines, caption)
304
334
  end
305
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
+
306
354
  def ul_begin
307
355
  puts '<ul>'
308
356
  end
309
357
 
310
358
  def ul_item_begin(lines)
311
- print "<li>#{lines.join}"
359
+ print "<li>#{join_lines_to_paragraph(lines)}"
312
360
  end
313
361
 
314
362
  def ul_item_end
@@ -329,7 +377,7 @@ module ReVIEW
329
377
  end
330
378
 
331
379
  def ol_item(lines, _num)
332
- puts "<li>#{lines.join}</li>"
380
+ puts "<li>#{join_lines_to_paragraph(lines)}</li>"
333
381
  end
334
382
 
335
383
  def ol_end
@@ -345,7 +393,7 @@ module ReVIEW
345
393
  end
346
394
 
347
395
  def dd(lines)
348
- puts "<dd>#{lines.join}</dd>"
396
+ puts "<dd>#{join_lines_to_paragraph(lines)}</dd>"
349
397
  end
350
398
 
351
399
  def dl_end
@@ -354,10 +402,10 @@ module ReVIEW
354
402
 
355
403
  def paragraph(lines)
356
404
  if @noindent
357
- puts %Q(<p class="noindent">#{lines.join}</p>)
405
+ puts %Q(<p class="noindent">#{join_lines_to_paragraph(lines)}</p>)
358
406
  @noindent = nil
359
407
  else
360
- puts "<p>#{lines.join}</p>"
408
+ puts "<p>#{join_lines_to_paragraph(lines)}</p>"
361
409
  end
362
410
  end
363
411
 
@@ -374,12 +422,7 @@ module ReVIEW
374
422
 
375
423
  def list(lines, id, caption, lang = nil)
376
424
  puts %Q(<div id="#{normalize_id(id)}" class="caption-code">)
377
- begin
378
- list_header id, caption, lang
379
- rescue KeyError
380
- error "no such list: #{id}"
381
- end
382
- list_body id, lines, lang
425
+ super(lines, id, caption, lang)
383
426
  puts '</div>'
384
427
  end
385
428
 
@@ -404,8 +447,7 @@ module ReVIEW
404
447
 
405
448
  def source(lines, caption = nil, lang = nil)
406
449
  puts %Q(<div class="source-code">)
407
- source_header caption
408
- source_body caption, lines, lang
450
+ super(lines, caption, lang)
409
451
  puts '</div>'
410
452
  end
411
453
 
@@ -415,7 +457,7 @@ module ReVIEW
415
457
  end
416
458
  end
417
459
 
418
- def source_body(_id, lines, lang)
460
+ def source_body(lines, lang)
419
461
  print %Q(<pre class="source">)
420
462
  body = lines.inject('') { |i, j| i + detab(j) + "\n" }
421
463
  lexer = lang
@@ -425,12 +467,7 @@ module ReVIEW
425
467
 
426
468
  def listnum(lines, id, caption, lang = nil)
427
469
  puts %Q(<div id="#{normalize_id(id)}" class="code">)
428
- begin
429
- list_header id, caption, lang
430
- rescue KeyError
431
- error "no such list: #{id}"
432
- end
433
- listnum_body lines, lang
470
+ super(lines, id, caption, lang)
434
471
  puts '</div>'
435
472
  end
436
473
 
@@ -456,7 +493,7 @@ module ReVIEW
456
493
 
457
494
  def emlist(lines, caption = nil, lang = nil)
458
495
  puts %Q(<div class="emlist-code">)
459
- if caption.present?
496
+ if caption_top?('list') && caption.present?
460
497
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
461
498
  end
462
499
  class_names = ['emlist']
@@ -467,12 +504,15 @@ module ReVIEW
467
504
  lexer = lang
468
505
  puts highlight(body: body, lexer: lexer, format: 'html')
469
506
  puts '</pre>'
507
+ if !caption_top?('list') && caption.present?
508
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
509
+ end
470
510
  puts '</div>'
471
511
  end
472
512
 
473
513
  def emlistnum(lines, caption = nil, lang = nil)
474
514
  puts %Q(<div class="emlistnum-code">)
475
- if caption.present?
515
+ if caption_top?('list') && caption.present?
476
516
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
477
517
  end
478
518
 
@@ -494,19 +534,29 @@ module ReVIEW
494
534
  puts '</pre>'
495
535
  end
496
536
 
537
+ if !caption_top?('list') && caption.present?
538
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
539
+ end
540
+
497
541
  puts '</div>'
498
542
  end
499
543
 
500
544
  def cmd(lines, caption = nil)
501
545
  puts %Q(<div class="cmd-code">)
502
- if caption.present?
546
+ if caption_top?('list') && caption.present?
503
547
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
504
548
  end
549
+
505
550
  print %Q(<pre class="cmd">)
506
551
  body = lines.inject('') { |i, j| i + detab(j) + "\n" }
507
552
  lexer = 'shell-session'
508
553
  puts highlight(body: body, lexer: lexer, format: 'html')
509
554
  puts '</pre>'
555
+
556
+ if !caption_top?('list') && caption.present?
557
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
558
+ end
559
+
510
560
  puts '</div>'
511
561
  end
512
562
 
@@ -541,18 +591,19 @@ module ReVIEW
541
591
 
542
592
  def texequation(lines, id = nil, caption = '')
543
593
  if id
544
- texequation_header id, caption
594
+ puts %Q(<div id="#{normalize_id(id)}" class="caption-equation">)
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
553
605
 
554
606
  def texequation_header(id, caption)
555
- puts %Q(<div id="#{normalize_id(id)}" class="caption-equation">)
556
607
  if get_chap
557
608
  puts %Q(<p class="caption">#{I18n.t('equation')}#{I18n.t('format_number_header', [get_chap, @chapter.equation(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}</p>)
558
609
  else
@@ -562,24 +613,27 @@ module ReVIEW
562
613
 
563
614
  def texequation_body(lines)
564
615
  puts %Q(<div class="equation">)
565
- if @book.config['mathml']
566
- require 'math_ml'
567
- 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
568
623
  p = MathML::LaTeX::Parser.new(symbol: MathML::Symbol::CharacterReference)
569
- puts p.parse(unescape(lines.join("\n")), true)
570
- elsif @book.config['imgmath']
624
+ print p.parse(lines.join("\n") + "\n", true)
625
+ elsif @book.config['math_format'] == 'mathjax'
626
+ puts "$$#{lines.join("\n")}$$"
627
+ elsif @book.config['math_format'] == 'imgmath'
571
628
  fontsize = @book.config['imgmath_options']['fontsize'].to_f
572
629
  lineheight = @book.config['imgmath_options']['lineheight'].to_f
573
- math_str = "\\begin{equation*}\n\\fontsize{#{fontsize}}{#{lineheight}}\\selectfont\n#{unescape(lines.join("\n"))}\n\\end{equation*}\n"
630
+ math_str = "\\begin{equation*}\n\\fontsize{#{fontsize}}{#{lineheight}}\\selectfont\n#{lines.join("\n")}\n\\end{equation*}\n"
574
631
  key = Digest::SHA256.hexdigest(math_str)
575
- math_dir = File.join(@book.config['imagedir'], '_review_math')
576
- Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
577
- img_path = File.join(math_dir, "_gen_#{key}.#{@book.config['imgmath_options']['format']}")
578
632
  if @book.config.check_version('2', exception: false)
579
- make_math_image(math_str, img_path)
633
+ img_path = @img_math.make_math_image(math_str, key)
580
634
  puts %Q(<img src="#{img_path}" />)
581
635
  else
582
- defer_math_image(math_str, img_path, key)
636
+ img_path = @img_math.defer_math_image(math_str, key)
583
637
  puts %Q(<img src="#{img_path}" class="math_gen_#{key}" alt="#{escape(lines.join(' '))}" />)
584
638
  end
585
639
  else
@@ -615,20 +669,22 @@ module ReVIEW
615
669
  def image_image(id, caption, metric)
616
670
  metrics = parse_metric('html', metric)
617
671
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
672
+ image_header(id, caption) if caption_top?('image')
618
673
  puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
619
- image_header id, caption
674
+ image_header(id, caption) unless caption_top?('image')
620
675
  puts '</div>'
621
676
  end
622
677
 
623
678
  def image_dummy(id, caption, lines)
624
679
  warn "image not bound: #{id}"
625
680
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
681
+ image_header(id, caption) if caption_top?('image')
626
682
  puts %Q(<pre class="dummyimage">)
627
683
  lines.each do |line|
628
684
  puts detab(line)
629
685
  end
630
686
  puts '</pre>'
631
- image_header id, caption
687
+ image_header(id, caption) unless caption_top?('image')
632
688
  puts '</div>'
633
689
  end
634
690
 
@@ -643,47 +699,12 @@ module ReVIEW
643
699
  end
644
700
 
645
701
  def table(lines, id = nil, caption = nil)
646
- rows = []
647
- sepidx = nil
648
- lines.each_with_index do |line, idx|
649
- if /\A[\=\-]{12}/ =~ line
650
- # just ignore
651
- # error "too many table separator" if sepidx
652
- sepidx ||= idx
653
- next
654
- end
655
- rows.push(line.strip.split(/\t+/).map { |s| s.sub(/\A\./, '') })
656
- end
657
- rows = adjust_n_cols(rows)
658
- error 'no rows in the table' if rows.empty?
659
-
660
702
  if id
661
703
  puts %Q(<div id="#{normalize_id(id)}" class="table">)
662
704
  else
663
705
  puts %Q(<div class="table">)
664
706
  end
665
- begin
666
- if caption.present?
667
- table_header id, caption
668
- end
669
- rescue KeyError
670
- error "no such table: #{id}"
671
- end
672
- table_begin rows.first.size
673
- if sepidx
674
- sepidx.times do
675
- tr(rows.shift.map { |s| th(s) })
676
- end
677
- rows.each do |cols|
678
- tr(cols.map { |s| td(s) })
679
- end
680
- else
681
- rows.each do |cols|
682
- h, *cs = *cols
683
- tr([th(h)] + cs.map { |s| td(s) })
684
- end
685
- end
686
- table_end
707
+ super(lines, id, caption)
687
708
  puts '</div>'
688
709
  end
689
710
 
@@ -718,23 +739,27 @@ module ReVIEW
718
739
  end
719
740
 
720
741
  def imgtable(lines, id, caption = nil, metric = nil)
721
- unless @chapter.image(id).bound?
742
+ unless @chapter.image_bound?(id)
722
743
  warn "image not bound: #{id}"
723
- image_dummy id, caption, lines
744
+ image_dummy(id, caption, lines)
724
745
  return
725
746
  end
726
747
 
727
748
  puts %Q(<div id="#{normalize_id(id)}" class="imgtable image">)
728
749
  begin
729
- if caption.present?
730
- table_header id, caption
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?
757
+ table_header(id, caption)
731
758
  end
732
759
  rescue KeyError
733
760
  error "no such table: #{id}"
734
761
  end
735
762
 
736
- imgtable_image(id, caption, metric)
737
-
738
763
  puts '</div>'
739
764
  end
740
765
 
@@ -749,8 +774,9 @@ module ReVIEW
749
774
 
750
775
  def comment(lines, comment = nil)
751
776
  return unless @book.config['draft']
777
+
752
778
  lines ||= []
753
- lines.unshift escape(comment) unless comment.blank?
779
+ lines.unshift(escape(comment)) unless comment.blank?
754
780
  str = lines.join('<br />')
755
781
  puts %Q(<div class="draft-comment">#{str}</div>)
756
782
  end
@@ -771,7 +797,19 @@ module ReVIEW
771
797
  def indepimage(lines, id, caption = '', metric = nil)
772
798
  metrics = parse_metric('html', metric)
773
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
+
774
809
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
810
+ if caption_top?('image') && caption.present?
811
+ puts caption_str
812
+ end
775
813
  begin
776
814
  puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
777
815
  rescue
@@ -785,10 +823,8 @@ module ReVIEW
785
823
  end
786
824
  end
787
825
 
788
- if caption.present?
789
- puts %Q(<p class="caption">)
790
- puts %Q(#{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)})
791
- puts '</p>'
826
+ if !caption_top?('image') && caption.present?
827
+ puts caption_str
792
828
  end
793
829
  puts '</div>'
794
830
  end
@@ -949,22 +985,25 @@ module ReVIEW
949
985
  end
950
986
 
951
987
  def inline_m(str)
952
- if @book.config['mathml']
953
- require 'math_ml'
954
- 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
955
995
  parser = MathML::LaTeX::Parser.new(symbol: MathML::Symbol::CharacterReference)
956
996
  %Q(<span class="equation">#{parser.parse(str, nil)}</span>)
957
- 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'
958
1000
  math_str = '$' + str + '$'
959
1001
  key = Digest::SHA256.hexdigest(str)
960
- math_dir = File.join(@book.config['imagedir'], '_review_math')
961
- Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
962
- img_path = File.join(math_dir, "_gen_#{key}.#{@book.config['imgmath_options']['format']}")
963
1002
  if @book.config.check_version('2', exception: false)
964
- make_math_image(math_str, img_path)
1003
+ img_path = @img_math.make_math_image(math_str, key)
965
1004
  %Q(<span class="equation"><img src="#{img_path}" /></span>)
966
1005
  else
967
- defer_math_image(math_str, img_path, key)
1006
+ img_path = @img_math.defer_math_image(math_str, key)
968
1007
  %Q(<span class="equation"><img src="#{img_path}" class="math_gen_#{key}" alt="#{escape(str)}" /></span>)
969
1008
  end
970
1009
  else
@@ -978,8 +1017,8 @@ module ReVIEW
978
1017
 
979
1018
  def bibpaper(lines, id, caption)
980
1019
  puts %Q(<div class="bibpaper">)
981
- bibpaper_header id, caption
982
- bibpaper_bibpaper id, caption, lines unless lines.empty?
1020
+ bibpaper_header(id, caption)
1021
+ bibpaper_bibpaper(id, caption, lines) unless lines.empty?
983
1022
  puts '</div>'
984
1023
  end
985
1024
 
@@ -1008,7 +1047,7 @@ module ReVIEW
1008
1047
  str = I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
1009
1048
  end
1010
1049
  if @book.config['chapterlink']
1011
- anchor = 'h' + n.gsub('.', '-')
1050
+ anchor = 'h' + n.tr('.', '-')
1012
1051
  %Q(<a href="#{chap.id}#{extname}##{anchor}">#{str}</a>)
1013
1052
  else
1014
1053
  str
@@ -1025,7 +1064,7 @@ module ReVIEW
1025
1064
 
1026
1065
  def inline_column_chap(chapter, id)
1027
1066
  if @book.config['chapterlink']
1028
- %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>)
1029
1068
  else
1030
1069
  I18n.t('column', compile_inline(chapter.column(id).caption))
1031
1070
  end
@@ -1187,7 +1226,7 @@ module ReVIEW
1187
1226
  %Q(<span class="balloon">#{escape_html(str)}</span>)
1188
1227
  end
1189
1228
 
1190
- def inline_raw(str)
1229
+ def inline_raw(str) # rubocop:disable Lint/UselessMethodDefinition
1191
1230
  super(str)
1192
1231
  end
1193
1232
 
@@ -1218,46 +1257,5 @@ module ReVIEW
1218
1257
  def olnum(num)
1219
1258
  @ol_num = num.to_i
1220
1259
  end
1221
-
1222
- def defer_math_image(str, path, key)
1223
- # for Re:VIEW >3
1224
- File.open(File.join(File.dirname(path), '__IMGMATH_BODY__.tex'), 'a+') do |f|
1225
- f.puts str
1226
- f.puts '\\clearpage'
1227
- end
1228
- File.open(File.join(File.dirname(path), '__IMGMATH_BODY__.map'), 'a+') do |f|
1229
- f.puts key
1230
- end
1231
- end
1232
-
1233
- def make_math_image(str, path, fontsize = 12)
1234
- # Re:VIEW 2 compatibility
1235
- fontsize2 = (fontsize * 1.2).round.to_i
1236
- texsrc = <<-EOB
1237
- \\documentclass[12pt]{article}
1238
- \\usepackage[utf8]{inputenc}
1239
- \\usepackage{amsmath}
1240
- \\usepackage{amsthm}
1241
- \\usepackage{amssymb}
1242
- \\usepackage{amsfonts}
1243
- \\usepackage{anyfontsize}
1244
- \\usepackage{bm}
1245
- \\pagestyle{empty}
1246
-
1247
- \\begin{document}
1248
- \\fontsize{#{fontsize}}{#{fontsize2}}\\selectfont #{str}
1249
- \\end{document}
1250
- EOB
1251
- Dir.mktmpdir do |tmpdir|
1252
- tex_path = File.join(tmpdir, 'tmpmath.tex')
1253
- dvi_path = File.join(tmpdir, 'tmpmath.dvi')
1254
- File.write(tex_path, texsrc)
1255
- cmd = "latex --interaction=nonstopmode --output-directory=#{tmpdir} #{tex_path} && dvipng -T tight -z9 -o #{path} #{dvi_path}"
1256
- out, status = Open3.capture2e(cmd)
1257
- unless status.success?
1258
- error "latex compile error\n\nError log:\n" + out
1259
- end
1260
- end
1261
- end
1262
1260
  end
1263
1261
  end # module ReVIEW