review 4.0.0 → 4.1.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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-win.yml +39 -0
  3. data/.github/workflows/ruby.yml +27 -0
  4. data/.rubocop.yml +10 -7
  5. data/Dockerfile +21 -5
  6. data/NEWS.ja.md +101 -1
  7. data/NEWS.md +102 -2
  8. data/README.md +10 -7
  9. data/appveyor.yml +0 -20
  10. data/bin/review-compile +1 -1
  11. data/bin/review-validate +1 -1
  12. data/doc/config.yml.sample +12 -1
  13. data/doc/config.yml.sample-simple +1 -0
  14. data/doc/format.ja.md +16 -4
  15. data/doc/format.md +2 -1
  16. data/doc/quickstart.ja.md +40 -23
  17. data/doc/quickstart.md +33 -15
  18. data/lib/review/book/base.rb +8 -7
  19. data/lib/review/book/index.rb +50 -56
  20. data/lib/review/book/index/item.rb +1 -1
  21. data/lib/review/builder.rb +26 -4
  22. data/lib/review/compiler.rb +6 -3
  23. data/lib/review/configure.rb +5 -3
  24. data/lib/review/epubmaker.rb +15 -2
  25. data/lib/review/extentions/string.rb +0 -4
  26. data/lib/review/htmlbuilder.rb +4 -15
  27. data/lib/review/idgxmlbuilder.rb +10 -19
  28. data/lib/review/idgxmlmaker.rb +10 -3
  29. data/lib/review/init.rb +8 -1
  30. data/lib/review/latexbuilder.rb +13 -6
  31. data/lib/review/pdfmaker.rb +24 -9
  32. data/lib/review/rstbuilder.rb +2 -2
  33. data/lib/review/textmaker.rb +7 -1
  34. data/lib/review/tocparser.rb +6 -2
  35. data/lib/review/version.rb +1 -1
  36. data/lib/review/webmaker.rb +8 -1
  37. data/review.gemspec +2 -2
  38. data/samples/sample-book/src/.gitignore +1 -0
  39. data/samples/sample-book/src/config-ebook.yml +4 -0
  40. data/samples/sample-book/src/config-jlreq-ebook.yml +4 -0
  41. data/samples/sample-book/src/config.yml +1 -1
  42. data/samples/sample-book/src/lib/tasks/review.rake +10 -6
  43. data/samples/syntax-book/ch01.re +4 -2
  44. data/samples/syntax-book/ch02.re +8 -16
  45. data/samples/syntax-book/config-jlreq-lualatex.yml +4 -0
  46. data/samples/syntax-book/config-print.yml +3 -0
  47. data/samples/syntax-book/config.yml +1 -1
  48. data/samples/syntax-book/lib/tasks/review.rake +23 -8
  49. data/templates/latex/config.erb +6 -6
  50. data/templates/latex/review-jlreq/review-base.sty +14 -4
  51. data/templates/latex/review-jlreq/review-jlreq.cls +10 -1
  52. data/templates/latex/review-jlreq/review-style.sty +1 -1
  53. data/templates/latex/review-jsbook/review-base.sty +10 -0
  54. data/templates/latex/review-jsbook/review-jsbook.cls +1 -1
  55. data/templates/latex/review-jsbook/review-style.sty +1 -1
  56. data/test/assets/test_template.tex +6 -6
  57. data/test/assets/test_template_backmatter.tex +6 -6
  58. data/test/test_book.rb +8 -0
  59. data/test/test_book_chapter.rb +4 -2
  60. data/test/test_catalog.rb +1 -0
  61. data/test/test_epubmaker_cmd.rb +12 -5
  62. data/test/test_helper.rb +11 -6
  63. data/test/test_htmlbuilder.rb +80 -8
  64. data/test/test_idgxmlbuilder.rb +57 -2
  65. data/test/test_idgxmlmaker_cmd.rb +46 -0
  66. data/test/test_image_finder.rb +52 -70
  67. data/test/test_index.rb +12 -12
  68. data/test/test_latexbuilder.rb +171 -8
  69. data/test/test_latexbuilder_v2.rb +9 -7
  70. data/test/test_pdfmaker_cmd.rb +99 -5
  71. data/test/test_textmaker_cmd.rb +54 -0
  72. data/test/test_topbuilder.rb +59 -0
  73. data/vendor/jsclasses/LICENSE +1 -1
  74. data/vendor/jsclasses/jis/jsarticle.cls +53 -14
  75. data/vendor/jsclasses/jis/jsbook.cls +53 -14
  76. data/vendor/jsclasses/jis/jsclasses.dtx +84 -25
  77. data/vendor/jsclasses/jis/jslogo.dtx +4 -4
  78. data/vendor/jsclasses/jis/jslogo.sty +3 -3
  79. data/vendor/jsclasses/jis/jspf.cls +52 -13
  80. data/vendor/jsclasses/jis/jsreport.cls +53 -14
  81. data/vendor/jsclasses/jis/kiyou.cls +53 -14
  82. data/vendor/jsclasses/jis/okumacro.dtx +4 -5
  83. data/vendor/jsclasses/jis/okumacro.sty +3 -4
  84. data/vendor/jsclasses/jsarticle.cls +53 -14
  85. data/vendor/jsclasses/jsbook.cls +53 -14
  86. data/vendor/jsclasses/jsclasses.dtx +84 -25
  87. data/vendor/jsclasses/jsclasses.pdf +0 -0
  88. data/vendor/jsclasses/jslogo.dtx +4 -4
  89. data/vendor/jsclasses/jslogo.pdf +0 -0
  90. data/vendor/jsclasses/jslogo.sty +3 -3
  91. data/vendor/jsclasses/jspf.cls +52 -13
  92. data/vendor/jsclasses/jsreport.cls +53 -14
  93. data/vendor/jsclasses/kiyou.cls +53 -14
  94. data/vendor/jsclasses/okumacro.dtx +4 -5
  95. data/vendor/jsclasses/okumacro.pdf +0 -0
  96. data/vendor/jsclasses/okumacro.sty +3 -4
  97. metadata +15 -6
  98. data/samples/syntax-book/review-ext.rb +0 -14
@@ -2,7 +2,3 @@ if defined?(Encoding) && Encoding.respond_to?('default_external') &&
2
2
  Encoding.default_external != Encoding::UTF_8
3
3
  Encoding.default_external = 'UTF-8'
4
4
  end
5
-
6
- class String
7
- alias_method :each, :each_line
8
- end
@@ -373,12 +373,7 @@ module ReVIEW
373
373
 
374
374
  def list(lines, id, caption, lang = nil)
375
375
  puts %Q(<div id="#{normalize_id(id)}" class="caption-code">)
376
- begin
377
- list_header(id, caption, lang)
378
- rescue KeyError
379
- error "no such list: #{id}"
380
- end
381
- list_body(id, lines, lang)
376
+ super(lines, id, caption, lang)
382
377
  puts '</div>'
383
378
  end
384
379
 
@@ -403,8 +398,7 @@ module ReVIEW
403
398
 
404
399
  def source(lines, caption = nil, lang = nil)
405
400
  puts %Q(<div class="source-code">)
406
- source_header(caption)
407
- source_body(caption, lines, lang)
401
+ super(lines, caption, lang)
408
402
  puts '</div>'
409
403
  end
410
404
 
@@ -414,7 +408,7 @@ module ReVIEW
414
408
  end
415
409
  end
416
410
 
417
- def source_body(_id, lines, lang)
411
+ def source_body(lines, lang)
418
412
  print %Q(<pre class="source">)
419
413
  body = lines.inject('') { |i, j| i + detab(j) + "\n" }
420
414
  lexer = lang
@@ -424,12 +418,7 @@ module ReVIEW
424
418
 
425
419
  def listnum(lines, id, caption, lang = nil)
426
420
  puts %Q(<div id="#{normalize_id(id)}" class="code">)
427
- begin
428
- list_header(id, caption, lang)
429
- rescue KeyError
430
- error "no such list: #{id}"
431
- end
432
- listnum_body(lines, lang)
421
+ super(lines, id, caption, lang)
433
422
  puts '</div>'
434
423
  end
435
424
 
@@ -297,12 +297,7 @@ module ReVIEW
297
297
 
298
298
  def list(lines, id, caption, lang = nil)
299
299
  puts '<codelist>'
300
- begin
301
- list_header(id, caption, lang)
302
- rescue KeyError
303
- error "no such list: #{id}"
304
- end
305
- list_body(id, lines, lang)
300
+ super(lines, id, caption, lang)
306
301
  puts '</codelist>'
307
302
  end
308
303
 
@@ -327,12 +322,7 @@ module ReVIEW
327
322
 
328
323
  def listnum(lines, id, caption, lang = nil)
329
324
  puts '<codelist>'
330
- begin
331
- list_header(id, caption, lang)
332
- rescue KeyError
333
- error "no such list: #{id}"
334
- end
335
- listnum_body(lines, lang)
325
+ super(lines, id, caption, lang)
336
326
  puts '</codelist>'
337
327
  end
338
328
 
@@ -490,6 +480,7 @@ module ReVIEW
490
480
  else
491
481
  print %Q(<tbody xmlns:aid5="http://ns.adobe.com/AdobeInDesign/5.0/" aid:table="table" aid:trows="#{rows.length}" aid:tcols="#{@col}">)
492
482
  end
483
+ @table_id = id
493
484
  table_rows(sepidx, rows)
494
485
  puts '</tbody></table>'
495
486
  @tsize = nil
@@ -508,7 +499,7 @@ module ReVIEW
508
499
  else
509
500
  rows.push(line.gsub(/\t\.\t/, "\t\t").gsub(/\t\.\.\t/, "\t.\t").gsub(/\t\.\Z/, "\t").gsub(/\t\.\.\Z/, "\t.").gsub(/\A\./, ''))
510
501
  end
511
- col2 = rows[rows.length - 1].split(/\t/).length
502
+ col2 = rows[rows.length - 1].split(table_row_separator_regexp).length
512
503
  @col = col2 if col2 > @col
513
504
  end
514
505
  error 'no rows in the table' if rows.empty?
@@ -526,11 +517,11 @@ module ReVIEW
526
517
  cellwidth.size.times do |n|
527
518
  cellwidth[n] = cellwidth[n].to_f / @book.config['pt_to_mm_unit'].to_f
528
519
  totallength += cellwidth[n]
529
- warn "total length exceeds limit for table: #{id}" if totallength > @tablewidth
520
+ warn "total length exceeds limit for table: #{@table_id}" if totallength > @tablewidth
530
521
  end
531
522
  if cellwidth.size < @col
532
523
  cw = (@tablewidth - totallength) / (@col - cellwidth.size)
533
- warn "auto cell sizing exceeds limit for table: #{id}" if cw <= 0
524
+ warn "auto cell sizing exceeds limit for table: #{@table_id}" if cw <= 0
534
525
  (cellwidth.size..(@col - 1)).each { |i| cellwidth[i] = cw }
535
526
  end
536
527
  end
@@ -542,7 +533,7 @@ module ReVIEW
542
533
  puts %Q(<tr type="header">#{rows.shift}</tr>)
543
534
  else
544
535
  i = 0
545
- rows.shift.split("\t").each_with_index do |cell, x|
536
+ rows.shift.split(table_row_separator_regexp).each_with_index do |cell, x|
546
537
  print %Q(<td xyh="#{x + 1},#{y + 1},#{sepidx}" aid:table="cell" aid:theader="1" aid:crows="1" aid:ccols="1" aid:ccolwidth="#{sprintf('%.3f', cellwidth[i])}">#{cell.sub('DUMMYCELLSPLITTER', '')}</td>)
547
538
  i += 1
548
539
  end
@@ -557,7 +548,7 @@ module ReVIEW
557
548
  if tablewidth
558
549
  rows.each_with_index do |row, y|
559
550
  i = 0
560
- row.split("\t").each_with_index do |cell, x|
551
+ row.split(table_row_separator_regexp).each_with_index do |cell, x|
561
552
  print %Q(<td xyh="#{x + 1},#{y + 1 + sepidx},#{sepidx}" aid:table="cell" aid:crows="1" aid:ccols="1" aid:ccolwidth="#{sprintf('%.3f', cellwidth[i])}">#{cell.sub('DUMMYCELLSPLITTER', '')}</td>)
562
553
  i += 1
563
554
  end
@@ -602,7 +593,7 @@ module ReVIEW
602
593
  end
603
594
 
604
595
  def imgtable(lines, id, caption = nil, metric = nil)
605
- if @chapter.image(id).bound?
596
+ if @chapter.image_bound?(id)
606
597
  metrics = parse_metric('idgxml', metric)
607
598
  puts '<table>'
608
599
  table_header(id, caption) if caption.present?
@@ -1155,7 +1146,7 @@ module ReVIEW
1155
1146
  error "unknown chapter: #{id}"
1156
1147
  end
1157
1148
 
1158
- def source(lines, caption, lang = nil)
1149
+ def source(lines, caption = nil, lang = nil)
1159
1150
  puts '<source>'
1160
1151
  source_header(caption)
1161
1152
  source_body(lines, lang)
@@ -44,11 +44,13 @@ module ReVIEW
44
44
  opts = OptionParser.new
45
45
  @table = nil
46
46
  @filter = nil
47
+ @buildonly = nil
47
48
 
48
49
  opts.banner = 'Usage: review-idgxmlmaker [options] configfile'
49
50
  opts.version = ReVIEW::VERSION
50
51
  opts.on('-w', '--width widthoftypepage', 'Specify the width of type page for layouting tables (mm).') { |v| @table = v }
51
52
  opts.on('-f', '--filter filterprogrampath', 'Specify the filter path.') { |v| @filter = v }
53
+ opts.on('-y', '--only file1,file2,...', 'Build only specified files.') { |v| @buildonly = v.split(/\s*,\s*/).map { |m| m.strip.sub(/\.re\Z/, '') } }
52
54
  opts.on('--help', 'Prints this message and quit.') do
53
55
  puts opts.help
54
56
  exit 0
@@ -116,13 +118,14 @@ module ReVIEW
116
118
  ENV['REVIEW_FNAME'] = File.basename(xmlfile).sub(/.xml\Z/, '.re')
117
119
  begin
118
120
  o, e, s = Open3.capture3(@filter, stdin_data: File.read(xmlfile))
121
+ unless e.empty?
122
+ warn("filter error for #{xmlfile}: #{e}")
123
+ end
119
124
  if s.success?
120
125
  File.write(xmlfile, o) # override
121
- else
122
- warn("filter error for #{xmlfile}: #{e.message}")
123
126
  end
124
127
  rescue => e
125
- warn("filter error for #{xmlfile}: #{e}")
128
+ warn("filter error for #{xmlfile}: #{e.message}")
126
129
  end
127
130
  end
128
131
 
@@ -169,6 +172,10 @@ module ReVIEW
169
172
  filename = Pathname.new(chap.path).relative_path_from(base_path).to_s
170
173
  end
171
174
  id = File.basename(filename).sub(/\.re\Z/, '')
175
+ if @buildonly && !@buildonly.include?(id)
176
+ warn "skip #{id}.re"
177
+ return
178
+ end
172
179
 
173
180
  xmlfile = "#{id}.xml"
174
181
 
@@ -82,6 +82,9 @@ module ReVIEW
82
82
  opts.on('', '--epub-version VERSION', 'define EPUB version.') do |version|
83
83
  @epub_version = version
84
84
  end
85
+ opts.on('', '--without-config-comment', "don't include comments in config.yml.") do
86
+ @without_config_comment = true
87
+ end
85
88
  opts.on('', '--without-doc', "don't generate doc files.") do
86
89
  @without_doc = true
87
90
  end
@@ -176,6 +179,10 @@ EOS
176
179
  content.gsub!(/^#\s*texdocumentclass:.*$/, %Q(texdocumentclass: ["#{@template}", "#{@tex_documentclass_opts[@template]}"]))
177
180
  end
178
181
 
182
+ if @without_config_comment
183
+ content = content.split("\n").delete_if { |l| l.strip.start_with?('#') || l.strip.empty? }.join("\n")
184
+ end
185
+
179
186
  File.open(File.join(dir, 'config.yml'), 'w') { |f| f.write content }
180
187
  if @webui && !@web_result[2].empty?
181
188
  File.open(File.join(dir, 'config-ebook.yml'), 'w') do |f|
@@ -292,7 +299,7 @@ EOS
292
299
  next
293
300
  end
294
301
 
295
- if fname =~ %r{\A/} || fname =~ /\.\./ # simple fool proof
302
+ if fname.start_with?('/') || fname =~ /\.\./ # simple fool proof
296
303
  made = nil
297
304
  break
298
305
  end
@@ -1,6 +1,6 @@
1
1
  # Copyright (c) 2002-2007 Minero Aoki
2
2
  # 2008-2009 Minero Aoki, Kenshi Muto
3
- # 2010-2019 Minero Aoki, Kenshi Muto, TAKAHASHI Masayoshi
3
+ # 2010-2020 Minero Aoki, Kenshi Muto, TAKAHASHI Masayoshi
4
4
  #
5
5
  # This program is free software.
6
6
  # You can distribute or modify this program under the terms of
@@ -60,7 +60,7 @@ module ReVIEW
60
60
  require 'nkf'
61
61
  @index_mecab = MeCab::Tagger.new(@book.config['pdfmaker']['makeindex_mecab_opts'])
62
62
  rescue LoadError
63
- error 'not found MeCab'
63
+ warn 'not found MeCab'
64
64
  end
65
65
  end
66
66
 
@@ -299,8 +299,7 @@ module ReVIEW
299
299
  end
300
300
 
301
301
  def dt(str)
302
- str.sub!(/\[/) { '\lbrack{}' }
303
- str.sub!(/\]/) { '\rbrack{}' }
302
+ str = str.gsub('[', '\lbrack{}').gsub(']', '\rbrack{}')
304
303
  puts '\item[' + str + '] \mbox{} \\\\'
305
304
  end
306
305
 
@@ -482,8 +481,16 @@ module ReVIEW
482
481
  def image_header(id, caption)
483
482
  end
484
483
 
484
+ def parse_metric(type, metric)
485
+ s = super(type, metric)
486
+ if @book.config['pdfmaker']['use_original_image_size'] && s.empty? && !metric.present?
487
+ return ' ' # pass empty to \reviewincludegraphics
488
+ end
489
+ s
490
+ end
491
+
485
492
  def handle_metric(str)
486
- if @book.config['image_scale2width'] && str =~ /\Ascale=([\d.]+)\Z/
493
+ if @book.config['pdfmaker']['image_scale2width'] && str =~ /\Ascale=([\d.]+)\Z/
487
494
  return "width=#{$1}\\maxwidth"
488
495
  end
489
496
  str
@@ -1019,7 +1026,7 @@ module ReVIEW
1019
1026
  def inline_fn(id)
1020
1027
  if @book.config['footnotetext']
1021
1028
  macro("footnotemark[#{@chapter.footnote(id).number}]", '')
1022
- elsif @doc_status[:caption] || @doc_status[:table] || @doc_status[:column]
1029
+ elsif @doc_status[:caption] || @doc_status[:table] || @doc_status[:column] || @doc_status[:dt]
1023
1030
  @foottext[id] = @chapter.footnote(id).number
1024
1031
  macro('protect\\footnotemark', '')
1025
1032
  else
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2010-2019 Kenshi Muto and Masayoshi Takahashi
1
+ # Copyright (c) 2010-2020 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
@@ -100,6 +100,7 @@ module ReVIEW
100
100
  def parse_opts(args)
101
101
  cmd_config = {}
102
102
  opts = OptionParser.new
103
+ @buildonly = nil
103
104
 
104
105
  opts.banner = 'Usage: review-pdfmaker configfile'
105
106
  opts.version = ReVIEW::VERSION
@@ -109,6 +110,7 @@ module ReVIEW
109
110
  end
110
111
  opts.on('--[no-]debug', 'Keep temporary files.') { |debug| cmd_config['debug'] = debug }
111
112
  opts.on('--ignore-errors', 'Ignore review-compile errors.') { cmd_config['ignore-errors'] = true }
113
+ opts.on('-y', '--only file1,file2,...', 'Build only specified files.') { |v| @buildonly = v.split(/\s*,\s*/).map { |m| m.strip.sub(/\.re\Z/, '') } }
112
114
 
113
115
  opts.parse!(args)
114
116
  if args.size != 1
@@ -166,8 +168,13 @@ module ReVIEW
166
168
  if part.name.present?
167
169
  @config['use_part'] = true
168
170
  if part.file?
169
- output_chaps(part.name)
170
- input_files['CHAPS'] << %Q(\\input{#{part.name}.tex}\n)
171
+ if @buildonly && !@buildonly.include?(part.name)
172
+ warn "skip #{part.name}.re"
173
+ input_files['CHAPS'] << %Q(\\part{}\n)
174
+ else
175
+ output_chaps(part.name)
176
+ input_files['CHAPS'] << %Q(\\input{#{part.name}.tex}\n)
177
+ end
171
178
  else
172
179
  input_files['CHAPS'] << %Q(\\part{#{part.name}}\n)
173
180
  end
@@ -175,11 +182,18 @@ module ReVIEW
175
182
 
176
183
  part.chapters.each do |chap|
177
184
  filename = File.basename(chap.path, '.*')
178
- output_chaps(filename)
179
- input_files['PREDEF'] << "\\input{#{filename}.tex}\n" if chap.on_predef?
180
- input_files['CHAPS'] << "\\input{#{filename}.tex}\n" if chap.on_chaps?
181
- input_files['APPENDIX'] << "\\input{#{filename}.tex}\n" if chap.on_appendix?
182
- input_files['POSTDEF'] << "\\input{#{filename}.tex}\n" if chap.on_postdef?
185
+ entry = "\\input{#{filename}.tex}\n"
186
+ if @buildonly && !@buildonly.include?(filename)
187
+ warn "skip #{filename}.re"
188
+ entry = "\\chapter{}\n"
189
+ else
190
+ output_chaps(filename)
191
+ end
192
+
193
+ input_files['PREDEF'] << entry if chap.on_predef?
194
+ input_files['CHAPS'] << entry if chap.on_chaps?
195
+ input_files['APPENDIX'] << entry if chap.on_appendix?
196
+ input_files['POSTDEF'] << entry if chap.on_postdef?
183
197
  end
184
198
  end
185
199
 
@@ -235,8 +249,9 @@ module ReVIEW
235
249
  end
236
250
 
237
251
  call_hook('hook_beforemakeindex')
238
- if @config['pdfmaker']['makeindex'] && File.exist?("#{@mastertex}.idx")
252
+ if @config['pdfmaker']['makeindex'] && File.size?("#{@mastertex}.idx")
239
253
  system_or_raise(*[makeindex_command, makeindex_options, @mastertex].flatten.compact)
254
+ system_or_raise(*[texcommand, texoptions, "#{@mastertex}.tex"].flatten.compact)
240
255
  end
241
256
  call_hook('hook_aftermakeindex')
242
257
 
@@ -67,13 +67,13 @@ module ReVIEW
67
67
  end
68
68
  private :builder_init_file
69
69
 
70
- def print(s)
70
+ def print(*s)
71
71
  @blank_seen = false
72
72
  super
73
73
  end
74
74
  private :print
75
75
 
76
- def puts(s)
76
+ def puts(*s)
77
77
  @blank_seen = false
78
78
  super
79
79
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2018-2019 Kenshi Muto
1
+ # Copyright (c) 2018-2020 Kenshi Muto
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -45,10 +45,12 @@ module ReVIEW
45
45
  def parse_opts(args)
46
46
  cmd_config = {}
47
47
  opts = OptionParser.new
48
+ @buildonly = nil
48
49
 
49
50
  opts.banner = 'Usage: review-textmaker [-n] configfile'
50
51
  opts.version = ReVIEW::VERSION
51
52
  opts.on('-n', 'No decoration.') { @plaintext = true }
53
+ opts.on('-y', '--only file1,file2,...', 'Build only specified files.') { |v| @buildonly = v.split(/\s*,\s*/).map { |m| m.strip.sub(/\.re\Z/, '') } }
52
54
  opts.on('--help', 'Prints this message and quit.') do
53
55
  puts opts.help
54
56
  exit 0
@@ -154,6 +156,10 @@ module ReVIEW
154
156
  filename = Pathname.new(chap.path).relative_path_from(base_path).to_s
155
157
  end
156
158
  id = File.basename(filename).sub(/\.re\Z/, '')
159
+ if @buildonly && !@buildonly.include?(id)
160
+ warn "skip #{id}.re"
161
+ return
162
+ end
157
163
 
158
164
  textfile = "#{id}.txt"
159
165
 
@@ -31,6 +31,7 @@ module ReVIEW
31
31
  def parse(f, chap)
32
32
  roots = [] # list of chapters
33
33
  node_stack = []
34
+ @chap = chap
34
35
  filename = chap.path
35
36
  while line = f.gets
36
37
  case line
@@ -52,7 +53,7 @@ module ReVIEW
52
53
  node_stack.push(dummy_chapter)
53
54
  roots.push(dummy_chapter)
54
55
  end
55
- next if label =~ %r{\A\[/} # ex) "[/column]"
56
+ next if label.start_with?('[/') # ex) "[/column]"
56
57
  sec = Section.new(lev, label.gsub(/\A\{.*?\}\s?/, ''))
57
58
  node_stack.pop until node_stack.last.level < sec.level
58
59
  node_stack.last.add_child(sec)
@@ -73,7 +74,7 @@ module ReVIEW
73
74
  beg = f.lineno
74
75
  list.add(line)
75
76
  while line = f.gets
76
- break if %r{\A//\}} =~ line
77
+ break if line.start_with?('//}')
77
78
  list.add(line)
78
79
  end
79
80
  error!(filename, beg, 'unterminated list') unless line
@@ -107,6 +108,9 @@ module ReVIEW
107
108
  b = ReVIEW::TEXTBuilder.new
108
109
  dummy_book = ReVIEW::Book::Base.load
109
110
  dummy_chapter = ReVIEW::Book::Chapter.new(dummy_book, 1, '-', nil, StringIO.new)
111
+ if @chap
112
+ dummy_chapter = @chap
113
+ end
110
114
  dummy_loc = Location.new('', StringIO.new)
111
115
  b.bind(ReVIEW::Compiler.new(b), dummy_chapter, dummy_loc)
112
116
  b.compile_inline(line)
@@ -1,3 +1,3 @@
1
1
  module ReVIEW
2
- VERSION = '4.0.0'.freeze
2
+ VERSION = '4.1.0'.freeze
3
3
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2016-2018 Masayoshi Takahashi, Masanori Kado, Kenshi Muto
1
+ # Copyright (c) 2016-2020 Masayoshi Takahashi, Masanori Kado, Kenshi Muto
2
2
  #
3
3
  # This program is free software.
4
4
  # You can distribute or modify this program under the terms of
@@ -50,6 +50,7 @@ module ReVIEW
50
50
  def parse_opts(args)
51
51
  cmd_config = {}
52
52
  opts = OptionParser.new
53
+ @buildonly = nil
53
54
 
54
55
  opts.banner = 'Usage: review-webmaker [option] configfile'
55
56
  opts.version = ReVIEW::VERSION
@@ -58,6 +59,7 @@ module ReVIEW
58
59
  exit 0
59
60
  end
60
61
  opts.on('--ignore-errors', 'Ignore review-compile errors.') { cmd_config['ignore-errors'] = true }
62
+ opts.on('-y', '--only file1,file2,...', 'Build only specified files.') { |v| @buildonly = v.split(/\s*,\s*/).map { |m| m.strip.sub(/\.re\Z/, '') } }
61
63
 
62
64
  opts.parse!(args)
63
65
  if args.size != 1
@@ -186,6 +188,11 @@ module ReVIEW
186
188
  end
187
189
  id = File.basename(filename).sub(/\.re\Z/, '')
188
190
 
191
+ if @buildonly && !@buildonly.include?(id)
192
+ warn "skip #{id}.re"
193
+ return
194
+ end
195
+
189
196
  htmlfile = "#{id}.#{@config['htmlext']}"
190
197
 
191
198
  if @config['params'].present?