review 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.rubocop.yml +293 -6
  4. data/.rubocop_todo.yml +3 -608
  5. data/.travis.yml +6 -13
  6. data/README.md +5 -3
  7. data/Rakefile +6 -6
  8. data/bin/review-catalog-converter +2 -2
  9. data/bin/review-check +1 -1
  10. data/bin/review-compile +1 -2
  11. data/bin/review-init +6 -3
  12. data/bin/review-validate +3 -3
  13. data/bin/review-vol +2 -1
  14. data/doc/NEWS.ja.md +138 -25
  15. data/doc/NEWS.md +137 -25
  16. data/doc/config.yml.sample +2 -2
  17. data/doc/config.yml.sample-simple +1 -1
  18. data/doc/format.ja.md +86 -5
  19. data/doc/format.md +67 -2
  20. data/doc/makeindex.ja.md +95 -0
  21. data/doc/makeindex.md +97 -0
  22. data/doc/sample.css +214 -0
  23. data/lib/epubmaker.rb +6 -6
  24. data/lib/epubmaker/epubcommon.rb +19 -47
  25. data/lib/epubmaker/epubv2.rb +3 -1
  26. data/lib/epubmaker/epubv3.rb +4 -26
  27. data/lib/epubmaker/producer.rb +46 -46
  28. data/lib/epubmaker/zip_exporter.rb +86 -0
  29. data/lib/review/book/base.rb +13 -15
  30. data/lib/review/book/chapter.rb +2 -1
  31. data/lib/review/book/compilable.rb +9 -9
  32. data/lib/review/book/image_finder.rb +13 -13
  33. data/lib/review/book/index.rb +2 -2
  34. data/lib/review/book/volume.rb +2 -2
  35. data/lib/review/builder.rb +57 -1
  36. data/lib/review/catalog.rb +2 -2
  37. data/lib/review/compiler.rb +15 -7
  38. data/lib/review/configure.rb +11 -0
  39. data/lib/review/epubmaker.rb +403 -401
  40. data/lib/review/ewbbuilder.rb +16 -16
  41. data/lib/review/htmlbuilder.rb +42 -58
  42. data/lib/review/htmltoc.rb +1 -1
  43. data/lib/review/htmlutils.rb +50 -4
  44. data/lib/review/i18n.rb +2 -2
  45. data/lib/review/idgxmlbuilder.rb +30 -47
  46. data/lib/review/latexbuilder.rb +86 -41
  47. data/lib/review/latexutils.rb +19 -19
  48. data/lib/review/markdownbuilder.rb +16 -4
  49. data/lib/review/md2inaobuilder.rb +0 -9
  50. data/lib/review/pdfmaker.rb +91 -48
  51. data/lib/review/preprocessor.rb +1 -1
  52. data/lib/review/rstbuilder.rb +763 -0
  53. data/lib/review/sec_counter.rb +7 -9
  54. data/lib/review/tocparser.rb +3 -3
  55. data/lib/review/tocprinter.rb +5 -5
  56. data/lib/review/topbuilder.rb +48 -56
  57. data/lib/review/version.rb +1 -1
  58. data/lib/review/webmaker.rb +6 -7
  59. data/review.gemspec +1 -0
  60. data/templates/latex/layout.tex.erb +27 -2
  61. data/test/assets/test_template.tex +10 -1
  62. data/test/book_test_helper.rb +1 -2
  63. data/test/run_test.rb +10 -0
  64. data/test/sample-book/src/style.css +215 -0
  65. data/test/sample-book/src/vendor/jumoline/lppl.txt +416 -0
  66. data/test/test_book.rb +0 -1
  67. data/test/test_catalog.rb +1 -0
  68. data/test/test_converter.rb +1 -1
  69. data/test/test_epub3maker.rb +44 -51
  70. data/test/test_epubmaker.rb +82 -38
  71. data/test/test_epubmaker_cmd.rb +1 -1
  72. data/test/test_extentions_hash.rb +8 -1
  73. data/test/test_htmlbuilder.rb +411 -18
  74. data/test/test_i18n.rb +17 -0
  75. data/test/test_idgxmlbuilder.rb +88 -3
  76. data/test/test_image_finder.rb +18 -0
  77. data/test/test_index.rb +2 -0
  78. data/test/test_latexbuilder.rb +96 -8
  79. data/test/test_makerhelper.rb +2 -2
  80. data/test/test_markdownbuilder.rb +22 -1
  81. data/test/test_md2inaobuilder.rb +0 -5
  82. data/test/test_pdfmaker.rb +54 -36
  83. data/test/test_pdfmaker_cmd.rb +1 -1
  84. data/test/test_rstbuilder.rb +356 -0
  85. data/test/test_textutils.rb +14 -4
  86. data/test/test_topbuilder.rb +23 -4
  87. data/test/test_zip_exporter.rb +113 -0
  88. metadata +28 -2
@@ -0,0 +1,86 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright (c) 2010-2016 Kenshi Muto and Masayoshi Takahashi
4
+ #
5
+ # This program is free software.
6
+ # You can distribute or modify this program under the terms of
7
+ # the GNU LGPL, Lesser General Public License version 2.1.
8
+ # For details of the GNU LGPL, see the file "COPYING".
9
+ #
10
+
11
+ require 'pathname'
12
+ begin
13
+ require 'zip'
14
+ rescue LoadError
15
+ ## I cannot find rubyzip library, so I use external zip command.
16
+ warn "rubyzip not found, so use external zip command"
17
+ end
18
+
19
+ module EPUBMaker
20
+
21
+ ##
22
+ # Export into zip file for EPUB producer.
23
+ #
24
+ class ZipExporter
25
+
26
+ attr_reader :tmpdir
27
+
28
+ def initialize(tmpdir, params)
29
+ @tmpdir = tmpdir
30
+ @params = params
31
+ end
32
+
33
+ def export_zip(epubfile)
34
+ if defined?(Zip)
35
+ export_zip_rubyzip(epubfile)
36
+ else
37
+ export_zip_extcmd(epubfile)
38
+ end
39
+ end
40
+
41
+ def export_zip_extcmd(epubfile)
42
+ stage1 = @params["epubmaker"]["zip_stage1"].to_s.split
43
+ path1 = stage1[0] || "zip"
44
+ opt1 = stage1[1] || "-0Xq"
45
+ stage2 = @params["epubmaker"]["zip_stage2"].to_s.split
46
+ path2 = stage2[0] || "zip"
47
+ opt2 = stage2[1] || "-Xr9Dq"
48
+
49
+ Dir.chdir(tmpdir) do |d|
50
+ system(path1, opt1, epubfile, "mimetype")
51
+ addpath = @params["epubmaker"]["zip_addpath"]
52
+ if addpath
53
+ system(path2, opt2, epubfile, "META-INF", "OEBPS", addpath)
54
+ else
55
+ system(path2, opt2, epubfile, "META-INF", "OEBPS")
56
+ end
57
+ end
58
+ end
59
+
60
+ def export_zip_rubyzip(epubfile)
61
+ Dir.chdir(tmpdir) do |d|
62
+ Zip::OutputStream.open(epubfile) do |epub|
63
+ root_pathname = Pathname.new(tmpdir)
64
+ # relpath = Pathname.new(File.join(tmpdir,'mimetype')).relative_path_from(root_pathname)
65
+ epub.put_next_entry('mimetype', nil, nil, Zip::Entry::STORED)
66
+ epub << "application/epub+zip"
67
+
68
+ export_zip_rubyzip_addpath(epub, File.join(tmpdir,'META-INF'), root_pathname)
69
+ export_zip_rubyzip_addpath(epub, File.join(tmpdir,'OEBPS'), root_pathname)
70
+ if @params["zip_addpath"].present?
71
+ export_zip_rubyzip_addpath(epub, File.join(tmpdir, @params["zip_addpath"]), root_pathname)
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ def export_zip_rubyzip_addpath(epub, dirname, rootdir)
78
+ Dir[File.join(dirname,'**','**')].each do |path|
79
+ next if File.directory?(path)
80
+ relpath = Pathname.new(path).relative_path_from(rootdir)
81
+ epub.put_next_entry(relpath)
82
+ epub << File.binread(path)
83
+ end
84
+ end
85
+ end
86
+ end
@@ -15,6 +15,9 @@ module ReVIEW
15
15
  class Base
16
16
 
17
17
  attr_writer :config
18
+ attr_writer :parts
19
+ attr_writer :catalog
20
+ attr_reader :basedir
18
21
 
19
22
  def self.load_default
20
23
  warn 'Book::Base.load_default() is obsoleted. Use Book::Base.load().'
@@ -51,6 +54,7 @@ module ReVIEW
51
54
  @config = ReVIEW::Configure.values
52
55
  @catalog = nil
53
56
  @read_part = nil
57
+ @warn_old_files = {} # XXX for checking CHAPS, PREDEF, POSTDEF
54
58
  end
55
59
 
56
60
  def bib_file
@@ -99,10 +103,6 @@ module ReVIEW
99
103
  @parts ||= read_parts()
100
104
  end
101
105
 
102
- def parts=(parts)
103
- @parts = parts
104
- end
105
-
106
106
  def parts_in_file
107
107
  parts.find_all{|part|
108
108
  part if part.present? and part.file?
@@ -198,10 +198,6 @@ module ReVIEW
198
198
  @catalog
199
199
  end
200
200
 
201
- def catalog=(catalog)
202
- @catalog = catalog
203
- end
204
-
205
201
  def read_CHAPS
206
202
  if catalog
207
203
  catalog.chaps
@@ -298,10 +294,6 @@ module ReVIEW
298
294
  end
299
295
  end
300
296
 
301
- def basedir
302
- @basedir
303
- end
304
-
305
297
  private
306
298
 
307
299
  def read_parts
@@ -344,9 +336,9 @@ module ReVIEW
344
336
  end
345
337
  end
346
338
 
347
- chap = read_CHAPS()\
348
- .strip.lines.map {|line| line.strip }.join("\n").split(/\n{2,}/)\
349
- .map {|part_chunk|
339
+ chap = read_CHAPS().
340
+ strip.lines.map {|line| line.strip }.join("\n").split(/\n{2,}/).
341
+ map {|part_chunk|
350
342
  chaps = part_chunk.split.map {|chapid|
351
343
  Chapter.new(self, (num += 1), chapid, "#{@basedir}/#{chapid}")
352
344
  }
@@ -396,6 +388,12 @@ module ReVIEW
396
388
  end
397
389
 
398
390
  def read_FILE(filename)
391
+ if !@warn_old_files[filename]
392
+ @warn_old_files[filename] = true
393
+ if !caller().any?{|item| item =~ %r|/review/test/test_|}
394
+ warn "!!! #{filename} is obsoleted. please use catalog.yml."
395
+ end
396
+ end
399
397
  res = ""
400
398
  File.open("#{@basedir}/#{filename}", 'r:BOM|utf-8') do |f|
401
399
  while line = f.gets
@@ -83,7 +83,7 @@ module ReVIEW
83
83
  return "#{@number}" if @number < 1 || @number > 27
84
84
  if @book.config["appendix_format"]
85
85
  raise ReVIEW::ConfigError,
86
- "'appendix_format:' in config.yml is obsoleted."
86
+ "'appendix_format:' in config.yml is obsoleted."
87
87
  end
88
88
 
89
89
  i18n_appendix = I18n.get("appendix")
@@ -121,6 +121,7 @@ module ReVIEW
121
121
  end
122
122
 
123
123
  private
124
+
124
125
  def on_FILE?(contents)
125
126
  contents.lines.map(&:strip).include?("#{id()}#{@book.ext()}")
126
127
  end
@@ -2,7 +2,7 @@
2
2
  # $Id: book.rb 4315 2009-09-02 04:15:24Z kmuto $
3
3
  #
4
4
  # Copyright (c) 2002-2008 Minero Aoki
5
- # 2009 Minero Aoki, Kenshi Muto
5
+ # 2009-2017 Minero Aoki, Kenshi Muto
6
6
  #
7
7
  # This program is free software.
8
8
  # You can distribute or modify this program under the terms of
@@ -118,29 +118,29 @@ module ReVIEW
118
118
  def numberless_image_index
119
119
  @numberless_image_index ||=
120
120
  NumberlessImageIndex.parse(lines(), id(),
121
- "#{book.basedir}/#{@book.image_dir}",
122
- @book.image_types, @book.config['builder'])
121
+ "#{book.basedir}/#{@book.config['imagedir']}",
122
+ @book.image_types, @book.config['builder'])
123
123
  end
124
124
 
125
125
  def image_index
126
126
  @image_index ||= ImageIndex.parse(lines(), id(),
127
- "#{book.basedir}/#{@book.image_dir}",
128
- @book.image_types, @book.config['builder'])
127
+ "#{book.basedir}/#{@book.config['imagedir']}",
128
+ @book.image_types, @book.config['builder'])
129
129
  @image_index
130
130
  end
131
131
 
132
132
  def icon_index
133
133
  @icon_index ||= IconIndex.parse(lines(), id(),
134
- "#{book.basedir}/#{@book.image_dir}",
135
- @book.image_types, @book.config['builder'])
134
+ "#{book.basedir}/#{@book.config['imagedir']}",
135
+ @book.image_types, @book.config['builder'])
136
136
  @icon_index
137
137
  end
138
138
 
139
139
  def indepimage_index
140
140
  @indepimage_index ||=
141
141
  IndepImageIndex.parse(lines(), id(),
142
- "#{book.basedir}/#{@book.image_dir}",
143
- @book.image_types, @book.config['builder'])
142
+ "#{book.basedir}/#{@book.config['imagedir']}",
143
+ @book.image_types, @book.config['builder'])
144
144
  end
145
145
 
146
146
  def bibpaper(id)
@@ -22,7 +22,7 @@ module ReVIEW
22
22
  end
23
23
 
24
24
  def get_entries
25
- Dir.glob(File.join(@basedir, "**/*.*"))
25
+ Dir.glob(File.join(@basedir, "**{,/*/**}/*.*")).uniq
26
26
  end
27
27
 
28
28
  def add_entry(path)
@@ -46,23 +46,23 @@ module ReVIEW
46
46
 
47
47
  def target_list(id)
48
48
  [
49
- # 1. <basedir>/<builder>/<chapid>/<id>.<ext>
50
- "#{@basedir}/#{@builder}/#{@chapid}/#{id}",
49
+ # 1. <basedir>/<builder>/<chapid>/<id>.<ext>
50
+ "#{@basedir}/#{@builder}/#{@chapid}/#{id}",
51
51
 
52
- # 2. <basedir>/<builder>/<chapid>-<id>.<ext>
53
- "#{@basedir}/#{@builder}/#{@chapid}-#{id}",
52
+ # 2. <basedir>/<builder>/<chapid>-<id>.<ext>
53
+ "#{@basedir}/#{@builder}/#{@chapid}-#{id}",
54
54
 
55
- # 3. <basedir>/<builder>/<id>.<ext>
56
- "#{@basedir}/#{@builder}/#{id}",
55
+ # 3. <basedir>/<builder>/<id>.<ext>
56
+ "#{@basedir}/#{@builder}/#{id}",
57
57
 
58
- # 4. <basedir>/<chapid>/<id>.<ext>
59
- "#{@basedir}/#{@chapid}/#{id}",
58
+ # 4. <basedir>/<chapid>/<id>.<ext>
59
+ "#{@basedir}/#{@chapid}/#{id}",
60
60
 
61
- # 5. <basedir>/<chapid>-<id>.<ext>
62
- "#{@basedir}/#{@chapid}-#{id}",
61
+ # 5. <basedir>/<chapid>-<id>.<ext>
62
+ "#{@basedir}/#{@chapid}-#{id}",
63
63
 
64
- # 6. <basedir>/<id>.<ext>
65
- "#{@basedir}/#{id}"
64
+ # 6. <basedir>/<id>.<ext>
65
+ "#{@basedir}/#{id}"
66
66
  ]
67
67
  end
68
68
 
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  #
3
3
  # Copyright (c) 2002-2007 Minero Aoki
4
- # 2008-2009 Minero Aoki, Kenshi Muto
4
+ # 2008-2017 Minero Aoki, Kenshi Muto
5
5
  #
6
6
  # This program is free software.
7
7
  # You can distribute or modify this program under the terms of
@@ -58,7 +58,7 @@ module ReVIEW
58
58
  @index.fetch(id)
59
59
  rescue
60
60
  if @index.keys.map{|i| i.split(/\|/).last }.flatten. # unfold all ids
61
- reduce(Hash.new(0)){|h, i| h[i] += 1; h}. # number of occurrences
61
+ each_with_object(Hash.new(0)){|i, h| h[i] += 1}. # number of occurrences
62
62
  select{|k, v| k == id && v > 1 }.present? # detect duplicated
63
63
  raise KeyError, "key '#{id}' is ambiguous for #{self.class}"
64
64
  end
@@ -58,8 +58,8 @@ module ReVIEW
58
58
 
59
59
  def +(other)
60
60
  Volume.new(@bytes + other.bytes,
61
- @chars + other.chars,
62
- @lines + other.lines)
61
+ @chars + other.chars,
62
+ @lines + other.lines)
63
63
  end
64
64
 
65
65
  end
@@ -25,6 +25,7 @@ module ReVIEW
25
25
  def pre_paragraph
26
26
  nil
27
27
  end
28
+
28
29
  def post_paragraph
29
30
  nil
30
31
  end
@@ -46,6 +47,7 @@ module ReVIEW
46
47
  @output = StringIO.new
47
48
  @book = @chapter.book if @chapter.present?
48
49
  @tabwidth = nil
50
+ @tsize = nil
49
51
  if @book && @book.config && @book.config["tabwidth"]
50
52
  @tabwidth = @book.config["tabwidth"]
51
53
  end
@@ -83,6 +85,21 @@ module ReVIEW
83
85
  end
84
86
  private :headline_prefix
85
87
 
88
+ ## for //firstlinenum[num]
89
+ def firstlinenum(num)
90
+ @first_line_num = num.to_i
91
+ end
92
+
93
+ def get_line_num
94
+ if !@first_line_num
95
+ return 1
96
+ end
97
+ line_num = @first_line_num
98
+ @first_line_num = nil
99
+
100
+ line_num
101
+ end
102
+
86
103
  def list(lines, id, caption, lang = nil)
87
104
  begin
88
105
  list_header id, caption, lang
@@ -327,6 +344,20 @@ module ReVIEW
327
344
  end
328
345
  end
329
346
 
347
+ def embed(lines, arg = nil)
348
+ if arg
349
+ builders = arg.gsub(/^\s*\|/, "").gsub(/\|\s*$/, "").gsub(/\s/, "").split(/,/)
350
+ c = target_name
351
+ if builders.include?(c)
352
+ print lines.join()
353
+ else
354
+ ""
355
+ end
356
+ else
357
+ print lines.join()
358
+ end
359
+ end
360
+
330
361
  def warn(msg)
331
362
  $stderr.puts "#{@location}: warning: #{msg}"
332
363
  end
@@ -350,7 +381,7 @@ module ReVIEW
350
381
  params.each do |param|
351
382
  if param =~ /\A.+?::/
352
383
  if param =~ /\A#{type}::/
353
- param.sub!(/\A#{type}::/, '')
384
+ param.sub!(/\A#{type}::/, '')
354
385
  else
355
386
  next
356
387
  end
@@ -435,6 +466,18 @@ module ReVIEW
435
466
  def ul_item_end
436
467
  end
437
468
 
469
+ def tsize(str)
470
+ if matched = str.match(/\A\|(.*?)\|(.*)/)
471
+ builders = matched[1].split(/,/).map{|i| i.gsub(/\s/, '') }
472
+ c = self.class.to_s.gsub(/ReVIEW::/, '').gsub(/Builder/, '').downcase
473
+ if builders.include?(c)
474
+ @tsize = matched[2]
475
+ end
476
+ else
477
+ @tsize = str
478
+ end
479
+ end
480
+
438
481
  def inline_raw(args)
439
482
  if matched = args.match(/\|(.*?)\|(.*)/)
440
483
  builders = matched[1].split(/,/).map{|i| i.gsub(/\s/, '') }
@@ -449,6 +492,19 @@ module ReVIEW
449
492
  end
450
493
  end
451
494
 
495
+ def inline_embed(args)
496
+ if matched = args.match(/\|(.*?)\|(.*)/)
497
+ builders = matched[1].split(/,/).map{|i| i.gsub(/\s/, '') }
498
+ if builders.include?(target_name)
499
+ matched[2]
500
+ else
501
+ ""
502
+ end
503
+ else
504
+ args
505
+ end
506
+ end
507
+
452
508
  ## override TextUtils::detab
453
509
  def detab(str, num = nil)
454
510
  if num
@@ -35,12 +35,12 @@ module ReVIEW
35
35
  if entry.is_a? Hash
36
36
  entry.keys
37
37
  end
38
- }.flatten.reject{|entry| entry.nil?}.join("\n")
38
+ }.flatten.compact.join("\n")
39
39
  end
40
40
 
41
41
  def parts_with_chaps
42
42
  return "" unless @yaml["CHAPS"]
43
- @yaml["CHAPS"].flatten.reject{|entry| entry.nil?}
43
+ @yaml["CHAPS"].flatten.compact
44
44
  end
45
45
 
46
46
  def appendix
@@ -161,6 +161,7 @@ module ReVIEW
161
161
  defblock :tip, 0..1
162
162
  defblock :box, 0..1
163
163
  defblock :comment, 0..1, true
164
+ defblock :embed, 0..1
164
165
 
165
166
  defsingle :footnote, 2
166
167
  defsingle :noindent, 0
@@ -175,6 +176,7 @@ module ReVIEW
175
176
  defsingle :tsize, 1
176
177
  defsingle :include, 1
177
178
  defsingle :olnum, 1
179
+ defsingle :firstlinenum, 1
178
180
 
179
181
  definline :chapref
180
182
  definline :chap
@@ -229,11 +231,12 @@ module ReVIEW
229
231
  definline :comment
230
232
  definline :include
231
233
  definline :tcy
234
+ definline :embed
232
235
 
233
236
  private
234
237
 
235
238
  def do_compile
236
- f = LineInput.new(Preprocessor::Strip.new(StringIO.new(@chapter.content)))
239
+ f = LineInput.new(StringIO.new(@chapter.content))
237
240
  @strategy.bind self, @chapter, Location.new(@chapter.basename, f)
238
241
  tagged_section_init
239
242
  while f.next?
@@ -265,7 +268,7 @@ module ReVIEW
265
268
  warn "`//' seen but is not valid command: #{line.strip.inspect}"
266
269
  if block_open?(line)
267
270
  warn "skipping block..."
268
- read_block(f)
271
+ read_block(f, false)
269
272
  end
270
273
  else
271
274
  if f.peek.strip.empty?
@@ -431,8 +434,9 @@ module ReVIEW
431
434
  def read_command(f)
432
435
  line = f.gets
433
436
  name = line.slice(/[a-z]+/).to_sym
437
+ ignore_inline = (name == :embed)
434
438
  args = parse_args(line.sub(%r<\A//[a-z]+>, '').rstrip.chomp('{'), name)
435
- lines = block_open?(line) ? read_block(f) : nil
439
+ lines = block_open?(line) ? read_block(f, ignore_inline) : nil
436
440
  return name, args, lines
437
441
  end
438
442
 
@@ -440,12 +444,16 @@ module ReVIEW
440
444
  line.rstrip[-1,1] == '{'
441
445
  end
442
446
 
443
- def read_block(f)
447
+ def read_block(f, ignore_inline)
444
448
  head = f.lineno
445
449
  buf = []
446
450
  f.until_match(%r<\A//\}>) do |line|
447
- unless line =~ /\A\#@/
448
- buf.push text(line.rstrip)
451
+ if ignore_inline
452
+ buf.push line
453
+ else
454
+ unless line =~ /\A\#@/
455
+ buf.push text(line.rstrip)
456
+ end
449
457
  end
450
458
  end
451
459
  unless %r<\A//\}> =~ f.peek
@@ -523,7 +531,7 @@ module ReVIEW
523
531
  end
524
532
  result = @strategy.nofunc_text(words.shift)
525
533
  until words.empty?
526
- result << compile_inline(words.shift.gsub(/\\\}/, '}'))
534
+ result << compile_inline(words.shift.gsub(/\\\}/, '}').gsub(/\\\\/, '\\'))
527
535
  result << @strategy.nofunc_text(words.shift)
528
536
  end
529
537
  result