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
@@ -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