review 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -1
  3. data/.rubocop.yml +4 -1
  4. data/NEWS.ja.md +29 -0
  5. data/NEWS.md +29 -0
  6. data/bin/review-index +2 -89
  7. data/bin/review-vol +4 -78
  8. data/doc/config.yml.sample +18 -5
  9. data/doc/config.yml.sample-simple +1 -1
  10. data/doc/pdfmaker.ja.md +42 -0
  11. data/doc/pdfmaker.md +41 -0
  12. data/doc/quickstart.ja.md +8 -5
  13. data/doc/quickstart.md +7 -4
  14. data/lib/review/book/base.rb +2 -4
  15. data/lib/review/book/compilable.rb +1 -5
  16. data/lib/review/book/page_metric.rb +7 -7
  17. data/lib/review/book/part.rb +6 -3
  18. data/lib/review/book/volume.rb +3 -4
  19. data/lib/review/builder.rb +23 -10
  20. data/lib/review/compiler.rb +9 -9
  21. data/lib/review/configure.rb +6 -0
  22. data/lib/review/epubmaker.rb +1 -1
  23. data/lib/review/htmlbuilder.rb +56 -16
  24. data/lib/review/idgxmlbuilder.rb +63 -22
  25. data/lib/review/latexbuilder.rb +70 -19
  26. data/lib/review/makerhelper.rb +18 -1
  27. data/lib/review/pdfmaker.rb +8 -1
  28. data/lib/review/plaintextbuilder.rb +41 -11
  29. data/lib/review/textmaker.rb +1 -1
  30. data/lib/review/textutils.rb +2 -3
  31. data/lib/review/tocprinter.rb +231 -102
  32. data/lib/review/topbuilder.rb +47 -13
  33. data/lib/review/version.rb +1 -1
  34. data/lib/review/volumeprinter.rb +99 -0
  35. data/lib/review/webmaker.rb +1 -1
  36. data/lib/review/webtocprinter.rb +38 -35
  37. data/review.gemspec +1 -1
  38. data/samples/sample-book/src/config.yml +1 -1
  39. data/templates/web/html/layout-html5.html.erb +2 -2
  40. data/test/test_book.rb +1 -1
  41. data/test/test_book_part.rb +3 -3
  42. data/test/test_helper.rb +4 -1
  43. data/test/test_htmlbuilder.rb +179 -0
  44. data/test/test_idgxmlbuilder.rb +143 -0
  45. data/test/test_latexbuilder.rb +223 -0
  46. data/test/test_pdfmaker.rb +17 -0
  47. data/test/test_plaintextbuilder.rb +99 -0
  48. data/test/test_topbuilder.rb +116 -2
  49. data/test/test_webtocprinter.rb +66 -34
  50. metadata +3 -5
  51. data/lib/review/tocparser.rb +0 -275
  52. data/test/test_tocparser.rb +0 -25
@@ -8,7 +8,7 @@ Re:VIEW は GNU Lesser General Public License Version 2.1 に基づいて配布
8
8
 
9
9
  このドキュメントでは、Re:VIEW のセットアップから変換の例までを簡単に説明します。
10
10
 
11
- このドキュメントは、Re:VIEW 4.0 に基づいています。
11
+ このドキュメントは、Re:VIEW 4.2 に基づいています。
12
12
 
13
13
  ## セットアップ
14
14
 
@@ -217,19 +217,22 @@ $ review-preproc --replace ファイル ←ファイルを更新したもので
217
217
  $ review-vol
218
218
  ```
219
219
 
220
- より細かな見出し一覧などを出したいときには、review-index コマンドを使うのもよいでしょう。
220
+ より細かな見出し一覧などを出したいときには、review-index コマンドを使うとよいでしょう。
221
221
 
222
222
  ```bash
223
- $ review-index --level 掘り下げる見出しレベル数 -a
223
+ $ review-index -l 掘り下げる見出しレベル数
224
+ $ review-index -l 掘り下げる見出しレベル数 -d ←分量の詳細を表示
224
225
  ```
225
226
 
227
+ review-vol と review-index では、文字数や行数、見込みページなど各値に大きな差が出ることがあります。これは、review-vol がごく簡単にファイルから概算しているのに対し、review-index は実際に内部でコンパイルして比較的精密に計量しているからです。
228
+
226
229
  ## プロジェクトフォルダを新しい Re:VIEW バージョンに追従する方法
227
230
 
228
231
  Re:VIEW は定期的に更新されています。おおむね後方互換性を保持していますが、新しいバージョン固有の機能を利用したいときには、プロジェクトフォルダを新しいバージョンに更新する review-update コマンドを利用します。
229
232
 
230
233
  ```bash
231
234
  $ review-update
232
- ** review-update はプロジェクトを 4.0.0 に更新します **
235
+ ** review-update はプロジェクトを 4.1.0 に更新します **
233
236
  config.yml: 'review_version' を '4.0' に更新しますか? [y]/n ←Enterで実行
234
237
  Rakefile は Re:VIEW バージョンのもの (/.../review/samples/sample-book/src/Rakefile) で置き換えられます。本当に進めますか? [y]/n
235
238
  lib/tasks/review.rake は Re:VIEW バージョンのもの (/.../review/samples/sample-book/src/lib/tasks/review.rake) で置き換えられます。本当に進めますか? [y]/n
@@ -246,7 +249,7 @@ INFO: 新しいファイル /.../sty/gentombow.sty が作成されました。
246
249
 
247
250
  ## クレジット
248
251
 
249
- Re:VIEW は、青木峰郎によって最初に作成されました。武藤健志がこの開発・保守を引き継ぎ、201912月時点では、武藤健志、高橋征義、角征典が開発・保守を継続しています。
252
+ Re:VIEW は、青木峰郎によって最初に作成されました。武藤健志がこの開発・保守を引き継ぎ、20203月時点では、武藤健志、高橋征義、角征典が開発・保守を継続しています。
250
253
 
251
254
  バグ・パッチの報告、その他の情報は、
252
255
 
@@ -9,7 +9,7 @@ Re:VIEW is free software under the terms of the GNU Lesser General Public Licens
9
9
 
10
10
  This article describes how to setup Re:VIEW and use it.
11
11
 
12
- The supported version of the article is Re:VIEW 4.0.
12
+ The supported version of the article is Re:VIEW 4.2.
13
13
 
14
14
  ## Set up Re:VIEW
15
15
 
@@ -223,16 +223,19 @@ $ review-vol
223
223
  You can also use `review-index` command to generate header list.
224
224
 
225
225
  ```bash
226
- $ review-index --level <heading level> -a
226
+ $ review-index --level <heading level>
227
+ $ review-index --level <heading level> -d ## show volumes also
227
228
  ```
228
229
 
230
+ review-vol and review-index can have large differences in the number of characters, lines, and pages. While review-vol only estimates from the file, review-index actually compiles and calculates.
231
+
229
232
  ## how to update the document folder to the new Re:VIEW version
230
233
 
231
234
  Re:VIEW is updated regularly. We Re:VIEW team watch the backward compatibility carefully, but if you want to use the features in the new version, you can use review-update command to update the project folder.
232
235
 
233
236
  ```bash
234
237
  $ review-update
235
- ** review-update updates your project to 4.0.0 **
238
+ ** review-update updates your project to 4.1.0 **
236
239
  config.yml: Update 'review_version' to '4.0'? [y]/n
237
240
  Rakefile will be overridden with Re:VIEW version (/.../review/samples/sample-book/src/Rakefile). Do you really proceed? [y]/n
238
241
  lib/tasks/review.rake will be overridden with Re:VIEW version (/.../review/samples/sample-book/src/lib/tasks/review.rake). Do you really proceed? [y]/n
@@ -249,7 +252,7 @@ Finished.
249
252
 
250
253
  ## Copyright
251
254
 
252
- The original author of Re:VIEW is Minero Aoki. The current maintainer is Kenshi Muto(@kmuto), and committers are Masayoshi Takahashi and Masanori Kado (December 2019).
255
+ The original author of Re:VIEW is Minero Aoki. The current maintainer is Kenshi Muto(@kmuto), and committers are Masayoshi Takahashi and Masanori Kado (March 2020).
253
256
 
254
257
  If you want to report bugs and patches, or to get more information, see:
255
258
 
@@ -79,7 +79,7 @@ module ReVIEW
79
79
  def page_metric
80
80
  if config['page_metric'].respond_to?(:downcase) && config['page_metric'].upcase =~ /\A[A-Z0-9_]+\Z/
81
81
  ReVIEW::Book::PageMetric.const_get(config['page_metric'].upcase)
82
- elsif config['page_metric'].is_a?(Array) && config['page_metric'].size == 5
82
+ elsif config['page_metric'].is_a?(Array) && (config['page_metric'].size == 5 || config['page_metric'].size == 4)
83
83
  ReVIEW::Book::PageMetric.new(*config['page_metric'])
84
84
  else
85
85
  config['page_metric']
@@ -175,9 +175,7 @@ module ReVIEW
175
175
  end
176
176
 
177
177
  def volume
178
- vol = Volume.sum(chapters.map(&:volume))
179
- vol.page_per_kbyte = page_metric.page_per_kbyte
180
- vol
178
+ Volume.sum(parts.map(&:volume) + chapters.map(&:volume))
181
179
  end
182
180
 
183
181
  def load_config(filename)
@@ -52,11 +52,7 @@ module ReVIEW
52
52
  end
53
53
 
54
54
  def volume
55
- unless @volume
56
- @volume = Volume.count_file(path)
57
- @volume.page_per_kbyte = @book.page_metric.page_per_kbyte
58
- end
59
- @volume
55
+ @volume ||= Volume.count_file(path)
60
56
  end
61
57
 
62
58
  def lines
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2009-2017 Minero Aoki, Kenshi Muto
1
+ # Copyright (c) 2009-2020 Minero Aoki, Kenshi Muto
2
2
  # 2002-2008 Minero Aoki
3
3
  #
4
4
  # This program is free software.
@@ -11,21 +11,21 @@ module ReVIEW
11
11
  class PageMetric
12
12
  MetricData = Struct.new(:n_lines, :n_columns)
13
13
 
14
- def initialize(list_lines, list_columns, text_lines, text_columns, page_per_kbyte)
14
+ def initialize(list_lines, list_columns, text_lines, text_columns, _page_per_kbyte = 1)
15
+ # page_per_kbyte is obsolete. Just for backward compatibility
15
16
  @list = MetricData.new(list_lines, list_columns)
16
17
  @text = MetricData.new(text_lines, text_columns)
17
- @page_per_kbyte = page_per_kbyte
18
18
  end
19
19
 
20
- A5 = PageMetric.new(46, 80, 30, 74, 1)
21
- B5 = PageMetric.new(46, 80, 30, 74, 2)
20
+ # based on review-jsbook's default
21
+ A5 = PageMetric.new(40, 34, 29, 34)
22
+ B5 = PageMetric.new(50, 40, 36, 40)
22
23
 
23
24
  attr_reader :list
24
25
  attr_reader :text
25
- attr_reader :page_per_kbyte
26
26
 
27
27
  def ==(other)
28
- self.list == other.list && self.text == other.text && self.page_per_kbyte == other.page_per_kbyte
28
+ self.list == other.list && self.text == other.text
29
29
  end
30
30
  end
31
31
  end
@@ -41,7 +41,7 @@ module ReVIEW
41
41
  @chapters = chapters
42
42
  @name = name
43
43
  @path = name
44
- @content = nil
44
+ @content = ''
45
45
  if io
46
46
  @content = io.read
47
47
  elsif @path.present? && File.exist?(File.join(@book.config['contentdir'], @path))
@@ -65,8 +65,11 @@ module ReVIEW
65
65
  end
66
66
 
67
67
  def volume
68
- vol = Volume.sum(@chapters.map(&:volume))
69
- vol.page_per_kbyte = @book.page_metric.page_per_kbyte
68
+ if @number && file?
69
+ vol = Volume.count_file(File.join(@book.config['contentdir'], @path))
70
+ else
71
+ vol = Volume.new(0, 0, 0)
72
+ end
70
73
  vol
71
74
  end
72
75
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2007-2017 Minero Aoki, Kenshi Muto
1
+ # Copyright (c) 2007-2020 Minero Aoki, Kenshi Muto
2
2
  # 2002-2007 Minero Aoki
3
3
  #
4
4
  # This program is free software.
@@ -33,20 +33,19 @@ module ReVIEW
33
33
  @bytes = bytes
34
34
  @chars = chars
35
35
  @lines = lines
36
- @page_per_kbyte = nil
37
36
  end
38
37
 
39
38
  attr_reader :bytes
40
39
  attr_reader :chars
41
40
  attr_accessor :lines
42
- attr_accessor :page_per_kbyte
43
41
 
44
42
  def kbytes
45
43
  (@bytes.to_f / 1024).ceil
46
44
  end
47
45
 
48
46
  def page
49
- (kbytes.to_f / @page_per_kbyte).ceil
47
+ # XXX:unrelibable
48
+ kbytes.to_f.ceil
50
49
  end
51
50
 
52
51
  def to_s
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2002-2019 Minero Aoki, Kenshi Muto
1
+ # Copyright (c) 2002-2020 Minero Aoki, Kenshi Muto
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -142,25 +142,28 @@ module ReVIEW
142
142
 
143
143
  def list(lines, id, caption, lang = nil)
144
144
  begin
145
- list_header(id, caption, lang)
145
+ list_header(id, caption, lang) if caption_top?('list')
146
+ list_body(id, lines, lang)
147
+ list_header(id, caption, lang) unless caption_top?('list')
146
148
  rescue KeyError
147
149
  error "no such list: #{id}"
148
150
  end
149
- list_body(id, lines, lang)
150
151
  end
151
152
 
152
153
  def listnum(lines, id, caption, lang = nil)
153
154
  begin
154
- list_header(id, caption, lang)
155
+ list_header(id, caption, lang) if caption_top?('list')
156
+ listnum_body(lines, lang)
157
+ list_header(id, caption, lang) unless caption_top?('list')
155
158
  rescue KeyError
156
159
  error "no such list: #{id}"
157
160
  end
158
- listnum_body(lines, lang)
159
161
  end
160
162
 
161
163
  def source(lines, caption = nil, lang = nil)
162
- source_header(caption)
164
+ source_header(caption) if caption_top?('list')
163
165
  source_body(lines, lang)
166
+ source_header(caption) unless caption_top?('list')
164
167
  end
165
168
 
166
169
  def image(lines, id, caption, metric = nil)
@@ -175,15 +178,18 @@ module ReVIEW
175
178
  def table(lines, id = nil, caption = nil)
176
179
  sepidx, rows = parse_table_rows(lines)
177
180
  begin
178
- if caption.present?
181
+ if caption_top?('table') && caption.present?
182
+ table_header(id, caption)
183
+ end
184
+ table_begin(rows.first.size)
185
+ table_rows(sepidx, rows)
186
+ table_end
187
+ if !caption_top?('table') && caption.present?
179
188
  table_header(id, caption)
180
189
  end
181
190
  rescue KeyError
182
191
  error "no such table: #{id}"
183
192
  end
184
- table_begin(rows.first.size)
185
- table_rows(sepidx, rows)
186
- table_end
187
193
  end
188
194
 
189
195
  def table_row_separator_regexp
@@ -680,5 +686,12 @@ EOTGNUPLOT
680
686
  def escape(str)
681
687
  str
682
688
  end
689
+
690
+ def caption_top?(type)
691
+ unless %w[top bottom].include?(@book.config['caption_position'][type])
692
+ warn("invalid caption_position/#{type} parameter. 'top' is assumed")
693
+ end
694
+ @book.config['caption_position'][type] != 'bottom'
695
+ end
683
696
  end
684
697
  end # module ReVIEW
@@ -26,6 +26,14 @@ module ReVIEW
26
26
 
27
27
  attr_reader :strategy
28
28
 
29
+ def non_escaped_commands
30
+ if @strategy.highlight?
31
+ %i[list emlist listnum emlistnum cmd]
32
+ else
33
+ []
34
+ end
35
+ end
36
+
29
37
  def compile(chap)
30
38
  @chapter = chap
31
39
  do_compile
@@ -225,14 +233,6 @@ module ReVIEW
225
233
  f = LineInput.new(StringIO.new(@chapter.content))
226
234
  @strategy.bind(self, @chapter, Location.new(@chapter.basename, f))
227
235
 
228
- @non_parsed_commands = %i[embed texequation graph]
229
- if @strategy.highlight?
230
- @non_escaped_commands = %i[list emlist listnum emlistnum cmd]
231
- else
232
- @non_escaped_commands = []
233
- end
234
- @command_name_stack = []
235
-
236
236
  tagged_section_init
237
237
  while f.next?
238
238
  case f.peek
@@ -554,7 +554,7 @@ module ReVIEW
554
554
 
555
555
  def in_non_escaped_command?
556
556
  current_command = @command_name_stack.last
557
- current_command && @non_escaped_commands.include?(current_command)
557
+ current_command && non_escaped_commands.include?(current_command)
558
558
  end
559
559
 
560
560
  def text(str, block_mode = false)
@@ -106,6 +106,12 @@ module ReVIEW
106
106
  'lineheight' => 10 * 1.2,
107
107
  'pdfcrop_pixelize_cmd' => 'pdftocairo -%t -r 90 -f %p -l %p -singlefile %i %O',
108
108
  'dvipng_cmd' => 'dvipng -T tight -z 9 -p %p -l %p -o %o %i'
109
+ },
110
+ 'caption_position' => {
111
+ 'list' => 'top',
112
+ 'image' => 'bottom',
113
+ 'table' => 'top',
114
+ 'equation' => 'top'
109
115
  }
110
116
  ]
111
117
  conf.maker = nil
@@ -166,7 +166,7 @@ module ReVIEW
166
166
  copy_backmatter(basetmpdir)
167
167
 
168
168
  math_dir = "./#{@config['imagedir']}/_review_math"
169
- if @config['imgmath'] && File.exist?(File.join(math_dir, '__IMGMATH_BODY__.tex'))
169
+ if @config['imgmath'] && File.exist?(File.join(math_dir, '__IMGMATH_BODY__.map'))
170
170
  make_math_images(math_dir)
171
171
  end
172
172
  call_hook('hook_afterbackmatter', basetmpdir)
@@ -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
  #
@@ -286,15 +286,25 @@ module ReVIEW
286
286
  end
287
287
 
288
288
  def box(lines, caption = nil)
289
- puts %Q(<div class="syntax">)
289
+ captionstr = nil
290
290
  if caption.present?
291
- puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
291
+ captionstr = %Q(<p class="caption">#{compile_inline(caption)}</p>)
292
+ end
293
+ puts %Q(<div class="syntax">)
294
+
295
+ if caption_top?('list') && caption.present?
296
+ puts captionstr
292
297
  end
298
+
293
299
  print %Q(<pre class="syntax">)
294
300
  lines.each do |line|
295
301
  puts detab(line)
296
302
  end
297
303
  puts '</pre>'
304
+
305
+ if !caption_top?('list') && caption.present?
306
+ puts captionstr
307
+ end
298
308
  puts '</div>'
299
309
  end
300
310
 
@@ -444,7 +454,7 @@ module ReVIEW
444
454
 
445
455
  def emlist(lines, caption = nil, lang = nil)
446
456
  puts %Q(<div class="emlist-code">)
447
- if caption.present?
457
+ if caption_top?('list') && caption.present?
448
458
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
449
459
  end
450
460
  class_names = ['emlist']
@@ -455,12 +465,15 @@ module ReVIEW
455
465
  lexer = lang
456
466
  puts highlight(body: body, lexer: lexer, format: 'html')
457
467
  puts '</pre>'
468
+ if !caption_top?('list') && caption.present?
469
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
470
+ end
458
471
  puts '</div>'
459
472
  end
460
473
 
461
474
  def emlistnum(lines, caption = nil, lang = nil)
462
475
  puts %Q(<div class="emlistnum-code">)
463
- if caption.present?
476
+ if caption_top?('list') && caption.present?
464
477
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
465
478
  end
466
479
 
@@ -482,19 +495,29 @@ module ReVIEW
482
495
  puts '</pre>'
483
496
  end
484
497
 
498
+ if !caption_top?('list') && caption.present?
499
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
500
+ end
501
+
485
502
  puts '</div>'
486
503
  end
487
504
 
488
505
  def cmd(lines, caption = nil)
489
506
  puts %Q(<div class="cmd-code">)
490
- if caption.present?
507
+ if caption_top?('list') && caption.present?
491
508
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
492
509
  end
510
+
493
511
  print %Q(<pre class="cmd">)
494
512
  body = lines.inject('') { |i, j| i + detab(j) + "\n" }
495
513
  lexer = 'shell-session'
496
514
  puts highlight(body: body, lexer: lexer, format: 'html')
497
515
  puts '</pre>'
516
+
517
+ if !caption_top?('list') && caption.present?
518
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
519
+ end
520
+
498
521
  puts '</div>'
499
522
  end
500
523
 
@@ -530,12 +553,13 @@ module ReVIEW
530
553
  def texequation(lines, id = nil, caption = '')
531
554
  if id
532
555
  puts %Q(<div id="#{normalize_id(id)}" class="caption-equation">)
533
- texequation_header(id, caption)
556
+ texequation_header(id, caption) if caption_top?('equation')
534
557
  end
535
558
 
536
559
  texequation_body(lines)
537
560
 
538
561
  if id
562
+ texequation_header(id, caption) unless caption_top?('equation')
539
563
  puts '</div>'
540
564
  end
541
565
  end
@@ -603,20 +627,22 @@ module ReVIEW
603
627
  def image_image(id, caption, metric)
604
628
  metrics = parse_metric('html', metric)
605
629
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
630
+ image_header(id, caption) if caption_top?('image')
606
631
  puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
607
- image_header(id, caption)
632
+ image_header(id, caption) unless caption_top?('image')
608
633
  puts '</div>'
609
634
  end
610
635
 
611
636
  def image_dummy(id, caption, lines)
612
637
  warn "image not bound: #{id}"
613
638
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
639
+ image_header(id, caption) if caption_top?('image')
614
640
  puts %Q(<pre class="dummyimage">)
615
641
  lines.each do |line|
616
642
  puts detab(line)
617
643
  end
618
644
  puts '</pre>'
619
- image_header(id, caption)
645
+ image_header(id, caption) unless caption_top?('image')
620
646
  puts '</div>'
621
647
  end
622
648
 
@@ -679,15 +705,19 @@ module ReVIEW
679
705
 
680
706
  puts %Q(<div id="#{normalize_id(id)}" class="imgtable image">)
681
707
  begin
682
- if caption.present?
708
+ if caption_top?('table') && caption.present?
709
+ table_header(id, caption)
710
+ end
711
+
712
+ imgtable_image(id, caption, metric)
713
+
714
+ if !caption_top?('table') && caption.present?
683
715
  table_header(id, caption)
684
716
  end
685
717
  rescue KeyError
686
718
  error "no such table: #{id}"
687
719
  end
688
720
 
689
- imgtable_image(id, caption, metric)
690
-
691
721
  puts '</div>'
692
722
  end
693
723
 
@@ -724,7 +754,19 @@ module ReVIEW
724
754
  def indepimage(lines, id, caption = '', metric = nil)
725
755
  metrics = parse_metric('html', metric)
726
756
  caption = '' unless caption.present?
757
+ caption_str = nil
758
+ if caption.present?
759
+ caption_str = <<-EOS
760
+ <p class="caption">
761
+ #{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)}
762
+ </p>
763
+ EOS
764
+ end
765
+
727
766
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
767
+ if caption_top?('image') && caption.present?
768
+ puts caption_str
769
+ end
728
770
  begin
729
771
  puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
730
772
  rescue
@@ -738,10 +780,8 @@ module ReVIEW
738
780
  end
739
781
  end
740
782
 
741
- if caption.present?
742
- puts %Q(<p class="caption">)
743
- puts %Q(#{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)})
744
- puts '</p>'
783
+ if !caption_top?('image') && caption.present?
784
+ puts caption_str
745
785
  end
746
786
  puts '</div>'
747
787
  end