review 3.1.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
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']