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
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # Copyright (c) 2014-2017 Minero Aoki, Kenshi Muto
3
+ # Copyright (c) 2014-2019 Minero Aoki, Kenshi Muto
4
4
  # 2003-2014 Minero Aoki
5
5
  #
6
6
  # This program is free software.
@@ -37,8 +37,8 @@ def main
37
37
  end
38
38
  begin
39
39
  opts.parse!
40
- rescue OptionParser::ParseError => err
41
- @logger.error err.message
40
+ rescue OptionParser::ParseError => e
41
+ @logger.error e.message
42
42
  $stderr.puts opts.help
43
43
  exit 1
44
44
  end
@@ -70,9 +70,9 @@ def main
70
70
  end
71
71
  puts '============================='
72
72
  print_volume book.volume # puts "Total #{book.volume}"
73
- rescue ReVIEW::ApplicationError, Errno::ENOENT => err
73
+ rescue ReVIEW::ApplicationError, Errno::ENOENT => e
74
74
  raise if $DEBUG
75
- @logger.error "#{File.basename($PROGRAM_NAME)}: #{err.message}"
75
+ @logger.error "#{File.basename($PROGRAM_NAME)}: #{e.message}"
76
76
  exit 1
77
77
  end
78
78
 
@@ -20,9 +20,9 @@ Re:VIEW フォーマットの文法について解説します。Re:VIEW フォ
20
20
  * 2行以上空けても、1行空きと同じ意味になります。
21
21
  * 空行せずに改行して段落の記述を続ける際、英文の単語間スペースについては考慮されないことに注意してください。Re:VIEW は各行を単純に連結するだけであり、TeX のように前後の単語を判断してスペースを入れるようなことはしません。
22
22
 
23
- ## 章・節・項・段(見出し)
23
+ ## 章・節・項・目・段(見出し)
24
24
 
25
- 章・節・項・段といった見出しは「`=`」「`==`」「`===`」「`====`」「`=====`」で表します。6 レベル以上は使えません。`=`のあとにはスペースを入れます。
25
+ 章・節・項・目といった見出しは「`=`」「`==`」「`===`」「`====`」「`=====`」で表します。7 レベル以上は使えません。`=`のあとにはスペースを入れます。
26
26
 
27
27
  例:
28
28
 
@@ -33,9 +33,11 @@ Re:VIEW フォーマットの文法について解説します。Re:VIEW フォ
33
33
 
34
34
  === 項のキャプション
35
35
 
36
- ==== 段のキャプション
36
+ ==== 目のキャプション
37
37
 
38
- ===== 小段のキャプション
38
+ ===== 段のキャプション
39
+
40
+ ====== 小段のキャプション
39
41
  ```
40
42
 
41
43
  見出しは行の先頭から始める必要があります。行頭に空白を入れると、ただの本文と見なされます。
@@ -24,7 +24,7 @@ Two empty lines or more are same as one empty line.
24
24
 
25
25
  ## Chapter, Section, Subsection (headings)
26
26
 
27
- Chapters, sections, subsections, subsubsections use `=`, `==`, `===`, `====`, `=====`.
27
+ Chapters, sections, subsections, subsubsections use `=`, `==`, `===`, `====`, `=====`, and `======`.
28
28
  You should add one or more spaces after `=`.
29
29
 
30
30
  Usage:
@@ -39,6 +39,8 @@ Usage:
39
39
  ==== 4th level
40
40
 
41
41
  ===== 5th level
42
+
43
+ ====== 6th level
42
44
  ```
43
45
 
44
46
  Headings should not have any spaces before title; if line head has space, it is as paragraph.
@@ -36,10 +36,9 @@ module EPUBMaker
36
36
  if @producer.config['coverimage']
37
37
  file = nil
38
38
  @producer.contents.each do |item|
39
- if !item.media.start_with?('image') || item.file !~ /#{@producer.config["coverimage"]}\Z/
39
+ if !item.media.start_with?('image') || item.file !~ /#{@producer.config['coverimage']}\Z/
40
40
  next
41
41
  end
42
-
43
42
  s << %Q( <meta name="cover" content="#{item.id}"/>\n)
44
43
  file = item.file
45
44
  break
@@ -39,7 +39,7 @@ module EPUBMaker
39
39
  if @producer.config[item].is_a?(Array)
40
40
  s << @producer.config.names_of(item).map { |i| %Q( <dc:#{item}>#{CGI.escapeHTML(i)}</dc:#{item}>\n) }.join
41
41
  else
42
- s << %Q( <dc:#{item}>#{CGI.escapeHTML(@producer.config.name_of(item))}</dc:#{item}>\n)
42
+ s << %Q( <dc:#{item}>#{CGI.escapeHTML(@producer.config.name_of(item).to_s)}</dc:#{item}>\n)
43
43
  end
44
44
  end
45
45
 
@@ -26,6 +26,7 @@ module EPUBMaker
26
26
  # Return opf file content.
27
27
  def opf
28
28
  @opf_metainfo = opf_metainfo
29
+ @opf_coverimage = opf_coverimage
29
30
  @opf_manifest = opf_manifest
30
31
  @opf_toc = opf_tocx
31
32
  @package_attrs = ''
@@ -192,7 +192,8 @@ module EPUBMaker
192
192
  current = Dir.pwd
193
193
  basedir ||= current
194
194
 
195
- new_tmpdir = tmpdir.nil? ? Dir.mktmpdir : tmpdir
195
+ # use Dir to solve a path for Windows (see #1011)
196
+ new_tmpdir = Dir[File.join(tmpdir.nil? ? Dir.mktmpdir : tmpdir)][0]
196
197
  if epubfile !~ %r{\A/}
197
198
  epubfile = "#{current}/#{epubfile}"
198
199
  end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2009-2018 Minero Aoki, Kenshi Muto
2
+ # Copyright (c) 2009-2019 Minero Aoki, Kenshi Muto
3
3
  # 2002-2008 Minero Aoki
4
4
  #
5
5
  # This program is free software.
@@ -266,8 +266,8 @@ module ReVIEW
266
266
  if File.file?(predef_file)
267
267
  mkpart_from_namelistfile(predef_file)
268
268
  end
269
- rescue FileNotFound => err
270
- raise FileNotFound, "preface #{err.message}"
269
+ rescue FileNotFound => e
270
+ raise FileNotFound, "preface #{e.message}"
271
271
  end
272
272
  end
273
273
 
@@ -283,8 +283,8 @@ module ReVIEW
283
283
  if File.file?(postdef_file)
284
284
  mkpart_from_namelistfile(postdef_file)
285
285
  end
286
- rescue FileNotFound => err
287
- raise FileNotFound, "postscript #{err.message}"
286
+ rescue FileNotFound => e
287
+ raise FileNotFound, "postscript #{e.message}"
288
288
  end
289
289
  end
290
290
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2008-2018 Minero Aoki, Kenshi Muto
1
+ # Copyright (c) 2008-2019 Minero Aoki, Kenshi Muto
2
2
  # 2002-2007 Minero Aoki
3
3
  #
4
4
  # This program is free software.
@@ -316,6 +316,7 @@ module ReVIEW
316
316
  if m.nil? || m[1].size > 10 # Ignore too deep index
317
317
  next
318
318
  end
319
+
319
320
  index = m[1].size - 2
320
321
 
321
322
  # column
@@ -335,7 +336,9 @@ module ReVIEW
335
336
 
336
337
  next unless index >= 0
337
338
  if indexs.size > (index + 1)
338
- indexs = indexs.take(index + 1)
339
+ unless %w[nonum notoc nodisp].include?(m[2])
340
+ indexs = indexs.take(index + 1)
341
+ end
339
342
  headlines = headlines.take(index + 1)
340
343
  end
341
344
  if indexs[index].nil?
@@ -343,9 +346,15 @@ module ReVIEW
343
346
  indexs[i] ||= 0
344
347
  end
345
348
  end
346
- indexs[index] += 1
347
- headlines[index] = m[3].present? ? m[3].strip : m[4].strip
348
- items.push Item.new(headlines.join('|'), indexs.dup, m[4].strip)
349
+
350
+ if %w[nonum notoc nodisp].include?(m[2])
351
+ headlines[index] = m[3].present? ? m[3].strip : m[4].strip
352
+ items.push Item.new(headlines.join('|'), nil, m[4].strip)
353
+ else
354
+ indexs[index] += 1
355
+ headlines[index] = m[3].present? ? m[3].strip : m[4].strip
356
+ items.push Item.new(headlines.join('|'), indexs.dup, m[4].strip)
357
+ end
349
358
  end
350
359
  new(items, chap)
351
360
  end
@@ -364,6 +373,10 @@ module ReVIEW
364
373
  end
365
374
 
366
375
  def number(id)
376
+ unless self[id].number
377
+ # when notoc
378
+ return ''
379
+ end
367
380
  n = @chap.number
368
381
  # XXX: remove magic number (move to lib/review/book/chapter.rb)
369
382
  if @chap.on_appendix? && @chap.number > 0 && @chap.number < 28
@@ -165,6 +165,7 @@ module ReVIEW
165
165
  rows.push(line.strip.split(/\t+/).map { |s| s.sub(/\A\./, '') })
166
166
  end
167
167
  rows = adjust_n_cols(rows)
168
+ error 'no rows in the table' if rows.empty?
168
169
 
169
170
  begin
170
171
  if caption.present?
@@ -173,7 +174,6 @@ module ReVIEW
173
174
  rescue KeyError
174
175
  error "no such table: #{id}"
175
176
  end
176
- return if rows.empty?
177
177
  table_begin rows.first.size
178
178
  if sepidx
179
179
  sepidx.times do
@@ -478,7 +478,9 @@ module ReVIEW
478
478
  def extract_chapter_id(chap_ref)
479
479
  m = /\A([\w+-]+)\|(.+)/.match(chap_ref)
480
480
  if m
481
- return [@book.contents.detect { |chap| chap.id == m[1] }, m[2]]
481
+ ch = @book.contents.detect { |chap| chap.id == m[1] }
482
+ raise KeyError unless ch
483
+ return [ch, m[2]]
482
484
  end
483
485
  [@chapter, chap_ref]
484
486
  end
@@ -614,6 +616,10 @@ EOTGNUPLOT
614
616
  end
615
617
  end
616
618
 
619
+ def over_secnolevel?(n)
620
+ @book.config['secnolevel'] >= n.to_s.split('.').size
621
+ end
622
+
617
623
  ## override TextUtils::detab
618
624
  def detab(str, num = nil)
619
625
  if num
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2009-2018 Minero Aoki, Kenshi Muto
1
+ # Copyright (c) 2009-2019 Minero Aoki, Kenshi Muto
2
2
  # Copyright (c) 2002-2007 Minero Aoki
3
3
  #
4
4
  # This program is free software.
@@ -9,32 +9,10 @@
9
9
  require 'review/extentions'
10
10
  require 'review/preprocessor'
11
11
  require 'review/exception'
12
+ require 'review/location'
12
13
  require 'strscan'
13
14
 
14
15
  module ReVIEW
15
- class Location
16
- def initialize(filename, f)
17
- @filename = filename
18
- @f = f
19
- end
20
-
21
- attr_reader :filename
22
-
23
- def lineno
24
- @f.lineno
25
- end
26
-
27
- def string
28
- begin
29
- "#{@filename}:#{@f.lineno}"
30
- rescue
31
- "#{@filename}:nil"
32
- end
33
- end
34
-
35
- alias_method :to_s, :string
36
- end
37
-
38
16
  class Compiler
39
17
  def initialize(strategy)
40
18
  @strategy = strategy
@@ -380,11 +358,10 @@ module ReVIEW
380
358
  @strategy.ul_item_begin buf
381
359
  elsif level < current_level # down
382
360
  level_diff = current_level - level
383
- level = current_level
384
- (1..(level_diff - 1)).to_a.reverse_each do |i|
385
- @strategy.ul_begin { i }
386
- @strategy.ul_item_begin []
361
+ if level_diff != 1
362
+ error 'too many *.'
387
363
  end
364
+ level = current_level
388
365
  @strategy.ul_begin { level }
389
366
  @strategy.ul_item_begin buf
390
367
  elsif level > current_level # up
@@ -501,8 +478,8 @@ module ReVIEW
501
478
  end
502
479
  begin
503
480
  syntax.check_args args
504
- rescue CompileError => err
505
- error err.message
481
+ rescue CompileError => e
482
+ error e.message
506
483
  args = ['(NoArgument)'] * syntax.min_argc
507
484
  end
508
485
  if syntax.block_allowed?
@@ -564,8 +541,8 @@ module ReVIEW
564
541
  result << @strategy.nofunc_text(revert_replace_fence(words.shift))
565
542
  end
566
543
  result
567
- rescue => err
568
- error err.message
544
+ rescue => e
545
+ error e.message
569
546
  end
570
547
  public :text # called from strategy
571
548
 
@@ -578,8 +555,8 @@ module ReVIEW
578
555
  raise "strategy does not support inline op: @<#{op}>"
579
556
  end
580
557
  @strategy.__send__("inline_#{op}", arg)
581
- rescue => err
582
- error err.message
558
+ rescue => e
559
+ error e.message
583
560
  @strategy.nofunc_text(str)
584
561
  end
585
562
 
@@ -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
@@ -9,6 +9,8 @@
9
9
  require 'zip'
10
10
  require 'rexml/document'
11
11
  require 'cgi'
12
+ require 'optparse'
13
+ require 'review/version'
12
14
 
13
15
  module ReVIEW
14
16
  class Epub2Html
@@ -17,13 +19,26 @@ module ReVIEW
17
19
  end
18
20
 
19
21
  def execute(*args)
20
- if args[0].nil? || !File.exist?(args[0])
21
- STDERR.puts <<EOT
22
- Usage: #{File.basename($PROGRAM_NAME)} EPUBfile [file_for_head_and_foot] > HTMLfile
22
+ opts = OptionParser.new
23
+
24
+ opts.banner = <<EOT
25
+ Usage: review-epub2html [options] EPUBfile [file_for_head_and_foot] > HTMLfile
23
26
  file_for_head_and_foot: HTML file to extract header and footer area.
24
27
  This file must be contained in the EPUB.
25
28
  If omitted, the first found file is used.
29
+
26
30
  EOT
31
+ opts.version = ReVIEW::VERSION
32
+ opts.on('--help', 'Prints this message and quit.') do
33
+ puts opts.help
34
+ exit 0
35
+ end
36
+ opts.on('--inline-footnote', 'Embed footnote blocks in paragraph.') { @inline_footnote = true }
37
+
38
+ opts.parse!(args)
39
+
40
+ if args[0].nil? || !File.exist?(args[0])
41
+ puts opts.help
27
42
  exit 1
28
43
  end
29
44
 
@@ -36,6 +51,7 @@ EOT
36
51
  @htmls = {}
37
52
  @head = nil
38
53
  @tail = nil
54
+ @inline_footnote = nil
39
55
  end
40
56
 
41
57
  def parse_epub(epubname)
@@ -99,6 +115,23 @@ EOT
99
115
  e.attributes['href'] = "##{anc}"
100
116
  end
101
117
 
118
+ if @inline_footnote
119
+ # move footnotes to inline as same as LaTeX.
120
+ footnotes = {}
121
+
122
+ doc.each_element("//div[@class='footnote']") do |e|
123
+ e.name = 'span'
124
+ e.attributes.delete('epub:type')
125
+ footnotes[e.attributes['id']] = e
126
+ e.remove
127
+ end
128
+
129
+ doc.each_element("//a[@class='noteref']") do |e|
130
+ e.parent.insert_after(e, footnotes[e.attributes['href'].sub('#', '')])
131
+ e.remove
132
+ end
133
+ end
134
+
102
135
  doc.to_s.
103
136
  sub(/.*(<body.*?>)/m, %Q(<section id="#{sanitize(fname)}">)).
104
137
  sub(%r{(</body>).*}m, '</section>')
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2010-2018 Kenshi Muto and Masayoshi Takahashi
1
+ # Copyright (c) 2010-2019 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
@@ -64,7 +64,45 @@ module ReVIEW
64
64
  @producer.load(yamlfile)
65
65
  @config = @producer.config
66
66
  @config.maker = 'epubmaker'
67
+ end
68
+
69
+ def self.execute(*args)
70
+ self.new.execute(*args)
71
+ end
72
+
73
+ def parse_opts(args)
74
+ cmd_config = {}
75
+ opts = OptionParser.new
76
+
77
+ opts.banner = 'Usage: review-epubmaker [options] configfile [export_filename]'
78
+ opts.version = ReVIEW::VERSION
79
+ opts.on('--help', 'Prints this message and quit.') do
80
+ puts opts.help
81
+ exit 0
82
+ end
83
+ opts.on('--[no-]debug', 'Keep temporary files.') { |debug| cmd_config['debug'] = debug }
84
+
85
+ opts.parse!(args)
86
+ if args.size < 1 || args.size > 2
87
+ puts opts.help
88
+ exit 0
89
+ end
90
+
91
+ [cmd_config, args[0], args[1]]
92
+ end
93
+
94
+ def execute(*args)
95
+ @config = ReVIEW::Configure.values
96
+ @config.maker = 'epubmaker'
97
+ cmd_config, yamlfile, exportfile = parse_opts(args)
98
+ error "#{yamlfile} not found." unless File.exist?(yamlfile)
99
+
100
+ load_yaml(yamlfile)
101
+ @config.deep_merge!(cmd_config)
67
102
  update_log_level
103
+ log("Loaded yaml file (#{yamlfile}).")
104
+
105
+ produce(yamlfile, exportfile)
68
106
  end
69
107
 
70
108
  def update_log_level
@@ -89,7 +127,6 @@ module ReVIEW
89
127
  end
90
128
 
91
129
  def produce(yamlfile, bookname = nil)
92
- load_yaml(yamlfile)
93
130
  I18n.setup(@config['language'])
94
131
  bookname ||= @config['bookname']
95
132
  booktmpname = "#{bookname}-epub"
@@ -99,7 +136,7 @@ module ReVIEW
99
136
  rescue ReVIEW::ConfigError => e
100
137
  warn e.message
101
138
  end
102
- log("Loaded yaml file (#{yamlfile}). I will produce #{bookname}.epub.")
139
+ log("#{bookname}.epub will be created.")
103
140
 
104
141
  FileUtils.rm_f("#{bookname}.epub")
105
142
  if @config['debug']