review 4.1.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2008-2019 Minero Aoki, Kenshi Muto
1
+ # Copyright (c) 2008-2020 Minero Aoki, Kenshi Muto
2
2
  # 2002-2007 Minero Aoki
3
3
  #
4
4
  # This program is free software.
@@ -351,7 +351,9 @@ module ReVIEW
351
351
 
352
352
  def quotedlist(lines, css_class, caption)
353
353
  print %Q(<list type='#{css_class}'>)
354
- puts "<caption aid:pstyle='#{css_class}-title'>#{compile_inline(caption)}</caption>" if caption.present?
354
+ if caption_top?('list') && caption.present?
355
+ puts "<caption aid:pstyle='#{css_class}-title'>#{compile_inline(caption)}</caption>"
356
+ end
355
357
  print '<pre>'
356
358
  no = 1
357
359
  lines.each do |line|
@@ -366,7 +368,11 @@ module ReVIEW
366
368
  print '</listinfo>' if @book.config['listinfo']
367
369
  no += 1
368
370
  end
369
- puts '</pre></list>'
371
+ puts '</pre>'
372
+ if !caption_top?('list') && caption.present?
373
+ puts "<caption aid:pstyle='#{css_class}-title'>#{compile_inline(caption)}</caption>"
374
+ end
375
+ puts '</list>'
370
376
  end
371
377
  private :quotedlist
372
378
 
@@ -410,20 +416,22 @@ module ReVIEW
410
416
  def image_image(id, caption, metric = nil)
411
417
  metrics = parse_metric('idgxml', metric)
412
418
  puts '<img>'
419
+ image_header(id, caption) if caption_top?('image')
413
420
  puts %Q(<Image href="file://#{@chapter.image(id).path.sub(%r{\A./}, '')}"#{metrics} />)
414
- image_header(id, caption)
421
+ image_header(id, caption) unless caption_top?('image')
415
422
  puts '</img>'
416
423
  end
417
424
 
418
425
  def image_dummy(id, caption, lines)
419
426
  puts '<img>'
427
+ image_header(id, caption) if caption_top?('image')
420
428
  print %Q(<pre aid:pstyle="dummyimage">)
421
429
  lines.each do |line|
422
430
  print detab(line)
423
431
  print "\n"
424
432
  end
425
433
  print '</pre>'
426
- image_header(id, caption)
434
+ image_header(id, caption) unless caption_top?('image')
427
435
  puts '</img>'
428
436
  warn "image not bound: #{id}"
429
437
  end
@@ -439,13 +447,15 @@ module ReVIEW
439
447
 
440
448
  def texequation(lines, id = nil, caption = '')
441
449
  @texblockequation += 1
450
+ caption_str = nil
442
451
  if id
443
452
  puts '<equationblock>'
444
453
  if get_chap.nil?
445
- puts %Q(<caption>#{I18n.t('equation')}#{I18n.t('format_number_without_chapter', [@chapter.equation(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}</caption>)
454
+ caption_str = %Q(<caption>#{I18n.t('equation')}#{I18n.t('format_number_without_chapter', [@chapter.equation(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}</caption>)
446
455
  else
447
- puts %Q(<caption>#{I18n.t('equation')}#{I18n.t('format_number', [get_chap, @chapter.equation(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}</caption>)
456
+ caption_str = %Q(<caption>#{I18n.t('equation')}#{I18n.t('format_number', [get_chap, @chapter.equation(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}</caption>)
448
457
  end
458
+ puts caption_str if caption_top?('equation')
449
459
  end
450
460
 
451
461
  puts %Q(<replace idref="texblock-#{@texblockequation}">)
@@ -455,6 +465,7 @@ module ReVIEW
455
465
  puts '</replace>'
456
466
 
457
467
  if id
468
+ puts caption_str unless caption_top?('equation')
458
469
  puts '</equationblock>'
459
470
  end
460
471
  end
@@ -470,19 +481,26 @@ module ReVIEW
470
481
  puts '<table>'
471
482
 
472
483
  begin
473
- table_header(id, caption) if caption.present?
484
+ if caption_top?('table') && caption.present?
485
+ table_header(id, caption)
486
+ end
487
+
488
+ if @tablewidth.nil?
489
+ print '<tbody>'
490
+ else
491
+ print %Q(<tbody xmlns:aid5="http://ns.adobe.com/AdobeInDesign/5.0/" aid:table="table" aid:trows="#{rows.length}" aid:tcols="#{@col}">)
492
+ end
493
+ @table_id = id
494
+ table_rows(sepidx, rows)
495
+ puts '</tbody>'
496
+
497
+ if !caption_top?('table') && caption.present?
498
+ table_header(id, caption)
499
+ end
474
500
  rescue KeyError
475
501
  error "no such table: #{id}"
476
502
  end
477
-
478
- if @tablewidth.nil?
479
- print '<tbody>'
480
- else
481
- print %Q(<tbody xmlns:aid5="http://ns.adobe.com/AdobeInDesign/5.0/" aid:table="table" aid:trows="#{rows.length}" aid:tcols="#{@col}">)
482
- end
483
- @table_id = id
484
- table_rows(sepidx, rows)
485
- puts '</tbody></table>'
503
+ puts '</table>'
486
504
  @tsize = nil
487
505
  end
488
506
 
@@ -596,8 +614,13 @@ module ReVIEW
596
614
  if @chapter.image_bound?(id)
597
615
  metrics = parse_metric('idgxml', metric)
598
616
  puts '<table>'
599
- table_header(id, caption) if caption.present?
617
+ if caption_top?('table') && caption.present?
618
+ table_header(id, caption)
619
+ end
600
620
  puts %Q(<imgtable><Image href="file://#{@chapter.image(id).path.sub(%r{\A./}, '')}"#{metrics} /></imgtable>)
621
+ if !caption_top?('table') && caption.present?
622
+ table_header(id, caption)
623
+ end
601
624
  puts '</table>'
602
625
  else
603
626
  warn "image not bound: #{id}" if @strict
@@ -1003,6 +1026,7 @@ module ReVIEW
1003
1026
  end
1004
1027
 
1005
1028
  def syntaxblock(type, lines, caption)
1029
+ captionstr = nil
1006
1030
  if caption.present?
1007
1031
  titleopentag = %Q(caption aid:pstyle="#{type}-title")
1008
1032
  titleclosetag = 'caption'
@@ -1010,9 +1034,13 @@ module ReVIEW
1010
1034
  titleopentag = %Q(floattitle type="insn")
1011
1035
  titleclosetag = 'floattitle'
1012
1036
  end
1013
- puts %Q(<#{type}><#{titleopentag}>#{compile_inline(caption)}</#{titleclosetag}>)
1037
+ captionstr = %Q(<#{titleopentag}>#{compile_inline(caption)}</#{titleclosetag}>)
1038
+ end
1039
+ print "<#{type}>"
1040
+ if caption_top?('list')
1041
+ puts captionstr
1014
1042
  else
1015
- puts "<#{type}>"
1043
+ puts ''
1016
1044
  end
1017
1045
 
1018
1046
  no = 1
@@ -1028,6 +1056,9 @@ module ReVIEW
1028
1056
  print '</listinfo>' if @book.config['listinfo']
1029
1057
  no += 1
1030
1058
  end
1059
+ unless caption_top?('list')
1060
+ print captionstr
1061
+ end
1031
1062
  puts "</#{type}>"
1032
1063
  end
1033
1064
 
@@ -1042,12 +1073,17 @@ module ReVIEW
1042
1073
  def indepimage(_lines, id, caption = nil, metric = nil)
1043
1074
  metrics = parse_metric('idgxml', metric)
1044
1075
  puts '<img>'
1076
+ if caption_top?('image')
1077
+ puts %Q(<caption>#{compile_inline(caption)}</caption>) if caption.present?
1078
+ end
1045
1079
  begin
1046
1080
  puts %Q(<Image href="file://#{@chapter.image(id).path.sub(%r{\A\./}, '')}"#{metrics} />)
1047
1081
  rescue
1048
1082
  warn %Q(image not bound: #{id})
1049
1083
  end
1050
- puts %Q(<caption>#{compile_inline(caption)}</caption>) if caption.present?
1084
+ unless caption_top?('image')
1085
+ puts %Q(<caption>#{compile_inline(caption)}</caption>) if caption.present?
1086
+ end
1051
1087
  puts '</img>'
1052
1088
  end
1053
1089
 
@@ -1148,8 +1184,13 @@ module ReVIEW
1148
1184
 
1149
1185
  def source(lines, caption = nil, lang = nil)
1150
1186
  puts '<source>'
1151
- source_header(caption)
1187
+ if caption_top?('list')
1188
+ source_header(caption)
1189
+ end
1152
1190
  source_body(lines, lang)
1191
+ unless caption_top?('list')
1192
+ source_header(caption)
1193
+ end
1153
1194
  puts '</source>'
1154
1195
  end
1155
1196
 
@@ -403,18 +403,19 @@ module ReVIEW
403
403
 
404
404
  def common_code_block(id, lines, command, caption, _lang)
405
405
  @doc_status[:caption] = true
406
+ captionstr = nil
406
407
  unless @book.config.check_version('2', exception: false)
407
408
  puts '\\begin{reviewlistblock}'
408
409
  end
409
410
  if caption.present?
410
411
  if command =~ /emlist/ || command =~ /cmd/ || command =~ /source/
411
- puts macro(command + 'caption', compile_inline(caption))
412
+ captionstr = macro(command + 'caption', compile_inline(caption))
412
413
  else
413
414
  begin
414
415
  if get_chap.nil?
415
- puts macro('reviewlistcaption', "#{I18n.t('list')}#{I18n.t('format_number_header_without_chapter', [@chapter.list(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}")
416
+ captionstr = macro('reviewlistcaption', "#{I18n.t('list')}#{I18n.t('format_number_header_without_chapter', [@chapter.list(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}")
416
417
  else
417
- puts macro('reviewlistcaption', "#{I18n.t('list')}#{I18n.t('format_number_header', [get_chap, @chapter.list(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}")
418
+ captionstr = macro('reviewlistcaption', "#{I18n.t('list')}#{I18n.t('format_number_header', [get_chap, @chapter.list(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}")
418
419
  end
419
420
  rescue KeyError
420
421
  error "no such list: #{id}"
@@ -422,6 +423,11 @@ module ReVIEW
422
423
  end
423
424
  end
424
425
  @doc_status[:caption] = nil
426
+
427
+ if caption_top?('list') && captionstr
428
+ puts captionstr
429
+ end
430
+
425
431
  body = ''
426
432
  lines.each_with_index do |line, idx|
427
433
  body.concat(yield(line, idx))
@@ -429,6 +435,11 @@ module ReVIEW
429
435
  puts macro('begin', command)
430
436
  print body
431
437
  puts macro('end', command)
438
+
439
+ if !caption_top?('list') && captionstr
440
+ puts captionstr
441
+ end
442
+
432
443
  unless @book.config.check_version('2', exception: false)
433
444
  puts '\\end{reviewlistblock}'
434
445
  end
@@ -501,10 +512,24 @@ module ReVIEW
501
512
  end
502
513
 
503
514
  def image_image(id, caption, metric)
515
+ captionstr = nil
516
+ @doc_status[:caption] = true
517
+ if @book.config.check_version('2', exception: false)
518
+ captionstr = macro('caption', compile_inline(caption)) + "\n" if caption.present?
519
+ else
520
+ captionstr = macro('reviewimagecaption', compile_inline(caption)) + "\n" if caption.present?
521
+ end
522
+ captionstr << macro('label', image_label(id))
523
+ @doc_status[:caption] = nil
524
+
504
525
  metrics = parse_metric('latex', metric)
505
526
  # image is always bound here
506
527
  puts "\\begin{reviewimage}%%#{id}"
507
528
 
529
+ if caption_top?('image') && captionstr
530
+ puts captionstr
531
+ end
532
+
508
533
  command = 'reviewincludegraphics'
509
534
  if @book.config.check_version('2', exception: false)
510
535
  command = 'includegraphics'
@@ -515,15 +540,11 @@ module ReVIEW
515
540
  else
516
541
  puts "\\#{command}[width=\\maxwidth]{#{@chapter.image(id).path}}"
517
542
  end
518
- @doc_status[:caption] = true
519
543
 
520
- if @book.config.check_version('2', exception: false)
521
- puts macro('caption', compile_inline(caption)) if caption.present?
522
- else
523
- puts macro('reviewimagecaption', compile_inline(caption)) if caption.present?
544
+ if !caption_top?('image') && captionstr
545
+ puts captionstr
524
546
  end
525
- @doc_status[:caption] = nil
526
- puts macro('label', image_label(id))
547
+
527
548
  puts '\end{reviewimage}'
528
549
  end
529
550
 
@@ -588,9 +609,21 @@ module ReVIEW
588
609
  def indepimage(lines, id, caption = nil, metric = nil)
589
610
  metrics = parse_metric('latex', metric)
590
611
 
612
+ captionstr = nil
613
+ if caption.present?
614
+ @doc_status[:caption] = true
615
+ captionstr = macro('reviewindepimagecaption',
616
+ %Q(#{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)}))
617
+ @doc_status[:caption] = nil
618
+ end
619
+
591
620
  if @chapter.image(id).path
592
621
  puts "\\begin{reviewimage}%%#{id}"
593
622
 
623
+ if caption_top?('image') && captionstr
624
+ puts captionstr
625
+ end
626
+
594
627
  command = 'reviewincludegraphics'
595
628
  if @book.config.check_version('2', exception: false)
596
629
  command = 'includegraphics'
@@ -610,12 +643,9 @@ module ReVIEW
610
643
  end
611
644
  end
612
645
 
613
- @doc_status[:caption] = true
614
- if caption.present?
615
- puts macro('reviewindepimagecaption',
616
- %Q(#{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)}))
646
+ if !caption_top?('image') && captionstr
647
+ puts captionstr
617
648
  end
618
- @doc_status[:caption] = nil
619
649
 
620
650
  if @chapter.image(id).path
621
651
  puts '\end{reviewimage}'
@@ -637,7 +667,9 @@ module ReVIEW
637
667
 
638
668
  sepidx, rows = parse_table_rows(lines)
639
669
  begin
640
- table_header(id, caption) if caption.present?
670
+ if caption_top?('table') && caption.present?
671
+ table_header(id, caption)
672
+ end
641
673
  rescue KeyError
642
674
  error "no such table: #{id}"
643
675
  end
@@ -645,6 +677,9 @@ module ReVIEW
645
677
  table_rows(sepidx, rows)
646
678
  table_end
647
679
  if caption.present?
680
+ unless caption_top?('table')
681
+ table_header(id, caption)
682
+ end
648
683
  puts '\end{table}'
649
684
  end
650
685
  blank
@@ -807,12 +842,16 @@ module ReVIEW
807
842
  return
808
843
  end
809
844
 
845
+ captionstr = nil
810
846
  begin
811
847
  if caption.present?
812
848
  puts "\\begin{table}[h]%%#{id}"
813
849
  @doc_status[:caption] = true
814
- puts macro('reviewimgtablecaption', compile_inline(caption))
850
+ captionstr = macro('reviewimgtablecaption', compile_inline(caption))
815
851
  @doc_status[:caption] = nil
852
+ if caption_top?('table')
853
+ puts captionstr
854
+ end
816
855
  end
817
856
  puts macro('label', table_label(id))
818
857
  rescue ReVIEW::KeyError
@@ -821,6 +860,9 @@ module ReVIEW
821
860
  imgtable_image(id, caption, metric)
822
861
 
823
862
  if caption.present?
863
+ unless caption_top?('table')
864
+ puts captionstr
865
+ end
824
866
  puts '\end{table}'
825
867
  end
826
868
  blank
@@ -860,22 +902,31 @@ module ReVIEW
860
902
 
861
903
  def texequation(lines, id = nil, caption = '')
862
904
  blank
905
+ captionstr = nil
863
906
 
864
907
  if id
865
908
  puts macro('begin', 'reviewequationblock')
866
909
  if get_chap.nil?
867
- puts macro('reviewequationcaption', "#{I18n.t('equation')}#{I18n.t('format_number_header_without_chapter', [@chapter.equation(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}")
910
+ captionstr = macro('reviewequationcaption', "#{I18n.t('equation')}#{I18n.t('format_number_header_without_chapter', [@chapter.equation(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}")
868
911
  else
869
- puts macro('reviewequationcaption', "#{I18n.t('equation')}#{I18n.t('format_number_header', [get_chap, @chapter.equation(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}")
912
+ captionstr = macro('reviewequationcaption', "#{I18n.t('equation')}#{I18n.t('format_number_header', [get_chap, @chapter.equation(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}")
870
913
  end
871
914
  end
872
915
 
916
+ if caption_top?('equation') && captionstr
917
+ puts captionstr
918
+ end
919
+
873
920
  puts macro('begin', 'equation*')
874
921
  lines.each do |line|
875
922
  puts line
876
923
  end
877
924
  puts macro('end', 'equation*')
878
925
 
926
+ if !caption_top?('equation') && captionstr
927
+ puts captionstr
928
+ end
929
+
879
930
  if id
880
931
  puts macro('end', 'reviewequationblock')
881
932
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2012-2018 Yuto HAYAMIZU, Kenshi Muto
1
+ # Copyright (c) 2012-2020 Yuto HAYAMIZU, Kenshi Muto
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -112,6 +112,22 @@ module ReVIEW
112
112
  \\end{document}
113
113
  EOB
114
114
 
115
+ hashes = File.readlines(File.join(math_dir, '__IMGMATH_BODY__.map')).sort.uniq
116
+ File.write(File.join(math_dir, '__IMGMATH_BODY__.map'), hashes.join)
117
+
118
+ File.open(File.join(math_dir, '__IMGMATH_BODY__.tex'), 'w') do |f|
119
+ File.open(File.join(math_dir, '__IMGMATH_BODY__.map')) do |map|
120
+ map.each_line do |l|
121
+ l.chomp!
122
+ f.puts "% #{l}"
123
+ f.puts File.read(File.join(math_dir, "__IMGMATH_BODY__#{l}.tex"))
124
+ File.unlink(File.join(math_dir, "__IMGMATH_BODY__#{l}.tex"))
125
+ f.puts '\\clearpage'
126
+ f.puts
127
+ end
128
+ end
129
+ end
130
+
115
131
  math_dir = File.realpath(math_dir)
116
132
  Dir.mktmpdir do |tmpdir|
117
133
  FileUtils.cp([File.join(math_dir, '__IMGMATH_BODY__.tex'),
@@ -139,6 +155,7 @@ EOB
139
155
  FileUtils.rm_f([File.join(math_dir, '__IMGMATH_BODY__.tex'),
140
156
  File.join(math_dir, '__IMGMATH_BODY__.map')])
141
157
  end
158
+ module_function :make_math_images
142
159
 
143
160
  def make_math_images_pdfcrop(dir, tex_path, math_dir)
144
161
  # rubocop:disable Metrics/BlockLength
@@ -474,7 +474,14 @@ module ReVIEW
474
474
  end
475
475
 
476
476
  def latex_config
477
- erb_content(File.expand_path('./latex/config.erb', ReVIEW::Template::TEMPLATE_DIR))
477
+ result = erb_content(File.expand_path('./latex/config.erb', ReVIEW::Template::TEMPLATE_DIR))
478
+ local_config_file = File.join(@basedir, 'layouts', 'config-local.tex.erb')
479
+ if File.exist?(local_config_file)
480
+ result << "%% BEGIN: config-local.tex.erb\n"
481
+ result << erb_content(local_config_file)
482
+ result << "%% END: config-local.tex.erb\n"
483
+ end
484
+ result
478
485
  end
479
486
 
480
487
  def template_content