review 5.2.0 → 5.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-tex.yml +1 -1
  3. data/.github/workflows/ruby-win.yml +1 -1
  4. data/.github/workflows/ruby.yml +1 -1
  5. data/.rubocop.yml +1 -319
  6. data/NEWS.ja.md +116 -0
  7. data/NEWS.md +117 -0
  8. data/README.md +9 -8
  9. data/bin/review +1 -1
  10. data/bin/review-catalog-converter +15 -15
  11. data/bin/review-check +7 -7
  12. data/bin/review-compile +6 -8
  13. data/bin/review-index +1 -1
  14. data/bin/review-preproc +1 -1
  15. data/bin/review-validate +2 -2
  16. data/doc/config.yml.sample +7 -1
  17. data/doc/config.yml.sample-simple +1 -1
  18. data/doc/format.ja.md +34 -4
  19. data/doc/format.md +32 -3
  20. data/lib/review/book/base.rb +3 -3
  21. data/lib/review/book/book_unit.rb +13 -3
  22. data/lib/review/book/chapter.rb +1 -1
  23. data/lib/review/book/index.rb +7 -4
  24. data/lib/review/book/part.rb +12 -13
  25. data/lib/review/book/volume.rb +1 -1
  26. data/lib/review/builder.rb +82 -28
  27. data/lib/review/catalog.rb +6 -5
  28. data/lib/review/compiler.rb +20 -14
  29. data/lib/review/configure.rb +5 -2
  30. data/lib/review/epub2html.rb +12 -12
  31. data/lib/review/epubmaker/content.rb +1 -1
  32. data/lib/review/epubmaker/epubcommon.rb +47 -45
  33. data/lib/review/epubmaker/epubv2.rb +2 -1
  34. data/lib/review/epubmaker/epubv3.rb +5 -4
  35. data/lib/review/epubmaker/producer.rb +3 -3
  36. data/lib/review/epubmaker/reviewheaderlistener.rb +1 -1
  37. data/lib/review/epubmaker.rb +35 -32
  38. data/lib/review/extentions/string.rb +1 -1
  39. data/lib/review/htmlbuilder.rb +65 -15
  40. data/lib/review/htmlutils.rb +17 -17
  41. data/lib/review/i18n.rb +3 -3
  42. data/lib/review/i18n.yml +6 -0
  43. data/lib/review/idgxmlbuilder.rb +42 -21
  44. data/lib/review/idgxmlmaker.rb +15 -13
  45. data/lib/review/img_math.rb +1 -0
  46. data/lib/review/index_builder.rb +100 -38
  47. data/lib/review/init.rb +4 -4
  48. data/lib/review/latexbuilder.rb +69 -34
  49. data/lib/review/lineinput.rb +3 -3
  50. data/lib/review/location.rb +1 -1
  51. data/lib/review/logger.rb +21 -21
  52. data/lib/review/makerhelper.rb +3 -3
  53. data/lib/review/markdownbuilder.rb +16 -8
  54. data/lib/review/pdfmaker.rb +40 -21
  55. data/lib/review/plaintextbuilder.rb +8 -7
  56. data/lib/review/preprocessor/repository.rb +1 -1
  57. data/lib/review/preprocessor.rb +5 -5
  58. data/lib/review/rstbuilder.rb +11 -2
  59. data/lib/review/textmaker.rb +20 -18
  60. data/lib/review/textutils.rb +5 -6
  61. data/lib/review/tocprinter.rb +11 -6
  62. data/lib/review/topbuilder.rb +89 -12
  63. data/lib/review/update.rb +16 -8
  64. data/lib/review/version.rb +1 -1
  65. data/lib/review/volumeprinter.rb +9 -9
  66. data/lib/review/webmaker.rb +32 -32
  67. data/lib/review/webtocprinter.rb +10 -10
  68. data/lib/review/yamlloader.rb +36 -2
  69. data/review.gemspec +2 -0
  70. data/samples/sample-book/src/config.yml +0 -1
  71. data/samples/syntax-book/ch02.re +16 -1
  72. data/templates/html/_titlepage.html.erb +9 -17
  73. data/templates/latex/config.erb +3 -0
  74. data/templates/latex/review-jlreq/review-base.sty +2 -1
  75. data/templates/latex/review-jlreq/review-jlreq.cls +36 -3
  76. data/templates/latex/review-jsbook/review-base.sty +7 -1
  77. data/templates/latex/review-jsbook/review-jsbook.cls +31 -4
  78. data/templates/opf/opf_manifest_epubv2.opf.erb +1 -1
  79. data/templates/opf/opf_manifest_epubv3.opf.erb +1 -1
  80. data/test/assets/syntax_book_index_detail.txt +10 -8
  81. data/test/assets/test_template.tex +4 -1
  82. data/test/assets/test_template_backmatter.tex +4 -1
  83. data/test/book_test_helper.rb +10 -10
  84. data/test/test_book_chapter.rb +25 -2
  85. data/test/test_builder.rb +5 -3
  86. data/test/test_epub3maker.rb +3 -3
  87. data/test/test_epubmaker.rb +14 -29
  88. data/test/test_epubmaker_cmd.rb +2 -2
  89. data/test/test_htmlbuilder.rb +80 -8
  90. data/test/test_idgxmlbuilder.rb +13 -13
  91. data/test/test_idgxmlmaker_cmd.rb +1 -1
  92. data/test/test_img_math.rb +11 -2
  93. data/test/test_index.rb +30 -4
  94. data/test/test_latexbuilder.rb +53 -6
  95. data/test/test_markdownbuilder.rb +45 -0
  96. data/test/test_pdfmaker.rb +19 -0
  97. data/test/test_pdfmaker_cmd.rb +10 -10
  98. data/test/test_plaintextbuilder.rb +45 -4
  99. data/test/test_rstbuilder.rb +13 -0
  100. data/test/test_textmaker_cmd.rb +1 -1
  101. data/test/test_topbuilder.rb +169 -11
  102. data/test/test_yamlloader.rb +28 -42
  103. metadata +19 -4
data/lib/review/logger.rb CHANGED
@@ -76,27 +76,27 @@ module ReVIEW
76
76
  end
77
77
 
78
78
  def self.logger(level: 'info')
79
- if const_defined?(:TTYLogger)
80
- @logger ||= TTYLogger.new do |config|
81
- config.level = level.to_sym
82
- config.handlers = [
83
- [:console,
84
- {
85
- styles: {
86
- debug: { label: 'DEBUG' },
87
- info: { label: 'INFO', color: :magenta },
88
- success: { label: 'SUCCESS' },
89
- wait: { label: 'WAIT' },
90
- warn: { label: 'WARN' },
91
- error: { label: 'ERROR' },
92
- fatal: { label: 'FATAL' }
93
- }
94
- }]
95
- ]
96
- end
97
- else
98
- @logger ||= ReVIEW::Logger.new($stderr, progname: File.basename($PROGRAM_NAME, '.*'))
99
- end
79
+ @logger ||= if const_defined?(:TTYLogger)
80
+ TTYLogger.new do |config|
81
+ config.level = level.to_sym
82
+ config.handlers = [
83
+ [:console,
84
+ {
85
+ styles: {
86
+ debug: { label: 'DEBUG' },
87
+ info: { label: 'INFO', color: :magenta },
88
+ success: { label: 'SUCCESS' },
89
+ wait: { label: 'WAIT' },
90
+ warn: { label: 'WARN' },
91
+ error: { label: 'ERROR' },
92
+ fatal: { label: 'FATAL' }
93
+ }
94
+ }]
95
+ ]
96
+ end
97
+ else
98
+ ReVIEW::Logger.new($stderr, progname: File.basename($PROGRAM_NAME, '.*'))
99
+ end
100
100
  end
101
101
 
102
102
  def self.logger=(logger)
@@ -11,7 +11,7 @@ require 'yaml'
11
11
 
12
12
  begin
13
13
  require 'cgi/escape'
14
- rescue
14
+ rescue StandardError
15
15
  require 'cgi/util'
16
16
  end
17
17
 
@@ -43,7 +43,7 @@ module ReVIEW
43
43
 
44
44
  Dir.open(from_dir) do |dir|
45
45
  dir.each do |fname|
46
- next if fname =~ /^\./
46
+ next if /^\./.match?(fname)
47
47
 
48
48
  if FileTest.directory?("#{from_dir}/#{fname}")
49
49
  image_files += copy_images_to_dir("#{from_dir}/#{fname}", "#{to_dir}/#{fname}", options)
@@ -52,7 +52,7 @@ module ReVIEW
52
52
 
53
53
  is_converted = false
54
54
  (options[:convert] || {}).each do |orig_type, conv_type|
55
- next unless /\.#{orig_type}$/ =~ fname
55
+ next unless /\.#{orig_type}$/.match?(fname)
56
56
 
57
57
  is_converted = system("convert #{from_dir}/#{fname} #{to_dir}/#{fname}.#{conv_type}")
58
58
  image_files << "#{from_dir}/#{fname}.#{conv_type}"
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2013-2020 KADO Masanori, Masayoshi Takahashi, Kenshi Muto
1
+ # Copyright (c) 2013-2021 KADO Masanori, Masayoshi Takahashi, Kenshi Muto
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -98,7 +98,7 @@ module ReVIEW
98
98
  end
99
99
 
100
100
  def ul_item_begin(lines)
101
- puts ' ' * (@ul_indent - 1) + '* ' + join_lines_to_paragraph(lines)
101
+ puts (' ' * (@ul_indent - 1)) + '* ' + join_lines_to_paragraph(lines)
102
102
  end
103
103
 
104
104
  def ul_item_end
@@ -255,11 +255,11 @@ module ReVIEW
255
255
 
256
256
  def inline_hd_chap(chap, id)
257
257
  n = chap.headline_index.number(id)
258
- if n.present? && chap.number && over_secnolevel?(n)
259
- str = I18n.t('hd_quote', [n, compile_inline(chap.headline(id).caption)])
260
- else
261
- str = I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
262
- end
258
+ str = if n.present? && chap.number && over_secnolevel?(n)
259
+ I18n.t('hd_quote', [n, compile_inline(chap.headline(id).caption)])
260
+ else
261
+ I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
262
+ end
263
263
  if @book.config['chapterlink']
264
264
  if @chapter == chap
265
265
  anchor = 'h' + n.tr('.', '-')
@@ -361,6 +361,14 @@ module ReVIEW
361
361
  "[^#{id}]"
362
362
  end
363
363
 
364
+ def inline_endnote(id)
365
+ "<sup>#{I18n.t('html_endnote_refmark', @chapter.endnote(id).number)}</sup>"
366
+ end
367
+
368
+ def endnote_item(id)
369
+ puts "#{I18n.t('html_endnote_textmark', @chapter.endnote(id).number)}#{compile_inline(@chapter.endnote(id).content)}"
370
+ end
371
+
364
372
  def inline_br(_str)
365
373
  "\n"
366
374
  end
@@ -401,7 +409,7 @@ module ReVIEW
401
409
  def inline_icon(id)
402
410
  begin
403
411
  "![](#{@chapter.image(id).path.sub(%r{\A\./}, '')})"
404
- rescue
412
+ rescue StandardError
405
413
  warn "image not bound: #{id}", location: location
406
414
  %Q(<pre>missing image: #{id}</pre>)
407
415
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2010-2021 Kenshi Muto and Masayoshi Takahashi
1
+ # Copyright (c) 2010-2022 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
@@ -121,9 +121,13 @@ module ReVIEW
121
121
  cmd_config, yamlfile = parse_opts(args)
122
122
  error! "#{yamlfile} not found." unless File.exist?(yamlfile)
123
123
 
124
- @config = ReVIEW::Configure.create(maker: 'pdfmaker',
125
- yamlfile: yamlfile,
126
- config: cmd_config)
124
+ begin
125
+ @config = ReVIEW::Configure.create(maker: 'pdfmaker',
126
+ yamlfile: yamlfile,
127
+ config: cmd_config)
128
+ rescue ReVIEW::ConfigError => e
129
+ error! e.message
130
+ end
127
131
 
128
132
  I18n.setup(@config['language'])
129
133
  @basedir = File.absolute_path(File.dirname(yamlfile))
@@ -136,11 +140,11 @@ module ReVIEW
136
140
 
137
141
  # version 2 compatibility
138
142
  unless @config['texdocumentclass']
139
- if @config.check_version(2, exception: false)
140
- @config['texdocumentclass'] = ['jsbook', 'uplatex,oneside']
141
- else
142
- @config['texdocumentclass'] = @config['_texdocumentclass']
143
- end
143
+ @config['texdocumentclass'] = if @config.check_version(2, exception: false)
144
+ ['jsbook', 'uplatex,oneside']
145
+ else
146
+ @config['_texdocumentclass']
147
+ end
144
148
  end
145
149
 
146
150
  begin
@@ -193,7 +197,7 @@ module ReVIEW
193
197
  def build_pdf
194
198
  template = template_content
195
199
  Dir.chdir(@path) do
196
- File.open("./#{@mastertex}.tex", 'wb') { |f| f.write template }
200
+ File.write("./#{@mastertex}.tex", template)
197
201
 
198
202
  call_hook('hook_beforetexcompile', Dir.pwd, @basedir, base_dir: @basedir)
199
203
 
@@ -297,7 +301,7 @@ module ReVIEW
297
301
  @logger.info "compiling #{filename}.tex"
298
302
  begin
299
303
  @converter.convert(filename + '.re', File.join(@path, filename + '.tex'))
300
- rescue => e
304
+ rescue StandardError => e
301
305
  @compile_errors = true
302
306
  error "compile error in #{filename}.tex (#{e.class})"
303
307
  error e.message
@@ -318,12 +322,16 @@ module ReVIEW
318
322
  end
319
323
 
320
324
  def make_custom_page(file)
325
+ if file.nil?
326
+ return nil
327
+ end
328
+
321
329
  file_sty = file.to_s.sub(/\.[^.]+\Z/, '.tex')
322
330
  if File.exist?(file_sty)
323
- return File.read(file_sty)
331
+ File.read(file_sty)
332
+ else
333
+ warn "File #{file_sty} is not found."
324
334
  end
325
-
326
- nil
327
335
  end
328
336
 
329
337
  def join_with_separator(value, sep)
@@ -373,9 +381,9 @@ module ReVIEW
373
381
  items.each_with_index do |item, rev|
374
382
  editstr = edit == 0 ? ReVIEW::I18n.t('first_edition') : ReVIEW::I18n.t('nth_edition', (edit + 1).to_s)
375
383
  revstr = ReVIEW::I18n.t('nth_impression', (rev + 1).to_s)
376
- if item =~ /\A\d+-\d+-\d+\Z/
384
+ if /\A\d+-\d+-\d+\Z/.match?(item)
377
385
  buf << ReVIEW::I18n.t('published_by1', [date_to_s(item), editstr + revstr])
378
- elsif item =~ /\A(\d+-\d+-\d+)[\s ](.+)/
386
+ elsif /\A(\d+-\d+-\d+)[\s ](.+)/.match?(item)
379
387
  # custom date with string
380
388
  item.match(/\A(\d+-\d+-\d+)[\s ](.+)/) { |m| buf << ReVIEW::I18n.t('published_by3', [date_to_s(m[1]), m[2]]) }
381
389
  else
@@ -442,6 +450,10 @@ module ReVIEW
442
450
  end
443
451
  end
444
452
 
453
+ if @config['coverimage'] && !File.exist?(File.join(@config['imagedir'], @config['coverimage']))
454
+ raise ReVIEW::ConfigError, "coverimage #{@config['coverimage']} is not found."
455
+ end
456
+
445
457
  @locale_latex = {}
446
458
  part_tuple = I18n.get('part').split(/%[A-Za-z]{1,3}/, 2)
447
459
  chapter_tuple = I18n.get('chapter').split(/%[A-Za-z]{1,3}/, 2)
@@ -475,17 +487,24 @@ module ReVIEW
475
487
 
476
488
  def template_content
477
489
  template_dir = ReVIEW::Template::TEMPLATE_DIR
478
- if @config.check_version('2', exception: false)
479
- template_path = './latex-compat2/layout.tex.erb'
480
- else
481
- template_path = './latex/layout.tex.erb'
482
- end
490
+ template_path = if @config.check_version('2', exception: false)
491
+ './latex-compat2/layout.tex.erb'
492
+ else
493
+ './latex/layout.tex.erb'
494
+ end
483
495
  layout_file = File.join(@basedir, 'layouts', 'layout.tex.erb')
484
496
  if File.exist?(layout_file)
485
497
  template_dir = @basedir
486
498
  template_path = 'layouts/layout.tex.erb'
487
499
  end
488
500
  ReVIEW::Template.generate(path: template_path, mode: '-', binding: binding, template_dir: template_dir)
501
+ rescue StandardError => e
502
+ if defined?(e.full_message)
503
+ error! "template or configuration error: #{e.full_message(highlight: false)}"
504
+ else
505
+ # <= Ruby 2.4
506
+ error! "template or configuration error: #{e.message}"
507
+ end
489
508
  end
490
509
 
491
510
  def copy_sty(dirname, copybase, extname = 'sty')
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2018-2020 Kenshi Muto
1
+ # Copyright (c) 2018-2022 Kenshi Muto
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -74,6 +74,7 @@ module ReVIEW
74
74
  private :blank
75
75
 
76
76
  def result
77
+ check_printendnotes
77
78
  solve_nest(@output.string)
78
79
  end
79
80
 
@@ -85,11 +86,11 @@ module ReVIEW
85
86
  if l =~ /\A\x01→(dl|ul|ol)←\x01/
86
87
  clevel.push($1)
87
88
  lines.push("\x01→END←\x01")
88
- elsif l =~ %r{\A\x01→/(dl|ul|ol)←\x01}
89
+ elsif %r{\A\x01→/(dl|ul|ol)←\x01}.match?(l)
89
90
  clevel.pop
90
91
  lines.push("\x01→END←\x01")
91
92
  else
92
- lines.push("\t" * clevel.size + l)
93
+ lines.push(("\t" * clevel.size) + l)
93
94
  end
94
95
  end
95
96
 
@@ -213,14 +214,14 @@ module ReVIEW
213
214
 
214
215
  def emlistnum(lines, caption = nil, _lang = nil)
215
216
  blank
216
- if caption_top?('list')
217
- puts compile_inline(caption) if caption.present?
217
+ if caption_top?('list') && caption.present?
218
+ puts compile_inline(caption)
218
219
  end
219
220
  lines.each_with_index do |line, i|
220
221
  puts((i + 1).to_s.rjust(2) + ": #{line}")
221
222
  end
222
- unless caption_top?('list')
223
- puts compile_inline(caption) if caption.present?
223
+ if !caption_top?('list') && caption.present?
224
+ puts compile_inline(caption)
224
225
  end
225
226
  blank
226
227
  end
@@ -165,7 +165,7 @@ module ReVIEW
165
165
  end
166
166
 
167
167
  def check_spec(spec)
168
- app_error "wrong spec: #{spec.inspect}" unless /\A\w+\z/ =~ spec
168
+ app_error "wrong spec: #{spec.inspect}" unless /\A\w+\z/.match?(spec)
169
169
  spec
170
170
  end
171
171
 
@@ -70,11 +70,11 @@ module ReVIEW
70
70
  direc = parse_directive(line, 1, 'eval')
71
71
  path = expand(direc.arg)
72
72
  @leave_content = File.extname(path) == '.re'
73
- if direc['eval']
74
- ent = evaluate(path, ent)
75
- else
76
- ent = @repository.fetch_file(path)
77
- end
73
+ ent = if direc['eval']
74
+ evaluate(path, ent)
75
+ else
76
+ @repository.fetch_file(path)
77
+ end
78
78
  replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp
79
79
 
80
80
  when /\A\#@map(?:range)?/
@@ -86,6 +86,7 @@ module ReVIEW
86
86
  private :blank
87
87
 
88
88
  def result
89
+ check_printendnotes
89
90
  solve_nest(@output.string)
90
91
  end
91
92
 
@@ -124,7 +125,7 @@ module ReVIEW
124
125
  end
125
126
 
126
127
  def ul_item(lines)
127
- puts ' ' * (@ul_indent - 1) + "* #{join_lines_to_paragraph(lines)}"
128
+ puts (' ' * (@ul_indent - 1)) + "* #{join_lines_to_paragraph(lines)}"
128
129
  end
129
130
 
130
131
  def ul_end
@@ -138,7 +139,7 @@ module ReVIEW
138
139
  end
139
140
 
140
141
  def ol_item(lines, _num)
141
- puts ' ' * (@ol_indent - 1) + "#. #{join_lines_to_paragraph(lines)}"
142
+ puts (' ' * (@ol_indent - 1)) + "#. #{join_lines_to_paragraph(lines)}"
142
143
  end
143
144
 
144
145
  def ol_end
@@ -367,6 +368,14 @@ module ReVIEW
367
368
  " [##{id.sub(' ', '_')}]_ "
368
369
  end
369
370
 
371
+ def inline_endnote(id)
372
+ " [(#{@chapter.endnote(id).number})]_ "
373
+ end
374
+
375
+ def endnote_item(id)
376
+ puts ".. [(#{@chapter.endnote(id).number})] #{compile_inline(@chapter.endnote(id).content)}"
377
+ end
378
+
370
379
  def compile_ruby(base, ruby)
371
380
  " :ruby:`#{base}`<#{ruby}>`_ "
372
381
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2018-2021 Kenshi Muto
1
+ # Copyright (c) 2018-2022 Kenshi Muto
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -74,9 +74,14 @@ module ReVIEW
74
74
  cmd_config, yamlfile = parse_opts(args)
75
75
  error! "#{yamlfile} not found." unless File.exist?(yamlfile)
76
76
 
77
- @config = ReVIEW::Configure.create(maker: 'textmaker',
78
- yamlfile: yamlfile,
79
- config: cmd_config)
77
+ begin
78
+ @config = ReVIEW::Configure.create(maker: 'textmaker',
79
+ yamlfile: yamlfile,
80
+ config: cmd_config)
81
+ rescue ReVIEW::ConfigError => e
82
+ error! e.message
83
+ end
84
+
80
85
  @img_math = ReVIEW::ImgMath.new(@config, path_name: '_review_math_text')
81
86
 
82
87
  I18n.setup(@config['language'])
@@ -111,12 +116,11 @@ module ReVIEW
111
116
 
112
117
  def build_body(basetmpdir, _yamlfile)
113
118
  base_path = Pathname.new(@basedir)
114
- builder = nil
115
- if @plaintext
116
- builder = ReVIEW::PLAINTEXTBuilder.new(img_math: @img_math)
117
- else
118
- builder = ReVIEW::TOPBuilder.new(img_math: @img_math)
119
- end
119
+ builder = if @plaintext
120
+ ReVIEW::PLAINTEXTBuilder.new(img_math: @img_math)
121
+ else
122
+ ReVIEW::TOPBuilder.new(img_math: @img_math)
123
+ end
120
124
  @converter = ReVIEW::Converter.new(@book, builder)
121
125
  @book.parts.each do |part|
122
126
  if part.name.present?
@@ -142,13 +146,11 @@ module ReVIEW
142
146
  end
143
147
 
144
148
  def build_chap(chap, base_path, basetmpdir, ispart)
145
- filename = ''
146
-
147
- if ispart.present?
148
- filename = chap.path
149
- else
150
- filename = Pathname.new(chap.path).relative_path_from(base_path).to_s
151
- end
149
+ filename = if ispart.present?
150
+ chap.path
151
+ else
152
+ Pathname.new(chap.path).relative_path_from(base_path).to_s
153
+ end
152
154
  id = File.basename(filename).sub(/\.re\Z/, '')
153
155
  if @buildonly && !@buildonly.include?(id)
154
156
  warn "skip #{id}.re"
@@ -159,7 +161,7 @@ module ReVIEW
159
161
 
160
162
  begin
161
163
  @converter.convert(filename, File.join(basetmpdir, textfile))
162
- rescue => e
164
+ rescue StandardError => e
163
165
  @compile_errors = true
164
166
  error "compile error in #{filename} (#{e.class})"
165
167
  error e.message
@@ -15,7 +15,7 @@ module ReVIEW
15
15
  add = 0
16
16
  len = nil
17
17
  str.gsub("\t") do
18
- len = ts - ($`.size + add) % ts
18
+ len = ts - (($`.size + add) % ts)
19
19
  add += len - 1
20
20
  ' ' * len
21
21
  end
@@ -72,11 +72,10 @@ module ReVIEW
72
72
  end
73
73
 
74
74
  # lazy than rule 3, but it looks better
75
- if lazy &&
76
- (%i[F W H].include?(Unicode::Eaw.property(tail)) &&
77
- tail !~ /\p{Hangul}/) ||
78
- (%i[F W H].include?(Unicode::Eaw.property(head)) &&
79
- head !~ /\p{Hangul}/)
75
+ if lazy && ((%i[F W H].include?(Unicode::Eaw.property(tail)) &&
76
+ tail !~ /\p{Hangul}/) ||
77
+ (%i[F W H].include?(Unicode::Eaw.property(head)) &&
78
+ head !~ /\p{Hangul}/))
80
79
  space = nil
81
80
  end
82
81
  end
@@ -69,12 +69,17 @@ module ReVIEW
69
69
 
70
70
  def execute(*args)
71
71
  parse_options(args)
72
- @config = ReVIEW::Configure.create(yamlfile: @yamlfile)
73
- @book = ReVIEW::Book::Base.new('.', config: @config)
74
- unless File.readable?(@yamlfile)
75
- @logger.error("No such fiile or can't open #{@yamlfile}.")
72
+ begin
73
+ @config = ReVIEW::Configure.create(yamlfile: @yamlfile)
74
+ @book = ReVIEW::Book::Base.new('.', config: @config)
75
+ unless File.readable?(@yamlfile)
76
+ raise ReVIEW::FileNotFound, "No such fiile or can't open #{@yamlfile}."
77
+ end
78
+ rescue ReVIEW::ConfigError, ReVIEW::FileNotFound, ReVIEW::CompileError, ReVIEW::ApplicationError => e
79
+ @logger.error e.message
76
80
  exit 1
77
81
  end
82
+
78
83
  I18n.setup(@config['language'])
79
84
 
80
85
  if @detail
@@ -226,9 +231,9 @@ module ReVIEW
226
231
 
227
232
  case mode
228
233
  when :list
229
- (calc_linesize(line) - 1) / @book.page_metric.list.n_columns + 1
234
+ ((calc_linesize(line) - 1) / @book.page_metric.list.n_columns) + 1
230
235
  else # mode == :text
231
- (calc_linesize(line) - 1) / @book.page_metric.text.n_columns + 1
236
+ ((calc_linesize(line) - 1) / @book.page_metric.text.n_columns) + 1
232
237
  end
233
238
  end
234
239
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2008-2020 Minero Aoki, Kenshi Muto
1
+ # Copyright (c) 2008-2022 Minero Aoki, Kenshi Muto
2
2
  # 2002-2006 Minero Aoki
3
3
  #
4
4
  # This program is free software.
@@ -262,13 +262,61 @@ module ReVIEW
262
262
  blank
263
263
  end
264
264
 
265
+ def table_rows(sepidx, rows)
266
+ if sepidx
267
+ sepidx.times do
268
+ tr(rows.shift.map { |s| th(s) })
269
+ end
270
+ if !@book.config['textmaker'] || !@book.config['textmaker']['th_bold']
271
+ puts '-' * 12
272
+ end
273
+ rows.each do |cols|
274
+ tr(cols.map { |s| td(s) })
275
+ end
276
+ else
277
+ rows.each do |cols|
278
+ h, *cs = *cols
279
+ tr([th(h)] + cs.map { |s| td(s) })
280
+ end
281
+ end
282
+ end
283
+
265
284
  def th(str)
266
- "★#{str}☆"
285
+ if @book.config['textmaker'] && @book.config['textmaker']['th_bold']
286
+ "★#{str}☆"
287
+ else
288
+ str
289
+ end
267
290
  end
268
291
 
269
292
  def table_end
270
293
  end
271
294
 
295
+ def imgtable(lines, id, caption = nil, metric = nil)
296
+ metrics = parse_metric('top', metric)
297
+ metrics = " #{metrics}" if metrics.present?
298
+ blank
299
+ puts "◆→開始:#{@titles['table']}←◆"
300
+ if caption_top?('table') && caption.present?
301
+ table_header(id, caption)
302
+ end
303
+
304
+ if @chapter.image_bound?(id)
305
+ puts "◆→#{@chapter.image(id).path}#{metrics}←◆"
306
+ else
307
+ warn "image not bound: #{id}", location: location
308
+ lines.each do |line|
309
+ puts line
310
+ end
311
+ end
312
+
313
+ if !caption_top?('table') && caption.present?
314
+ table_header(id, caption)
315
+ end
316
+ puts "◆→終了:#{@titles['table']}←◆"
317
+ blank
318
+ end
319
+
272
320
  def comment(lines, comment = nil)
273
321
  return unless @book.config['draft']
274
322
 
@@ -290,14 +338,33 @@ module ReVIEW
290
338
  app_error "unknown footnote: #{id}"
291
339
  end
292
340
 
341
+ def inline_endnote(id)
342
+ "【後注#{@chapter.endnote(id).number}】"
343
+ rescue KeyError
344
+ app_error "unknown endnote: #{id}"
345
+ end
346
+
347
+ def endnote_begin
348
+ puts '◆→開始:後注←◆'
349
+ end
350
+
351
+ def endnote_end
352
+ puts '◆→終了:後注←◆'
353
+ end
354
+
355
+ def endnote_item(id)
356
+ puts "【後注#{@chapter.endnote(id).number}】#{compile_inline(@chapter.endnote(id).content)}"
357
+ end
358
+
293
359
  def compile_ruby(base, ruby)
294
360
  "#{base}◆→DTP連絡:「#{base}」に「#{ruby}」とルビ←◆"
295
361
  end
296
362
 
297
363
  def compile_kw(word, alt)
298
364
  if alt
299
- then "★#{word}☆(#{alt.strip})"
300
- else "★#{word}☆"
365
+ "★#{word}☆(#{alt.strip})"
366
+ else
367
+ "★#{word}☆"
301
368
  end
302
369
  end
303
370
 
@@ -380,7 +447,7 @@ module ReVIEW
380
447
  def inline_icon(id)
381
448
  begin
382
449
  "◆→画像 #{@chapter.image(id).path.sub(%r{\A\./}, '')}←◆"
383
- rescue
450
+ rescue StandardError
384
451
  warn "image not bound: #{id}", location: location
385
452
  "◆→画像 #{id}←◆"
386
453
  end
@@ -477,27 +544,37 @@ module ReVIEW
477
544
  ), __FILE__, __LINE__ - 11
478
545
  end
479
546
 
480
- def indepimage(_lines, id, caption = nil, metric = nil)
547
+ def indepimage(lines, id, caption = nil, metric = nil)
481
548
  metrics = parse_metric('top', metric)
482
549
  metrics = " #{metrics}" if metrics.present?
483
550
  blank
551
+ puts "◆→開始:#{@titles['image']}←◆"
484
552
  if caption_top?('image') && caption.present?
485
- puts "図 #{compile_inline(caption)}"
553
+ indepimage_header(id, caption)
554
+ blank
486
555
  end
487
- begin
488
- puts "◆→画像 #{@chapter.image(id).path.sub(%r{\A\./}, '')}#{metrics}←◆"
489
- rescue
556
+ if @chapter.image_bound?(id)
557
+ puts "◆→#{@chapter.image(id).path}#{metrics}←◆"
558
+ else
490
559
  warn "image not bound: #{id}", location: location
491
- puts "◆→画像 #{id}←◆"
560
+ lines.each do |line|
561
+ puts line
562
+ end
492
563
  end
493
564
  if !caption_top?('image') && caption.present?
494
- puts "図 #{compile_inline(caption)}"
565
+ blank
566
+ indepimage_header(id, caption)
495
567
  end
568
+ puts "◆→終了:#{@titles['image']}←◆"
496
569
  blank
497
570
  end
498
571
 
499
572
  alias_method :numberlessimage, :indepimage
500
573
 
574
+ def indepimage_header(_id, caption)
575
+ puts "図#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}"
576
+ end
577
+
501
578
  def inline_code(str)
502
579
  "△#{str}☆"
503
580
  end