review 3.1.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (225) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-win.yml +45 -0
  3. data/.github/workflows/ruby.yml +27 -0
  4. data/.rubocop.yml +161 -34
  5. data/.travis.yml +16 -15
  6. data/Dockerfile +21 -5
  7. data/NEWS.ja.md +394 -0
  8. data/NEWS.md +395 -1
  9. data/README.md +10 -7
  10. data/appveyor.yml +1 -3
  11. data/bin/review-catalog-converter +5 -5
  12. data/bin/review-check +10 -12
  13. data/bin/review-checkdep +2 -2
  14. data/bin/review-compile +17 -23
  15. data/bin/review-epubmaker +3 -35
  16. data/bin/review-idgxmlmaker +16 -0
  17. data/bin/review-index +2 -89
  18. data/bin/review-preproc +13 -13
  19. data/bin/review-validate +4 -4
  20. data/bin/review-vol +4 -78
  21. data/doc/config.yml.sample +47 -12
  22. data/doc/config.yml.sample-simple +3 -2
  23. data/doc/format.ja.md +120 -17
  24. data/doc/format.md +119 -27
  25. data/doc/makeindex.ja.md +2 -2
  26. data/doc/pdfmaker.ja.md +43 -1
  27. data/doc/pdfmaker.md +42 -1
  28. data/doc/quickstart.ja.md +45 -25
  29. data/doc/quickstart.md +37 -16
  30. data/lib/epubmaker/content.rb +3 -2
  31. data/lib/epubmaker/epubcommon.rb +34 -27
  32. data/lib/epubmaker/epubv2.rb +5 -6
  33. data/lib/epubmaker/epubv3.rb +21 -18
  34. data/lib/epubmaker/producer.rb +2 -1
  35. data/lib/review/book.rb +2 -2
  36. data/lib/review/book/base.rb +91 -96
  37. data/lib/review/book/bib.rb +21 -0
  38. data/lib/review/book/book_unit.rb +155 -0
  39. data/lib/review/book/chapter.rb +48 -29
  40. data/lib/review/book/index.rb +46 -240
  41. data/lib/review/book/index/item.rb +46 -0
  42. data/lib/review/book/page_metric.rb +7 -7
  43. data/lib/review/book/part.rb +45 -10
  44. data/lib/review/book/volume.rb +4 -5
  45. data/lib/review/builder.rb +172 -56
  46. data/lib/review/catalog.rb +14 -17
  47. data/lib/review/compiler.rb +219 -121
  48. data/lib/review/configure.rb +39 -7
  49. data/lib/review/converter.rb +1 -1
  50. data/lib/review/epub2html.rb +43 -5
  51. data/lib/review/epubmaker.rb +69 -27
  52. data/lib/review/extentions/string.rb +0 -4
  53. data/lib/review/htmlbuilder.rb +112 -101
  54. data/lib/review/htmlutils.rb +9 -13
  55. data/lib/review/i18n.rb +3 -3
  56. data/lib/review/idgxmlbuilder.rb +202 -78
  57. data/lib/review/idgxmlmaker.rb +186 -0
  58. data/lib/review/index_builder.rb +653 -0
  59. data/lib/review/init-web/finish.html +10 -0
  60. data/lib/review/init-web/index.html +190 -0
  61. data/lib/review/init-web/review-layout-design.js +691 -0
  62. data/lib/review/init.rb +129 -46
  63. data/lib/review/latexbuilder.rb +255 -92
  64. data/lib/review/lineinput.rb +1 -1
  65. data/lib/review/location.rb +32 -0
  66. data/lib/review/logger.rb +4 -8
  67. data/lib/review/makerhelper.rb +35 -5
  68. data/lib/review/markdownbuilder.rb +50 -38
  69. data/lib/review/md2inaobuilder.rb +3 -5
  70. data/lib/review/pdfmaker.rb +60 -57
  71. data/lib/review/plaintextbuilder.rb +154 -87
  72. data/lib/review/preprocessor.rb +20 -42
  73. data/lib/review/rstbuilder.rb +57 -38
  74. data/lib/review/sec_counter.rb +13 -0
  75. data/lib/review/textmaker.rb +23 -15
  76. data/lib/review/textutils.rb +76 -2
  77. data/lib/review/tocprinter.rb +230 -102
  78. data/lib/review/topbuilder.rb +139 -60
  79. data/lib/review/update.rb +24 -24
  80. data/lib/review/version.rb +1 -1
  81. data/lib/review/volumeprinter.rb +98 -0
  82. data/lib/review/webmaker.rb +20 -24
  83. data/lib/review/webtocprinter.rb +38 -35
  84. data/lib/review/yamlloader.rb +26 -16
  85. data/review.gemspec +6 -4
  86. data/samples/sample-book/README.md +7 -2
  87. data/samples/sample-book/src/.gitignore +154 -0
  88. data/samples/sample-book/src/config-ebook.yml +4 -0
  89. data/samples/sample-book/src/config-jlreq-ebook.yml +4 -0
  90. data/samples/sample-book/src/config-jlreq.yml +6 -0
  91. data/samples/sample-book/src/config.yml +2 -2
  92. data/samples/sample-book/src/lib/tasks/review.rake +29 -14
  93. data/samples/sample-book/src/lib/tasks/z01_copy_sty.rake +14 -8
  94. data/samples/syntax-book/Gemfile +1 -1
  95. data/samples/syntax-book/ch01.re +4 -2
  96. data/samples/syntax-book/ch02.re +8 -16
  97. data/samples/syntax-book/ch03.re +3 -6
  98. data/samples/syntax-book/config-jlreq-lualatex.yml +4 -0
  99. data/samples/syntax-book/config-jlreq.yml +5 -0
  100. data/samples/syntax-book/config-print.yml +3 -0
  101. data/samples/syntax-book/config.yml +1 -1
  102. data/samples/syntax-book/lib/tasks/review.rake +30 -15
  103. data/samples/syntax-book/lib/tasks/z01_copy_sty.rake +14 -8
  104. data/templates/latex/config.erb +39 -25
  105. data/templates/latex/layout.tex.erb +1 -0
  106. data/templates/latex/review-jlreq/README.md +3 -1
  107. data/templates/latex/review-jlreq/review-base.sty +161 -50
  108. data/templates/latex/review-jlreq/review-jlreq.cls +21 -22
  109. data/templates/latex/review-jlreq/review-style.sty +4 -1
  110. data/templates/latex/review-jsbook/README.md +46 -5
  111. data/templates/latex/review-jsbook/review-base.sty +123 -35
  112. data/templates/latex/review-jsbook/review-jsbook.cls +10 -4
  113. data/templates/latex/review-jsbook/review-style.sty +5 -2
  114. data/templates/opf/epubv3.opf.erb +1 -0
  115. data/templates/web/html/layout-html5.html.erb +3 -3
  116. data/test/assets/test_template.tex +19 -7
  117. data/test/assets/test_template_backmatter.tex +19 -7
  118. data/test/book_test_helper.rb +11 -5
  119. data/test/test_book.rb +124 -79
  120. data/test/test_book_chapter.rb +97 -54
  121. data/test/test_book_part.rb +3 -3
  122. data/test/test_builder.rb +38 -13
  123. data/test/test_catalog.rb +24 -42
  124. data/test/test_catalog_converter_cmd.rb +1 -1
  125. data/test/test_converter.rb +1 -0
  126. data/test/test_epub3maker.rb +2 -2
  127. data/test/test_epubmaker.rb +8 -0
  128. data/test/test_epubmaker_cmd.rb +14 -7
  129. data/test/test_helper.rb +18 -7
  130. data/test/test_htmlbuilder.rb +1491 -205
  131. data/test/test_htmlutils.rb +0 -12
  132. data/test/test_i18n.rb +37 -37
  133. data/test/test_idgxmlbuilder.rb +744 -42
  134. data/test/test_idgxmlmaker_cmd.rb +46 -0
  135. data/test/test_image_finder.rb +52 -70
  136. data/test/test_index.rb +94 -44
  137. data/test/test_indexbuilder.rb +52 -0
  138. data/test/test_latexbuilder.rb +1784 -161
  139. data/test/test_latexbuilder_v2.rb +671 -102
  140. data/test/test_logger.rb +17 -4
  141. data/test/test_makerhelper.rb +2 -14
  142. data/test/test_markdownbuilder.rb +137 -16
  143. data/test/test_md2inaobuilder.rb +32 -9
  144. data/test/test_pdfmaker.rb +30 -12
  145. data/test/test_pdfmaker_cmd.rb +100 -6
  146. data/test/test_plaintextbuilder.rb +791 -30
  147. data/test/test_preprocessor.rb +2 -16
  148. data/test/test_review_ext.rb +2 -1
  149. data/test/test_rstbuilder.rb +274 -27
  150. data/test/test_sec_counter.rb +156 -0
  151. data/test/test_textmaker_cmd.rb +54 -0
  152. data/test/test_textutils.rb +109 -2
  153. data/test/test_topbuilder.rb +724 -34
  154. data/test/test_update.rb +20 -11
  155. data/test/test_webtocprinter.rb +75 -43
  156. data/test/test_yamlloader.rb +13 -0
  157. data/vendor/gentombow/LICENSE +1 -1
  158. data/vendor/gentombow/Makefile +0 -1
  159. data/vendor/gentombow/bounddvi-en.pdf +0 -0
  160. data/vendor/gentombow/bounddvi-en.tex +1 -0
  161. data/vendor/gentombow/bounddvi.pdf +0 -0
  162. data/vendor/gentombow/bounddvi.sty +30 -7
  163. data/vendor/gentombow/bounddvi.tex +1 -0
  164. data/vendor/gentombow/create_archive.sh +1 -0
  165. data/vendor/gentombow/gentombow-ja.pdf +0 -0
  166. data/vendor/gentombow/gentombow-ja.tex +9 -0
  167. data/vendor/gentombow/gentombow.pdf +0 -0
  168. data/vendor/gentombow/gentombow.sty +32 -10
  169. data/vendor/gentombow/gentombow.tex +8 -0
  170. data/vendor/gentombow/tests/gentombow-01-pdfx.tex +8 -0
  171. data/vendor/gentombow/tests/gentombow-02-pdfx.tex +8 -0
  172. data/vendor/jsclasses/LICENSE +1 -1
  173. data/vendor/jsclasses/Makefile +3 -2
  174. data/vendor/jsclasses/create_archive.sh +5 -5
  175. data/vendor/jsclasses/jis/Makefile +3 -2
  176. data/vendor/jsclasses/jis/jsarticle.cls +74 -31
  177. data/vendor/jsclasses/jis/jsbook.cls +74 -31
  178. data/vendor/jsclasses/jis/jsclasses.dtx +176 -36
  179. data/vendor/jsclasses/jis/jsclasses.ins +15 -5
  180. data/vendor/jsclasses/jis/jslogo.dtx +4 -4
  181. data/vendor/jsclasses/jis/jslogo.ins +9 -0
  182. data/vendor/jsclasses/jis/jslogo.sty +4 -16
  183. data/vendor/jsclasses/jis/jspf.cls +73 -30
  184. data/vendor/jsclasses/jis/jsreport.cls +74 -31
  185. data/vendor/jsclasses/jis/jsverb.ins +9 -0
  186. data/vendor/jsclasses/jis/jsverb.sty +1 -13
  187. data/vendor/jsclasses/jis/kiyou.cls +74 -31
  188. data/vendor/jsclasses/jis/minijs.sty +65 -22
  189. data/vendor/jsclasses/jis/okumacro.dtx +4 -5
  190. data/vendor/jsclasses/jis/okumacro.ins +9 -0
  191. data/vendor/jsclasses/jis/okumacro.sty +4 -17
  192. data/vendor/jsclasses/jis/okuverb.ins +9 -0
  193. data/vendor/jsclasses/jis/okuverb.sty +1 -13
  194. data/vendor/jsclasses/jis/winjis.sty +23 -19
  195. data/vendor/jsclasses/jsarticle.cls +74 -31
  196. data/vendor/jsclasses/jsbook.cls +74 -31
  197. data/vendor/jsclasses/jsclasses.dtx +176 -36
  198. data/vendor/jsclasses/jsclasses.ins +15 -5
  199. data/vendor/jsclasses/jsclasses.pdf +0 -0
  200. data/vendor/jsclasses/jslogo.dtx +4 -4
  201. data/vendor/jsclasses/jslogo.ins +9 -0
  202. data/vendor/jsclasses/jslogo.pdf +0 -0
  203. data/vendor/jsclasses/jslogo.sty +4 -16
  204. data/vendor/jsclasses/jspf.cls +73 -30
  205. data/vendor/jsclasses/jsreport.cls +74 -31
  206. data/vendor/jsclasses/jsverb.ins +9 -0
  207. data/vendor/jsclasses/jsverb.pdf +0 -0
  208. data/vendor/jsclasses/jsverb.sty +1 -13
  209. data/vendor/jsclasses/kiyou.cls +74 -31
  210. data/vendor/jsclasses/minijs.sty +68 -22
  211. data/vendor/jsclasses/okumacro.dtx +4 -5
  212. data/vendor/jsclasses/okumacro.ins +9 -0
  213. data/vendor/jsclasses/okumacro.pdf +0 -0
  214. data/vendor/jsclasses/okumacro.sty +4 -17
  215. data/vendor/jsclasses/okuverb.ins +9 -0
  216. data/vendor/jsclasses/okuverb.pdf +0 -0
  217. data/vendor/jsclasses/okuverb.sty +1 -13
  218. data/vendor/jsclasses/tests/relfont.tex +10 -0
  219. data/vendor/jsclasses/winjis.sty +23 -19
  220. metadata +65 -12
  221. data/.rubocop_todo.yml +0 -7
  222. data/lib/review/book/compilable.rb +0 -173
  223. data/lib/review/tocparser.rb +0 -271
  224. data/samples/syntax-book/review-ext.rb +0 -14
  225. data/test/test_tocparser.rb +0 -25
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2012-2018 Masanori Kado, Masayoshi Takahashi, Kenshi Muto
2
+ # Copyright (c) 2012-2020 Masanori Kado, Masayoshi Takahashi, Kenshi Muto
3
3
  #
4
4
  # This program is free software.
5
5
  # You can distribute or modify this program under the terms of
@@ -15,7 +15,7 @@ module ReVIEW
15
15
  def self.values
16
16
  conf = Configure[
17
17
  # These parameters can be overridden by YAML file.
18
- 'bookname' => 'example', # it defines epub file name also
18
+ 'bookname' => 'book', # it defines epub file name also
19
19
  'booktitle' => 'Re:VIEW Sample Book',
20
20
  'title' => nil,
21
21
  'aut' => nil, # author
@@ -32,7 +32,7 @@ module ReVIEW
32
32
  'rights' => nil, # Copyright messages
33
33
  'description' => nil, # Description
34
34
  'urnid' => "urn:uid:#{SecureRandom.uuid}", # Identifier
35
- 'stylesheet' => 'stylesheet.css', # stylesheet file
35
+ 'stylesheet' => [], # stylesheet file
36
36
  'coverfile' => nil, # content file of body of cover page
37
37
  'mytoc' => nil, # whether make own table of contents or not
38
38
  'params' => '', # specify review2html parameters
@@ -64,7 +64,10 @@ module ReVIEW
64
64
  'bib_file' => 'bib.re',
65
65
  'words_file' => nil,
66
66
  'colophon_order' => %w[aut csl trl dsr ill cov edt pbl contact prt],
67
+ 'chapterlink' => true,
67
68
  'externallink' => true,
69
+ 'join_lines_by_lang' => nil, # experimental. default should be nil
70
+ 'table_row_separator' => 'tabs',
68
71
  # for IDGXML
69
72
  'tableopt' => nil,
70
73
  'listinfo' => nil,
@@ -73,22 +76,25 @@ module ReVIEW
73
76
  'structuredxml' => nil,
74
77
  'pt_to_mm_unit' => 0.3528, # DTP: 1pt = 0.3528mm, JIS: 1pt = 0.3514mm
75
78
  # for LaTeX
76
- 'image_scale2width' => true,
77
79
  'footnotetext' => nil,
78
80
  'texcommand' => 'uplatex',
79
- 'texoptions' => '-interaction=nonstopmode -file-line-error',
81
+ 'texoptions' => '-interaction=nonstopmode -file-line-error -halt-on-error',
80
82
  '_texdocumentclass' => ['review-jsbook', ''],
83
+ 'texstyle' => ['reviewmacro'],
81
84
  'dvicommand' => 'dvipdfmx',
82
85
  'dvioptions' => '-d 5 -z 9',
83
86
  # for PDFMaker
84
87
  'pdfmaker' => {
88
+ 'image_scale2width' => true,
85
89
  'makeindex' => nil, # Make index page
86
90
  'makeindex_command' => 'mendex', # works only when makeindex is true
87
91
  'makeindex_options' => '-f -r -I utf8',
88
92
  'makeindex_sty' => nil,
89
93
  'makeindex_dic' => nil,
90
94
  'makeindex_mecab' => true,
91
- 'makeindex_mecab_opts' => '-Oyomi'
95
+ 'makeindex_mecab_opts' => '-Oyomi',
96
+ 'use_cover_nombre' => true,
97
+ 'use_original_image_size' => nil
92
98
  },
93
99
  'imgmath_options' => {
94
100
  'format' => 'png',
@@ -99,14 +105,40 @@ module ReVIEW
99
105
  'preamble_file' => nil,
100
106
  'fontsize' => 10,
101
107
  'lineheight' => 10 * 1.2,
102
- 'pdfcrop_pixelize_cmd' => 'pdftocairo -png -r 90 -f %p -l %p -singlefile %i %O',
108
+ 'pdfcrop_pixelize_cmd' => 'pdftocairo -%t -r 90 -f %p -l %p -singlefile %i %O',
103
109
  'dvipng_cmd' => 'dvipng -T tight -z 9 -p %p -l %p -o %o %i'
110
+ },
111
+ 'caption_position' => {
112
+ 'list' => 'top',
113
+ 'image' => 'bottom',
114
+ 'table' => 'top',
115
+ 'equation' => 'top'
104
116
  }
105
117
  ]
106
118
  conf.maker = nil
107
119
  conf
108
120
  end
109
121
 
122
+ def self.create(maker: nil, yamlfile: nil, config: nil)
123
+ conf = self.values
124
+ conf.maker = maker
125
+
126
+ if yamlfile
127
+ begin
128
+ loader = ReVIEW::YAMLLoader.new
129
+ conf.deep_merge!(loader.load_file(yamlfile))
130
+ rescue => e
131
+ error "yaml error #{e.message}"
132
+ end
133
+ end
134
+ # YAML configs will be overridden by command line options.
135
+ if config
136
+ conf.deep_merge!(config)
137
+ end
138
+
139
+ conf
140
+ end
141
+
110
142
  def [](key)
111
143
  maker = self.maker
112
144
  if maker && self.key?(maker) && self.fetch(maker) && self.fetch(maker).key?(key)
@@ -17,7 +17,7 @@ module ReVIEW
17
17
  chap_name = File.basename(file, '.*')
18
18
  chap = @book.chapter(chap_name)
19
19
  result = @compiler.compile(chap)
20
- File.open(output_path, 'w') { |f| f.puts result }
20
+ File.write(output_path, result)
21
21
  end
22
22
  end
23
23
  end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2018 Kenshi Muto
2
+ # Copyright (c) 2018-2019 Kenshi Muto
3
3
  #
4
4
  # This program is free software.
5
5
  # You can distribute or modify this program under the terms of
@@ -8,7 +8,14 @@
8
8
 
9
9
  require 'zip'
10
10
  require 'rexml/document'
11
- require 'cgi'
11
+ require 'optparse'
12
+ require 'review/version'
13
+
14
+ begin
15
+ require 'cgi/escape'
16
+ rescue
17
+ require 'cgi/util'
18
+ end
12
19
 
13
20
  module ReVIEW
14
21
  class Epub2Html
@@ -17,13 +24,26 @@ module ReVIEW
17
24
  end
18
25
 
19
26
  def execute(*args)
20
- if args[0].nil? || !File.exist?(args[0])
21
- STDERR.puts <<EOT
22
- Usage: #{File.basename($PROGRAM_NAME)} EPUBfile [file_for_head_and_foot] > HTMLfile
27
+ opts = OptionParser.new
28
+
29
+ opts.banner = <<EOT
30
+ Usage: review-epub2html [options] EPUBfile [file_for_head_and_foot] > HTMLfile
23
31
  file_for_head_and_foot: HTML file to extract header and footer area.
24
32
  This file must be contained in the EPUB.
25
33
  If omitted, the first found file is used.
34
+
26
35
  EOT
36
+ opts.version = ReVIEW::VERSION
37
+ opts.on('--help', 'Prints this message and quit.') do
38
+ puts opts.help
39
+ exit 0
40
+ end
41
+ opts.on('--inline-footnote', 'Embed footnote blocks in paragraph.') { @inline_footnote = true }
42
+
43
+ opts.parse!(args)
44
+
45
+ if args[0].nil? || !File.exist?(args[0])
46
+ puts opts.help
27
47
  exit 1
28
48
  end
29
49
 
@@ -36,6 +56,7 @@ EOT
36
56
  @htmls = {}
37
57
  @head = nil
38
58
  @tail = nil
59
+ @inline_footnote = nil
39
60
  end
40
61
 
41
62
  def parse_epub(epubname)
@@ -99,6 +120,23 @@ EOT
99
120
  e.attributes['href'] = "##{anc}"
100
121
  end
101
122
 
123
+ if @inline_footnote
124
+ # move footnotes to inline as same as LaTeX.
125
+ footnotes = {}
126
+
127
+ doc.each_element("//div[@class='footnote']") do |e|
128
+ e.name = 'span'
129
+ e.attributes.delete('epub:type')
130
+ footnotes[e.attributes['id']] = e
131
+ e.remove
132
+ end
133
+
134
+ doc.each_element("//a[@class='noteref']") do |e|
135
+ e.parent.insert_after(e, footnotes[e.attributes['href'].sub('#', '')])
136
+ e.remove
137
+ end
138
+ end
139
+
102
140
  doc.to_s.
103
141
  sub(/.*(<body.*?>)/m, %Q(<section id="#{sanitize(fname)}">)).
104
142
  sub(%r{(</body>).*}m, '</section>')
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2010-2018 Kenshi Muto and Masayoshi Takahashi
1
+ # Copyright (c) 2010-2020 Kenshi Muto and Masayoshi Takahashi
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -18,7 +18,6 @@ require 'review/version'
18
18
  require 'review/htmltoc'
19
19
  require 'review/htmlbuilder'
20
20
 
21
- require 'review/yamlloader'
22
21
  require 'rexml/document'
23
22
  require 'rexml/streamlistener'
24
23
  require 'epubmaker'
@@ -39,12 +38,12 @@ module ReVIEW
39
38
  end
40
39
 
41
40
  def error(msg)
42
- @logger.error "#{File.basename($PROGRAM_NAME, '.*')}: #{msg}"
41
+ @logger.error msg
43
42
  exit 1
44
43
  end
45
44
 
46
45
  def warn(msg)
47
- @logger.warn "#{File.basename($PROGRAM_NAME, '.*')}: #{msg}"
46
+ @logger.warn msg
48
47
  end
49
48
 
50
49
  def log(msg)
@@ -52,19 +51,50 @@ module ReVIEW
52
51
  end
53
52
 
54
53
  def load_yaml(yamlfile)
55
- loader = ReVIEW::YAMLLoader.new
56
- @config = ReVIEW::Configure.values
57
- begin
58
- @config.deep_merge!(loader.load_file(yamlfile))
59
- rescue => e
60
- error "yaml error #{e.message}"
61
- end
62
-
63
54
  @producer = Producer.new(@config)
64
55
  @producer.load(yamlfile)
65
56
  @config = @producer.config
66
- @config.maker = 'epubmaker'
57
+ end
58
+
59
+ def self.execute(*args)
60
+ self.new.execute(*args)
61
+ end
62
+
63
+ def parse_opts(args)
64
+ cmd_config = {}
65
+ opts = OptionParser.new
66
+ @buildonly = nil
67
+
68
+ opts.banner = 'Usage: review-epubmaker [options] configfile [export_filename]'
69
+ opts.version = ReVIEW::VERSION
70
+ opts.on('--help', 'Prints this message and quit.') do
71
+ puts opts.help
72
+ exit 0
73
+ end
74
+ opts.on('--[no-]debug', 'Keep temporary files.') { |debug| cmd_config['debug'] = debug }
75
+ opts.on('-y', '--only file1,file2,...', 'Build only specified files.') { |v| @buildonly = v.split(/\s*,\s*/).map { |m| m.strip.sub(/\.re\Z/, '') } }
76
+
77
+ opts.parse!(args)
78
+ if args.size < 1 || args.size > 2
79
+ puts opts.help
80
+ exit 0
81
+ end
82
+
83
+ [cmd_config, args[0], args[1]]
84
+ end
85
+
86
+ def execute(*args)
87
+ cmd_config, yamlfile, exportfile = parse_opts(args)
88
+ error "#{yamlfile} not found." unless File.exist?(yamlfile)
89
+
90
+ @config = ReVIEW::Configure.create(maker: 'epubmaker',
91
+ yamlfile: yamlfile,
92
+ config: cmd_config)
93
+ load_yaml(yamlfile)
67
94
  update_log_level
95
+ log("Loaded yaml file (#{yamlfile}).")
96
+
97
+ produce(yamlfile, exportfile)
68
98
  end
69
99
 
70
100
  def update_log_level
@@ -89,7 +119,6 @@ module ReVIEW
89
119
  end
90
120
 
91
121
  def produce(yamlfile, bookname = nil)
92
- load_yaml(yamlfile)
93
122
  I18n.setup(@config['language'])
94
123
  bookname ||= @config['bookname']
95
124
  booktmpname = "#{bookname}-epub"
@@ -99,7 +128,7 @@ module ReVIEW
99
128
  rescue ReVIEW::ConfigError => e
100
129
  warn e.message
101
130
  end
102
- log("Loaded yaml file (#{yamlfile}). I will produce #{bookname}.epub.")
131
+ log("#{bookname}.epub will be created.")
103
132
 
104
133
  FileUtils.rm_f("#{bookname}.epub")
105
134
  if @config['debug']
@@ -127,7 +156,7 @@ module ReVIEW
127
156
  copy_backmatter(basetmpdir)
128
157
 
129
158
  math_dir = "./#{@config['imagedir']}/_review_math"
130
- if @config['imgmath'] && File.exist?(File.join(math_dir, '__IMGMATH_BODY__.tex'))
159
+ if @config['imgmath'] && File.exist?(File.join(math_dir, '__IMGMATH_BODY__.map'))
131
160
  make_math_images(math_dir)
132
161
  end
133
162
  call_hook('hook_afterbackmatter', basetmpdir)
@@ -213,7 +242,7 @@ module ReVIEW
213
242
  if @config['epubmaker']['verify_target_images'].present?
214
243
  @config['epubmaker']['force_include_images'].each do |file|
215
244
  unless File.exist?(file)
216
- if file !~ /\Ahttp[s]?:/
245
+ if file !~ /\Ahttps?:/
217
246
  warn "#{file} is not found, skip."
218
247
  end
219
248
  next
@@ -268,8 +297,7 @@ module ReVIEW
268
297
 
269
298
  basedir = File.dirname(yamlfile)
270
299
  base_path = Pathname.new(basedir)
271
- book = ReVIEW::Book.load(basedir)
272
- book.config = @config
300
+ book = ReVIEW::Book::Base.new(basedir, config: @config)
273
301
  @converter = ReVIEW::Converter.new(book, ReVIEW::HTMLBuilder.new)
274
302
  @compile_errors = nil
275
303
 
@@ -301,9 +329,9 @@ module ReVIEW
301
329
  File.open(File.join(basetmpdir, htmlfile), 'w') do |f|
302
330
  @body = ''
303
331
  @body << %Q(<div class="part">\n)
304
- @body << %Q(<h1 class="part-number">#{CGI.escapeHTML(ReVIEW::I18n.t('part', part.number))}</h1>\n)
332
+ @body << %Q(<h1 class="part-number">#{h(ReVIEW::I18n.t('part', part.number))}</h1>\n)
305
333
  if part.name.strip.present?
306
- @body << %Q(<h2 class="part-title">#{CGI.escapeHTML(part.name.strip)}</h2>\n)
334
+ @body << %Q(<h2 class="part-title">#{h(part.name.strip)}</h2>\n)
307
335
  end
308
336
  @body << %Q(</div>\n)
309
337
 
@@ -357,6 +385,11 @@ module ReVIEW
357
385
  end
358
386
  end
359
387
 
388
+ if @buildonly && !@buildonly.include?(id)
389
+ warn "skip #{id}.re"
390
+ return
391
+ end
392
+
360
393
  htmlfile = "#{id}.#{@config['htmlext']}"
361
394
  write_buildlogtxt(basetmpdir, htmlfile, filename)
362
395
  log("Create #{htmlfile} from #{filename}.")
@@ -408,6 +441,13 @@ module ReVIEW
408
441
  path = File.join(basetmpdir, filename)
409
442
  htmlio = File.new(path)
410
443
  Document.parse_stream(htmlio, ReVIEWHeaderListener.new(headlines))
444
+ htmlio.close
445
+
446
+ if headlines.empty?
447
+ warn "#{filename} is discarded because there is no heading. Use `=[notoc]' or `=[nodisp]' to exclude headlines from the table of contents."
448
+ return
449
+ end
450
+
411
451
  properties = detect_properties(path)
412
452
  if properties.present?
413
453
  prop_str = ',properties=' + properties.join(' ')
@@ -435,7 +475,6 @@ module ReVIEW
435
475
  first = nil
436
476
  end
437
477
  end
438
- htmlio.close
439
478
  end
440
479
 
441
480
  def push_contents(_basetmpdir)
@@ -463,6 +502,9 @@ module ReVIEW
463
502
  def copy_stylesheet(basetmpdir)
464
503
  return if @config['stylesheet'].empty?
465
504
  @config['stylesheet'].each do |sfile|
505
+ unless File.exist?(sfile)
506
+ error "#{sfile} is not found."
507
+ end
466
508
  FileUtils.cp(sfile, basetmpdir)
467
509
  @producer.contents.push(Content.new('file' => sfile))
468
510
  end
@@ -510,19 +552,19 @@ module ReVIEW
510
552
 
511
553
  def build_titlepage(basetmpdir, htmlfile)
512
554
  # TODO: should be created via epubcommon
513
- @title = CGI.escapeHTML(@config.name_of('booktitle'))
555
+ @title = h(@config.name_of('booktitle'))
514
556
  File.open(File.join(basetmpdir, htmlfile), 'w') do |f|
515
557
  @body = ''
516
558
  @body << %Q(<div class="titlepage">\n)
517
- @body << %Q(<h1 class="tp-title">#{CGI.escapeHTML(@config.name_of('booktitle'))}</h1>\n)
559
+ @body << %Q(<h1 class="tp-title">#{h(@config.name_of('booktitle'))}</h1>\n)
518
560
  if @config['subtitle']
519
- @body << %Q(<h2 class="tp-subtitle">#{CGI.escapeHTML(@config.name_of('subtitle'))}</h2>\n)
561
+ @body << %Q(<h2 class="tp-subtitle">#{h(@config.name_of('subtitle'))}</h2>\n)
520
562
  end
521
563
  if @config['aut']
522
- @body << %Q(<h2 class="tp-author">#{CGI.escapeHTML(@config.names_of('aut').join(ReVIEW::I18n.t('names_splitter')))}</h2>\n)
564
+ @body << %Q(<h2 class="tp-author">#{h(@config.names_of('aut').join(ReVIEW::I18n.t('names_splitter')))}</h2>\n)
523
565
  end
524
566
  if @config['pbl']
525
- @body << %Q(<h3 class="tp-publisher">#{CGI.escapeHTML(@config.names_of('pbl').join(ReVIEW::I18n.t('names_splitter')))}</h3>\n)
567
+ @body << %Q(<h3 class="tp-publisher">#{h(@config.names_of('pbl').join(ReVIEW::I18n.t('names_splitter')))}</h3>\n)
526
568
  end
527
569
  @body << '</div>'
528
570
 
@@ -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
@@ -93,7 +88,7 @@ module ReVIEW
93
88
  def result
94
89
  # default XHTML header/footer
95
90
  @title = strip_html(compile_inline(@chapter.title))
96
- @body = @output.string
91
+ @body = solve_nest(@output.string)
97
92
  @language = @book.config['language']
98
93
  @stylesheets = @book.config['stylesheet']
99
94
  @next = @chapter.next_chapter
@@ -108,6 +103,20 @@ module ReVIEW
108
103
  ReVIEW::Template.load(layoutfile).result(binding)
109
104
  end
110
105
 
106
+ def solve_nest(s)
107
+ check_nest
108
+ s.gsub("</dd>\n</dl>\n\x01→dl←\x01", '').
109
+ gsub("\x01→/dl←\x01", "</dd>\n</dl>←END\x01").
110
+ gsub("</li>\n</ul>\n\x01→ul←\x01", '').
111
+ gsub("\x01→/ul←\x01", "</li>\n</ul>←END\x01").
112
+ gsub("</li>\n</ol>\n\x01→ol←\x01", '').
113
+ gsub("\x01→/ol←\x01", "</li>\n</ol>←END\x01").
114
+ gsub("</dl>←END\x01\n<dl>", '').
115
+ gsub("</ul>←END\x01\n<ul>", '').
116
+ gsub("</ol>←END\x01\n<ol>", '').
117
+ gsub("←END\x01", '')
118
+ end
119
+
111
120
  def xmlns_ops_prefix
112
121
  if @book.config['epubversion'].to_i == 3
113
122
  'epub'
@@ -229,6 +238,7 @@ module ReVIEW
229
238
  end
230
239
 
231
240
  def captionblock(type, lines, caption)
241
+ check_nested_minicolumn
232
242
  puts %Q(<div class="#{type}">)
233
243
  if caption.present?
234
244
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
@@ -287,15 +297,25 @@ module ReVIEW
287
297
  end
288
298
 
289
299
  def box(lines, caption = nil)
290
- puts %Q(<div class="syntax">)
300
+ captionstr = nil
291
301
  if caption.present?
292
- puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
302
+ captionstr = %Q(<p class="caption">#{compile_inline(caption)}</p>)
303
+ end
304
+ puts %Q(<div class="syntax">)
305
+
306
+ if caption_top?('list') && caption.present?
307
+ puts captionstr
293
308
  end
309
+
294
310
  print %Q(<pre class="syntax">)
295
311
  lines.each do |line|
296
312
  puts detab(line)
297
313
  end
298
314
  puts '</pre>'
315
+
316
+ if !caption_top?('list') && caption.present?
317
+ puts captionstr
318
+ end
299
319
  puts '</div>'
300
320
  end
301
321
 
@@ -303,12 +323,30 @@ module ReVIEW
303
323
  captionblock('note', lines, caption)
304
324
  end
305
325
 
326
+ CAPTION_TITLES.each do |name|
327
+ class_eval %Q(
328
+ def #{name}_begin(caption = nil)
329
+ check_nested_minicolumn
330
+ @doc_status[:minicolumn] = '#{name}'
331
+ puts %Q(<div class="#{name}">)
332
+ if caption.present?
333
+ puts %Q(<p class="caption">\#{compile_inline(caption)}</p>)
334
+ end
335
+ end
336
+
337
+ def #{name}_end
338
+ puts '</div>'
339
+ @doc_status[:minicolumn] = nil
340
+ end
341
+ ), __FILE__, __LINE__ - 14
342
+ end
343
+
306
344
  def ul_begin
307
345
  puts '<ul>'
308
346
  end
309
347
 
310
348
  def ul_item_begin(lines)
311
- print "<li>#{lines.join}"
349
+ print "<li>#{join_lines_to_paragraph(lines)}"
312
350
  end
313
351
 
314
352
  def ul_item_end
@@ -329,7 +367,7 @@ module ReVIEW
329
367
  end
330
368
 
331
369
  def ol_item(lines, _num)
332
- puts "<li>#{lines.join}</li>"
370
+ puts "<li>#{join_lines_to_paragraph(lines)}</li>"
333
371
  end
334
372
 
335
373
  def ol_end
@@ -345,7 +383,7 @@ module ReVIEW
345
383
  end
346
384
 
347
385
  def dd(lines)
348
- puts "<dd>#{lines.join}</dd>"
386
+ puts "<dd>#{join_lines_to_paragraph(lines)}</dd>"
349
387
  end
350
388
 
351
389
  def dl_end
@@ -354,10 +392,10 @@ module ReVIEW
354
392
 
355
393
  def paragraph(lines)
356
394
  if @noindent
357
- puts %Q(<p class="noindent">#{lines.join}</p>)
395
+ puts %Q(<p class="noindent">#{join_lines_to_paragraph(lines)}</p>)
358
396
  @noindent = nil
359
397
  else
360
- puts "<p>#{lines.join}</p>"
398
+ puts "<p>#{join_lines_to_paragraph(lines)}</p>"
361
399
  end
362
400
  end
363
401
 
@@ -374,12 +412,7 @@ module ReVIEW
374
412
 
375
413
  def list(lines, id, caption, lang = nil)
376
414
  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
415
+ super(lines, id, caption, lang)
383
416
  puts '</div>'
384
417
  end
385
418
 
@@ -404,8 +437,7 @@ module ReVIEW
404
437
 
405
438
  def source(lines, caption = nil, lang = nil)
406
439
  puts %Q(<div class="source-code">)
407
- source_header caption
408
- source_body caption, lines, lang
440
+ super(lines, caption, lang)
409
441
  puts '</div>'
410
442
  end
411
443
 
@@ -415,7 +447,7 @@ module ReVIEW
415
447
  end
416
448
  end
417
449
 
418
- def source_body(_id, lines, lang)
450
+ def source_body(lines, lang)
419
451
  print %Q(<pre class="source">)
420
452
  body = lines.inject('') { |i, j| i + detab(j) + "\n" }
421
453
  lexer = lang
@@ -425,12 +457,7 @@ module ReVIEW
425
457
 
426
458
  def listnum(lines, id, caption, lang = nil)
427
459
  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
460
+ super(lines, id, caption, lang)
434
461
  puts '</div>'
435
462
  end
436
463
 
@@ -456,7 +483,7 @@ module ReVIEW
456
483
 
457
484
  def emlist(lines, caption = nil, lang = nil)
458
485
  puts %Q(<div class="emlist-code">)
459
- if caption.present?
486
+ if caption_top?('list') && caption.present?
460
487
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
461
488
  end
462
489
  class_names = ['emlist']
@@ -467,12 +494,15 @@ module ReVIEW
467
494
  lexer = lang
468
495
  puts highlight(body: body, lexer: lexer, format: 'html')
469
496
  puts '</pre>'
497
+ if !caption_top?('list') && caption.present?
498
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
499
+ end
470
500
  puts '</div>'
471
501
  end
472
502
 
473
503
  def emlistnum(lines, caption = nil, lang = nil)
474
504
  puts %Q(<div class="emlistnum-code">)
475
- if caption.present?
505
+ if caption_top?('list') && caption.present?
476
506
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
477
507
  end
478
508
 
@@ -494,19 +524,29 @@ module ReVIEW
494
524
  puts '</pre>'
495
525
  end
496
526
 
527
+ if !caption_top?('list') && caption.present?
528
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
529
+ end
530
+
497
531
  puts '</div>'
498
532
  end
499
533
 
500
534
  def cmd(lines, caption = nil)
501
535
  puts %Q(<div class="cmd-code">)
502
- if caption.present?
536
+ if caption_top?('list') && caption.present?
503
537
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
504
538
  end
539
+
505
540
  print %Q(<pre class="cmd">)
506
541
  body = lines.inject('') { |i, j| i + detab(j) + "\n" }
507
542
  lexer = 'shell-session'
508
543
  puts highlight(body: body, lexer: lexer, format: 'html')
509
544
  puts '</pre>'
545
+
546
+ if !caption_top?('list') && caption.present?
547
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
548
+ end
549
+
510
550
  puts '</div>'
511
551
  end
512
552
 
@@ -541,18 +581,19 @@ module ReVIEW
541
581
 
542
582
  def texequation(lines, id = nil, caption = '')
543
583
  if id
544
- texequation_header id, caption
584
+ puts %Q(<div id="#{normalize_id(id)}" class="caption-equation">)
585
+ texequation_header(id, caption) if caption_top?('equation')
545
586
  end
546
587
 
547
588
  texequation_body(lines)
548
589
 
549
590
  if id
591
+ texequation_header(id, caption) unless caption_top?('equation')
550
592
  puts '</div>'
551
593
  end
552
594
  end
553
595
 
554
596
  def texequation_header(id, caption)
555
- puts %Q(<div id="#{normalize_id(id)}" class="caption-equation">)
556
597
  if get_chap
557
598
  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
599
  else
@@ -566,11 +607,11 @@ module ReVIEW
566
607
  require 'math_ml'
567
608
  require 'math_ml/symbol/character_reference'
568
609
  p = MathML::LaTeX::Parser.new(symbol: MathML::Symbol::CharacterReference)
569
- puts p.parse(unescape(lines.join("\n")), true)
610
+ print p.parse(lines.join("\n") + "\n", true)
570
611
  elsif @book.config['imgmath']
571
612
  fontsize = @book.config['imgmath_options']['fontsize'].to_f
572
613
  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"
614
+ math_str = "\\begin{equation*}\n\\fontsize{#{fontsize}}{#{lineheight}}\\selectfont\n#{lines.join("\n")}\n\\end{equation*}\n"
574
615
  key = Digest::SHA256.hexdigest(math_str)
575
616
  math_dir = File.join(@book.config['imagedir'], '_review_math')
576
617
  Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
@@ -615,20 +656,22 @@ module ReVIEW
615
656
  def image_image(id, caption, metric)
616
657
  metrics = parse_metric('html', metric)
617
658
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
659
+ image_header(id, caption) if caption_top?('image')
618
660
  puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
619
- image_header id, caption
661
+ image_header(id, caption) unless caption_top?('image')
620
662
  puts '</div>'
621
663
  end
622
664
 
623
665
  def image_dummy(id, caption, lines)
624
666
  warn "image not bound: #{id}"
625
667
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
668
+ image_header(id, caption) if caption_top?('image')
626
669
  puts %Q(<pre class="dummyimage">)
627
670
  lines.each do |line|
628
671
  puts detab(line)
629
672
  end
630
673
  puts '</pre>'
631
- image_header id, caption
674
+ image_header(id, caption) unless caption_top?('image')
632
675
  puts '</div>'
633
676
  end
634
677
 
@@ -643,47 +686,12 @@ module ReVIEW
643
686
  end
644
687
 
645
688
  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
-
659
689
  if id
660
690
  puts %Q(<div id="#{normalize_id(id)}" class="table">)
661
691
  else
662
692
  puts %Q(<div class="table">)
663
693
  end
664
- begin
665
- if caption.present?
666
- table_header id, caption
667
- end
668
- rescue KeyError
669
- error "no such table: #{id}"
670
- end
671
- table_begin rows.first.size
672
- return if rows.empty?
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
694
+ super(lines, id, caption)
687
695
  puts '</div>'
688
696
  end
689
697
 
@@ -718,23 +726,27 @@ module ReVIEW
718
726
  end
719
727
 
720
728
  def imgtable(lines, id, caption = nil, metric = nil)
721
- unless @chapter.image(id).bound?
729
+ unless @chapter.image_bound?(id)
722
730
  warn "image not bound: #{id}"
723
- image_dummy id, caption, lines
731
+ image_dummy(id, caption, lines)
724
732
  return
725
733
  end
726
734
 
727
735
  puts %Q(<div id="#{normalize_id(id)}" class="imgtable image">)
728
736
  begin
729
- if caption.present?
730
- table_header id, caption
737
+ if caption_top?('table') && caption.present?
738
+ table_header(id, caption)
739
+ end
740
+
741
+ imgtable_image(id, caption, metric)
742
+
743
+ if !caption_top?('table') && caption.present?
744
+ table_header(id, caption)
731
745
  end
732
746
  rescue KeyError
733
747
  error "no such table: #{id}"
734
748
  end
735
749
 
736
- imgtable_image(id, caption, metric)
737
-
738
750
  puts '</div>'
739
751
  end
740
752
 
@@ -750,7 +762,7 @@ module ReVIEW
750
762
  def comment(lines, comment = nil)
751
763
  return unless @book.config['draft']
752
764
  lines ||= []
753
- lines.unshift escape(comment) unless comment.blank?
765
+ lines.unshift(escape(comment)) unless comment.blank?
754
766
  str = lines.join('<br />')
755
767
  puts %Q(<div class="draft-comment">#{str}</div>)
756
768
  end
@@ -771,7 +783,19 @@ module ReVIEW
771
783
  def indepimage(lines, id, caption = '', metric = nil)
772
784
  metrics = parse_metric('html', metric)
773
785
  caption = '' unless caption.present?
786
+ caption_str = nil
787
+ if caption.present?
788
+ caption_str = <<-EOS
789
+ <p class="caption">
790
+ #{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)}
791
+ </p>
792
+ EOS
793
+ end
794
+
774
795
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
796
+ if caption_top?('image') && caption.present?
797
+ puts caption_str
798
+ end
775
799
  begin
776
800
  puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
777
801
  rescue
@@ -785,10 +809,8 @@ module ReVIEW
785
809
  end
786
810
  end
787
811
 
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>'
812
+ if !caption_top?('image') && caption.present?
813
+ puts caption_str
792
814
  end
793
815
  puts '</div>'
794
816
  end
@@ -978,8 +1000,8 @@ module ReVIEW
978
1000
 
979
1001
  def bibpaper(lines, id, caption)
980
1002
  puts %Q(<div class="bibpaper">)
981
- bibpaper_header id, caption
982
- bibpaper_bibpaper id, caption, lines unless lines.empty?
1003
+ bibpaper_header(id, caption)
1004
+ bibpaper_bibpaper(id, caption, lines) unless lines.empty?
983
1005
  puts '</div>'
984
1006
  end
985
1007
 
@@ -1002,7 +1024,7 @@ module ReVIEW
1002
1024
 
1003
1025
  def inline_hd_chap(chap, id)
1004
1026
  n = chap.headline_index.number(id)
1005
- if chap.number and @book.config['secnolevel'] >= n.split('.').size
1027
+ if n.present? && chap.number && over_secnolevel?(n)
1006
1028
  str = I18n.t('hd_quote', [n, compile_inline(chap.headline(id).caption)])
1007
1029
  else
1008
1030
  str = I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
@@ -1025,7 +1047,7 @@ module ReVIEW
1025
1047
 
1026
1048
  def inline_column_chap(chapter, id)
1027
1049
  if @book.config['chapterlink']
1028
- %Q(<a href="\##{column_label(id, chapter)}" class="columnref">#{I18n.t('column', compile_inline(chapter.column(id).caption))}</a>)
1050
+ %Q(<a href="#{chapter.id}#{extname}##{column_label(id, chapter)}" class="columnref">#{I18n.t('column', compile_inline(chapter.column(id).caption))}</a>)
1029
1051
  else
1030
1052
  I18n.t('column', compile_inline(chapter.column(id).caption))
1031
1053
  end
@@ -1187,7 +1209,7 @@ module ReVIEW
1187
1209
  %Q(<span class="balloon">#{escape_html(str)}</span>)
1188
1210
  end
1189
1211
 
1190
- def inline_raw(str)
1212
+ def inline_raw(str) # rubocop:disable Lint/UselessMethodDefinition
1191
1213
  super(str)
1192
1214
  end
1193
1215
 
@@ -1219,17 +1241,6 @@ module ReVIEW
1219
1241
  @ol_num = num.to_i
1220
1242
  end
1221
1243
 
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
1244
  def make_math_image(str, path, fontsize = 12)
1234
1245
  # Re:VIEW 2 compatibility
1235
1246
  fontsize2 = (fontsize * 1.2).round.to_i