review 3.1.0 → 3.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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +11 -1
  3. data/.travis.yml +16 -15
  4. data/NEWS.ja.md +75 -0
  5. data/NEWS.md +75 -0
  6. data/appveyor.yml +20 -2
  7. data/bin/review-catalog-converter +3 -3
  8. data/bin/review-check +3 -3
  9. data/bin/review-compile +6 -6
  10. data/bin/review-epubmaker +3 -35
  11. data/bin/review-index +5 -5
  12. data/bin/review-preproc +4 -4
  13. data/bin/review-vol +5 -5
  14. data/doc/format.ja.md +6 -4
  15. data/doc/format.md +3 -1
  16. data/lib/epubmaker/epubcommon.rb +1 -2
  17. data/lib/epubmaker/epubv2.rb +1 -1
  18. data/lib/epubmaker/epubv3.rb +1 -0
  19. data/lib/epubmaker/producer.rb +2 -1
  20. data/lib/review/book/base.rb +5 -5
  21. data/lib/review/book/index.rb +18 -5
  22. data/lib/review/builder.rb +8 -2
  23. data/lib/review/compiler.rb +11 -34
  24. data/lib/review/epub2html.rb +37 -4
  25. data/lib/review/epubmaker.rb +40 -3
  26. data/lib/review/htmlbuilder.rb +2 -2
  27. data/lib/review/idgxmlbuilder.rb +9 -8
  28. data/lib/review/init.rb +7 -7
  29. data/lib/review/latexbuilder.rb +36 -14
  30. data/lib/review/location.rb +32 -0
  31. data/lib/review/markdownbuilder.rb +8 -1
  32. data/lib/review/plaintextbuilder.rb +9 -9
  33. data/lib/review/preprocessor.rb +2 -24
  34. data/lib/review/topbuilder.rb +4 -4
  35. data/lib/review/update.rb +3 -3
  36. data/lib/review/version.rb +1 -1
  37. data/lib/review/yamlloader.rb +23 -16
  38. data/review.gemspec +3 -2
  39. data/templates/latex/config.erb +4 -0
  40. data/templates/latex/review-jlreq/review-base.sty +45 -22
  41. data/templates/latex/review-jsbook/review-base.sty +20 -15
  42. data/templates/latex/review-jsbook/review-jsbook.cls +3 -3
  43. data/templates/opf/epubv3.opf.erb +1 -0
  44. data/test/assets/test_template.tex +4 -0
  45. data/test/assets/test_template_backmatter.tex +4 -0
  46. data/test/test_book.rb +1 -1
  47. data/test/test_builder.rb +16 -0
  48. data/test/test_catalog.rb +5 -0
  49. data/test/test_htmlbuilder.rb +471 -96
  50. data/test/test_idgxmlbuilder.rb +132 -17
  51. data/test/test_index.rb +40 -0
  52. data/test/test_latexbuilder.rb +668 -72
  53. data/test/test_latexbuilder_v2.rb +597 -68
  54. data/test/test_markdownbuilder.rb +90 -13
  55. data/test/test_md2inaobuilder.rb +20 -7
  56. data/test/test_plaintextbuilder.rb +241 -19
  57. data/test/test_preprocessor.rb +2 -16
  58. data/test/test_rstbuilder.rb +216 -22
  59. data/test/test_topbuilder.rb +334 -22
  60. metadata +20 -6
@@ -655,6 +655,7 @@ module ReVIEW
655
655
  rows.push(line.strip.split(/\t+/).map { |s| s.sub(/\A\./, '') })
656
656
  end
657
657
  rows = adjust_n_cols(rows)
658
+ error 'no rows in the table' if rows.empty?
658
659
 
659
660
  if id
660
661
  puts %Q(<div id="#{normalize_id(id)}" class="table">)
@@ -669,7 +670,6 @@ module ReVIEW
669
670
  error "no such table: #{id}"
670
671
  end
671
672
  table_begin rows.first.size
672
- return if rows.empty?
673
673
  if sepidx
674
674
  sepidx.times do
675
675
  tr(rows.shift.map { |s| th(s) })
@@ -1002,7 +1002,7 @@ module ReVIEW
1002
1002
 
1003
1003
  def inline_hd_chap(chap, id)
1004
1004
  n = chap.headline_index.number(id)
1005
- if chap.number and @book.config['secnolevel'] >= n.split('.').size
1005
+ if n.present? && chap.number && over_secnolevel?(n)
1006
1006
  str = I18n.t('hd_quote', [n, compile_inline(chap.headline(id).caption)])
1007
1007
  else
1008
1008
  str = I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
@@ -146,6 +146,7 @@ module ReVIEW
146
146
 
147
147
  @subsubsubsection += 1
148
148
  print %Q(<sect4 id="sect:#{@chapter.number}.#{@section}.#{@subsection}.#{@subsubsection}.#{@subsubsubsection}">) if @secttags
149
+ when 6 # rubocop:disable Lint/EmptyWhen
149
150
  else
150
151
  raise "caption level too deep or unsupported: #{level}"
151
152
  end
@@ -449,7 +450,6 @@ module ReVIEW
449
450
  tablewidth = @book.config['tableopt'] ? @book.config['tableopt'].split(',')[0].to_f / @book.config['pt_to_mm_unit'].to_f : nil
450
451
  col = 0
451
452
 
452
- puts '<table>'
453
453
  rows = []
454
454
  sepidx = nil
455
455
  lines.each_with_index do |line, idx|
@@ -465,6 +465,9 @@ module ReVIEW
465
465
  col2 = rows[rows.length - 1].split(/\t/).length
466
466
  col = col2 if col2 > col
467
467
  end
468
+ error 'no rows in the table' if rows.empty?
469
+
470
+ puts '<table>'
468
471
 
469
472
  cellwidth = []
470
473
  if tablewidth
@@ -491,7 +494,6 @@ module ReVIEW
491
494
  rescue KeyError
492
495
  error "no such table: #{id}"
493
496
  end
494
- return if rows.empty?
495
497
 
496
498
  if tablewidth.nil?
497
499
  print '<tbody>'
@@ -1146,13 +1148,12 @@ module ReVIEW
1146
1148
  end
1147
1149
 
1148
1150
  def inline_hd_chap(chap, id)
1149
- if chap.number
1150
- n = chap.headline_index.number(id)
1151
- if @book.config['secnolevel'] >= n.split('.').size
1152
- return I18n.t('hd_quote', [n, compile_inline(chap.headline(id).caption)])
1153
- end
1151
+ n = chap.headline_index.number(id)
1152
+ if n.present? && chap.number && over_secnolevel?(n)
1153
+ I18n.t('hd_quote', [n, compile_inline(chap.headline(id).caption)])
1154
+ else
1155
+ I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
1154
1156
  end
1155
- I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
1156
1157
  rescue KeyError
1157
1158
  error "unknown headline: #{id}"
1158
1159
  end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2018 Masanori Kado, Masayoshi Takahashi, Kenshi Muto
2
+ # Copyright (c) 2018-2019 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
@@ -78,8 +78,8 @@ module ReVIEW
78
78
 
79
79
  begin
80
80
  opts.parse!(args)
81
- rescue OptionParser::ParseError => err
82
- @logger.error err.message
81
+ rescue OptionParser::ParseError => e
82
+ @logger.error e.message
83
83
  $stderr.puts opts.help
84
84
  exit 1
85
85
  end
@@ -226,8 +226,8 @@ EOS
226
226
  begin
227
227
  @logger.info "Downloading from #{filename}"
228
228
  zipdata = Net::HTTP.get(URI.parse(filename))
229
- rescue StandardError => err
230
- @logger.error "Failed to download #{filename}: #{err.message}"
229
+ rescue StandardError => e
230
+ @logger.error "Failed to download #{filename}: #{e.message}"
231
231
  exit 1
232
232
  end
233
233
 
@@ -267,8 +267,8 @@ EOS
267
267
  made = true
268
268
  end
269
269
  raise Zip::Error unless made
270
- rescue Zip::Error => err
271
- @logger.error "#{originalfilename} seems invalid or broken zip file: #{err.message}"
270
+ rescue Zip::Error => e
271
+ @logger.error "#{originalfilename} seems invalid or broken zip file: #{e.message}"
272
272
  end
273
273
  end
274
274
  end
@@ -257,7 +257,7 @@ module ReVIEW
257
257
  end
258
258
 
259
259
  def ul_item(lines)
260
- str = lines.join
260
+ str = lines.map(&:chomp).join("\n")
261
261
  str.sub!(/\A(\[)/) { '\lbrack{}' }
262
262
  puts '\item ' + str
263
263
  end
@@ -276,7 +276,7 @@ module ReVIEW
276
276
  end
277
277
 
278
278
  def ol_item(lines, _num)
279
- str = lines.join
279
+ str = lines.map(&:chomp).join("\n")
280
280
  str.sub!(/\A(\[)/) { '\lbrack{}' }
281
281
  puts '\item ' + str
282
282
  end
@@ -298,7 +298,7 @@ module ReVIEW
298
298
  end
299
299
 
300
300
  def dd(lines)
301
- puts lines.join
301
+ puts lines.map(&:chomp).join("\n")
302
302
  end
303
303
 
304
304
  def dl_end
@@ -471,10 +471,16 @@ module ReVIEW
471
471
  metrics = parse_metric('latex', metric)
472
472
  # image is always bound here
473
473
  puts "\\begin{reviewimage}%%#{id}"
474
+
475
+ command = 'reviewincludegraphics'
476
+ if @book.config.check_version('2', exception: false)
477
+ command = 'includegraphics'
478
+ end
479
+
474
480
  if metrics.present?
475
- puts "\\includegraphics[#{metrics}]{#{@chapter.image(id).path}}"
481
+ puts "\\#{command}[#{metrics}]{#{@chapter.image(id).path}}"
476
482
  else
477
- puts "\\includegraphics[width=\\maxwidth]{#{@chapter.image(id).path}}"
483
+ puts "\\#{command}[width=\\maxwidth]{#{@chapter.image(id).path}}"
478
484
  end
479
485
  @doc_status[:caption] = true
480
486
 
@@ -551,10 +557,16 @@ module ReVIEW
551
557
 
552
558
  if @chapter.image(id).path
553
559
  puts "\\begin{reviewimage}%%#{id}"
560
+
561
+ command = 'reviewincludegraphics'
562
+ if @book.config.check_version('2', exception: false)
563
+ command = 'includegraphics'
564
+ end
565
+
554
566
  if metrics.present?
555
- puts "\\includegraphics[#{metrics}]{#{@chapter.image(id).path}}"
567
+ puts "\\#{command}[#{metrics}]{#{@chapter.image(id).path}}"
556
568
  else
557
- puts "\\includegraphics[width=\\maxwidth]{#{@chapter.image(id).path}}"
569
+ puts "\\#{command}[width=\\maxwidth]{#{@chapter.image(id).path}}"
558
570
  end
559
571
  else
560
572
  warn "image not bound: #{id}"
@@ -594,13 +606,13 @@ module ReVIEW
594
606
  rows.push(line.strip.split(/\t+/).map { |s| s.sub(/\A\./, '') })
595
607
  end
596
608
  rows = adjust_n_cols(rows)
609
+ error 'no rows in the table' if rows.empty?
597
610
 
598
611
  begin
599
612
  table_header(id, caption) if caption.present?
600
613
  rescue KeyError
601
614
  error "no such table: #{id}"
602
615
  end
603
- return if rows.empty?
604
616
  table_begin(rows.first.size)
605
617
  if sepidx
606
618
  sepidx.times do
@@ -797,10 +809,16 @@ module ReVIEW
797
809
  metrics = parse_metric('latex', metric)
798
810
  # image is always bound here
799
811
  puts "\\begin{reviewimage}%%#{id}"
812
+
813
+ command = 'reviewincludegraphics'
814
+ if @book.config.check_version('2', exception: false)
815
+ command = 'includegraphics'
816
+ end
817
+
800
818
  if metrics.present?
801
- puts "\\includegraphics[#{metrics}]{#{@chapter.image(id).path}}"
819
+ puts "\\#{command}[#{metrics}]{#{@chapter.image(id).path}}"
802
820
  else
803
- puts "\\includegraphics[width=\\maxwidth]{#{@chapter.image(id).path}}"
821
+ puts "\\#{command}[width=\\maxwidth]{#{@chapter.image(id).path}}"
804
822
  end
805
823
  puts '\end{reviewimage}'
806
824
  end
@@ -997,7 +1015,7 @@ module ReVIEW
997
1015
  BOUTEN = '・'.freeze
998
1016
 
999
1017
  def inline_bou(str)
1000
- str.split(//).map { |c| macro('ruby', escape(c), macro('textgt', BOUTEN)) }.join('\allowbreak')
1018
+ macro('reviewbou', escape(str))
1001
1019
  end
1002
1020
 
1003
1021
  def compile_ruby(base, ruby)
@@ -1103,7 +1121,7 @@ module ReVIEW
1103
1121
 
1104
1122
  def inline_hd_chap(chap, id)
1105
1123
  n = chap.headline_index.number(id)
1106
- if chap.number and @book.config['secnolevel'] >= n.split('.').size
1124
+ if n.present? && chap.number && over_secnolevel?(n)
1107
1125
  str = I18n.t('hd_quote', [chap.headline_index.number(id), compile_inline(chap.headline(id).caption)])
1108
1126
  else
1109
1127
  str = I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
@@ -1154,7 +1172,11 @@ module ReVIEW
1154
1172
 
1155
1173
  def inline_icon(id)
1156
1174
  if @chapter.image(id).path
1157
- macro('includegraphics', @chapter.image(id).path)
1175
+ command = 'reviewincludegraphics'
1176
+ if @book.config.check_version('2', exception: false)
1177
+ command = 'includegraphics'
1178
+ end
1179
+ macro(command, @chapter.image(id).path)
1158
1180
  else
1159
1181
  warn "image not bound: #{id}"
1160
1182
  "\\verb|--[[path = #{id} (#{existence(id)})]]--|"
@@ -1193,7 +1215,7 @@ module ReVIEW
1193
1215
  end
1194
1216
 
1195
1217
  def bibpaper_bibpaper(_id, _caption, lines)
1196
- print split_paragraph(lines).join
1218
+ print split_paragraph(lines).map(&:chomp).join("\n")
1197
1219
  puts ''
1198
1220
  end
1199
1221
 
@@ -0,0 +1,32 @@
1
+ # Copyright (c) 2009-2019 Minero Aoki, Kenshi Muto, Masayoshi Takahashi
2
+ # Copyright (c) 2002-2007 Minero Aoki
3
+ #
4
+ # This program is free software.
5
+ # You can distribute or modify this program under the terms of
6
+ # the GNU LGPL, Lesser General Public License version 2.1.
7
+ #
8
+
9
+ module ReVIEW
10
+ class Location
11
+ def initialize(filename, f)
12
+ @filename = filename
13
+ @f = f
14
+ end
15
+
16
+ attr_reader :filename
17
+
18
+ def lineno
19
+ @f.lineno
20
+ end
21
+
22
+ def string
23
+ begin
24
+ "#{@filename}:#{@f.lineno}"
25
+ rescue
26
+ "#{@filename}:nil"
27
+ end
28
+ end
29
+
30
+ alias_method :to_s, :string
31
+ end
32
+ end
@@ -80,6 +80,13 @@ module ReVIEW
80
80
  puts '```'
81
81
  end
82
82
 
83
+ def listnum_body(lines, _lang)
84
+ lines.each_with_index do |line, i|
85
+ puts((i + 1).to_s.rjust(2) + ": #{detab(line)}")
86
+ end
87
+ puts '```'
88
+ end
89
+
83
90
  def ul_begin
84
91
  blank if @ul_indent == 0
85
92
  @ul_indent += 1
@@ -250,6 +257,7 @@ module ReVIEW
250
257
  rows.push(line.strip.split(/\t+/).map { |s| s.sub(/\A\./, '') })
251
258
  end
252
259
  rows = adjust_n_cols(rows)
260
+ error 'no rows in the table' if rows.empty?
253
261
 
254
262
  begin
255
263
  table_header id, caption unless caption.nil?
@@ -257,7 +265,6 @@ module ReVIEW
257
265
  error "no such table: #{id}"
258
266
  end
259
267
  table_begin rows.first.size
260
- return if rows.empty?
261
268
  if sepidx
262
269
  sepidx.times do
263
270
  tr(rows.shift.map { |s| th(s) })
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2018 Kenshi Muto
1
+ # Copyright (c) 2018-2019 Kenshi Muto
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -221,7 +221,6 @@ module ReVIEW
221
221
  end
222
222
 
223
223
  def table(lines, id = nil, caption = nil)
224
- blank
225
224
  rows = []
226
225
  sepidx = nil
227
226
  lines.each_with_index do |line, idx|
@@ -234,13 +233,15 @@ module ReVIEW
234
233
  rows.push(line.strip.split(/\t+/).map { |s| s.sub(/\A\./, '') })
235
234
  end
236
235
  rows = adjust_n_cols(rows)
236
+ error 'no rows in the table' if rows.empty?
237
+
238
+ blank
237
239
 
238
240
  begin
239
241
  table_header(id, caption) if caption.present?
240
242
  rescue KeyError
241
243
  error "no such table: #{id}"
242
244
  end
243
- return if rows.empty?
244
245
  table_begin rows.first.size
245
246
  if sepidx
246
247
  sepidx.times do
@@ -364,13 +365,12 @@ module ReVIEW
364
365
  end
365
366
 
366
367
  def inline_hd_chap(chap, id)
367
- if chap.number
368
- n = chap.headline_index.number(id)
369
- if @book.config['secnolevel'] >= n.split('.').size
370
- return I18n.t('hd_quote', [n, compile_inline(chap.headline(id).caption)])
371
- end
368
+ n = chap.headline_index.number(id)
369
+ if n.present? && chap.number && over_secnolevel?(n)
370
+ I18n.t('hd_quote', [n, compile_inline(chap.headline(id).caption)])
371
+ else
372
+ I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
372
373
  end
373
- I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
374
374
  rescue KeyError
375
375
  error "unknown headline: #{id}"
376
376
  end
@@ -43,28 +43,6 @@ module ReVIEW
43
43
  class Preprocessor
44
44
  include ErrorUtils
45
45
 
46
- class Strip
47
- def initialize(f)
48
- @f = f
49
- end
50
-
51
- def path
52
- @f.path
53
- end
54
-
55
- def lineno
56
- @f.lineno
57
- end
58
-
59
- def gets
60
- @f.each_line do |line|
61
- return "\#@\#\n" if /\A\#@/ =~ line
62
- return line
63
- end
64
- nil
65
- end
66
- end
67
-
68
46
  def initialize(repo, param)
69
47
  @repository = repo
70
48
  @config = param
@@ -77,8 +55,8 @@ module ReVIEW
77
55
  @f = outf
78
56
  begin
79
57
  preproc inf
80
- rescue Errno::ENOENT => err
81
- error err.message
58
+ rescue Errno::ENOENT => e
59
+ error e.message
82
60
  end
83
61
  end
84
62
 
@@ -186,9 +186,6 @@ module ReVIEW
186
186
  end
187
187
 
188
188
  def table(lines, id = nil, caption = nil)
189
- blank
190
- puts "◆→開始:#{@titles['table']}←◆"
191
-
192
189
  rows = []
193
190
  sepidx = nil
194
191
  lines.each_with_index do |line, idx|
@@ -201,13 +198,16 @@ module ReVIEW
201
198
  rows.push(line.strip.split(/\t+/).map { |s| s.sub(/\A\./, '') })
202
199
  end
203
200
  rows = adjust_n_cols(rows)
201
+ error 'no rows in the table' if rows.empty?
202
+
203
+ blank
204
+ puts "◆→開始:#{@titles['table']}←◆"
204
205
 
205
206
  begin
206
207
  table_header id, caption if caption.present?
207
208
  rescue KeyError
208
209
  error "no such table: #{id}"
209
210
  end
210
- return if rows.empty?
211
211
  table_begin rows.first.size
212
212
  if sepidx
213
213
  sepidx.times do
@@ -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
@@ -145,8 +145,8 @@ module ReVIEW
145
145
 
146
146
  begin
147
147
  opts.parse!(args)
148
- rescue OptionParser::ParseError => err
149
- @logger.error err.message
148
+ rescue OptionParser::ParseError => e
149
+ @logger.error e.message
150
150
  $stderr.puts opts.help
151
151
  raise ApplicationError
152
152
  end