review 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +36 -0
  3. data/.rubocop.yml +1 -0
  4. data/ChangeLog +102 -0
  5. data/README.rdoc +2 -2
  6. data/bin/review-check +18 -16
  7. data/bin/review-compile +49 -42
  8. data/bin/review-epubmaker +23 -993
  9. data/bin/review-epubmaker-legacy +1024 -0
  10. data/bin/review-index +17 -15
  11. data/bin/review-init +39 -9
  12. data/bin/review-pdfmaker +124 -89
  13. data/bin/review-preproc +16 -14
  14. data/bin/review-vol +17 -15
  15. data/debian/docs +1 -1
  16. data/doc/catalog.rdoc +34 -0
  17. data/doc/format.rdoc +16 -2
  18. data/doc/libepubmaker/{config.yaml → config.yml} +63 -19
  19. data/doc/quickstart.rdoc +1 -1
  20. data/doc/{sample.yaml → sample.yml} +0 -0
  21. data/lib/epubmaker.rb +1 -1
  22. data/lib/epubmaker/content.rb +9 -1
  23. data/lib/epubmaker/epubv2.rb +59 -7
  24. data/lib/epubmaker/epubv3.rb +14 -9
  25. data/lib/epubmaker/producer.rb +68 -27
  26. data/lib/epubmaker/resource.rb +3 -1
  27. data/lib/lineinput.rb +2 -2
  28. data/lib/review/book/base.rb +125 -24
  29. data/lib/review/book/chapter.rb +42 -0
  30. data/lib/review/book/compilable.rb +23 -4
  31. data/lib/review/book/image_finder.rb +64 -0
  32. data/lib/review/book/index.rb +64 -50
  33. data/lib/review/book/page_metric.rb +1 -1
  34. data/lib/review/builder.rb +19 -12
  35. data/lib/review/catalog.rb +47 -0
  36. data/lib/review/compiler.rb +3 -2
  37. data/lib/review/configure.rb +5 -3
  38. data/lib/review/epubmaker.rb +130 -46
  39. data/lib/review/ewbbuilder.rb +27 -31
  40. data/lib/review/extentions/string.rb +4 -4
  41. data/lib/review/htmlbuilder.rb +140 -79
  42. data/lib/review/htmllayout.rb +26 -4
  43. data/lib/review/htmlutils.rb +20 -1
  44. data/lib/review/i18n.rb +5 -2
  45. data/lib/review/{i18n.yaml → i18n.yml} +4 -2
  46. data/lib/review/idgxmlbuilder.rb +65 -39
  47. data/lib/review/latexbuilder.rb +72 -24
  48. data/lib/review/latexutils.rb +3 -1
  49. data/lib/review/makerhelper.rb +8 -2
  50. data/lib/review/preprocessor.rb +20 -20
  51. data/lib/review/review.tex.erb +4 -0
  52. data/lib/review/sec_counter.rb +9 -11
  53. data/lib/review/tocparser.rb +2 -2
  54. data/lib/review/tocprinter.rb +12 -12
  55. data/lib/review/topbuilder.rb +15 -15
  56. data/lib/review/version.rb +1 -1
  57. data/lib/uuid.rb +7 -7
  58. data/review.gemspec +2 -2
  59. data/rubocop-todo.yml +443 -0
  60. data/test/sample-book/src/config.yml +2 -2
  61. data/test/sample-book/src/{main.css → style.css} +0 -0
  62. data/test/test_book.rb +46 -48
  63. data/test/test_book_chapter.rb +25 -13
  64. data/test/test_builder.rb +3 -3
  65. data/test/test_catalog.rb +107 -0
  66. data/test/test_epubmaker.rb +6 -6
  67. data/test/test_htmlbuilder.rb +160 -39
  68. data/test/test_htmlutils.rb +22 -0
  69. data/test/test_i18n.rb +2 -2
  70. data/test/test_idgxmlbuilder.rb +33 -47
  71. data/test/test_image_finder.rb +82 -0
  72. data/test/test_inaobuilder.rb +1 -1
  73. data/test/test_latexbuilder.rb +35 -39
  74. data/test/test_lineinput.rb +2 -2
  75. data/test/test_markdownbuilder.rb +2 -2
  76. data/test/test_topbuilder.rb +39 -23
  77. metadata +23 -14
  78. data/bin/review-epubmaker-ng +0 -23
@@ -15,6 +15,9 @@ module ReVIEW
15
15
  class Chapter
16
16
  include Compilable
17
17
 
18
+ ROMAN = %w[0 I II III IV V VI VII VIII IX X XI XII XIII XIV XV XVI XVII XVIII XIX XX XXI XXII XXIII XXIV XXV XXVI XXVII]
19
+ ALPHA = %w[0 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]
20
+
18
21
  def Chapter.intern_pathes(pathes)
19
22
  books = {}
20
23
  pathes.map {|path|
@@ -54,12 +57,51 @@ module ReVIEW
54
57
  @numberless_image_index = nil
55
58
  @indepimage_index = nil
56
59
  @headline_index = nil
60
+ @column_index = nil
57
61
  end
58
62
 
59
63
  def inspect
60
64
  "\#<#{self.class} #{@number} #{@path}>"
61
65
  end
62
66
 
67
+ def format_number(heading = true)
68
+ if on_PREDEF?
69
+ return "#{@number}"
70
+ end
71
+
72
+ if on_POSTDEF?
73
+ return "#{@number}" if @number < 1 || @number > 27
74
+
75
+ if @book.config["appendix_format"].blank?
76
+ type = "arabic"
77
+ else
78
+ type = @book.config["appendix_format"].downcase.strip
79
+ end
80
+
81
+ appendix = case type
82
+ when "roman"
83
+ ROMAN[@number]
84
+ when "alphabet", "alpha"
85
+ ALPHA[@number]
86
+ else
87
+ # nil, "arabic", etc...
88
+ "#{@number}"
89
+ end
90
+
91
+ if heading
92
+ return "#{I18n.t("appendix", appendix)}"
93
+ else
94
+ return "#{appendix}"
95
+ end
96
+ end
97
+
98
+ if heading
99
+ "#{I18n.t("chapter", @number)}"
100
+ else
101
+ "#{@number}"
102
+ end
103
+ end
104
+
63
105
  def on_CHAPS?
64
106
  on_FILE?(@book.read_CHAPS())
65
107
  end
@@ -32,16 +32,19 @@ module ReVIEW
32
32
  end
33
33
 
34
34
  def name
35
+ return nil unless @name
35
36
  File.basename(@name, '.*')
36
37
  end
37
38
 
38
- alias id name
39
+ alias_method :id, :name
39
40
 
40
41
  def title
41
- @title = ""
42
+ return @title if @title
43
+
44
+ @title = ''
42
45
  open {|f|
43
46
  f.each_line {|l|
44
- l = convert_inencoding(l, ReVIEW.book.param["inencoding"])
47
+ l = convert_inencoding(l, book.config["inencoding"])
45
48
  if l =~ /\A=+/
46
49
  @title = l.sub(/\A=+(\[.+?\])?(\{.+?\})?/, '').strip
47
50
  break
@@ -68,7 +71,7 @@ module ReVIEW
68
71
 
69
72
  def content
70
73
  @content = convert_inencoding(File.read(path()),
71
- ReVIEW.book.param["inencoding"])
74
+ book.config["inencoding"])
72
75
  rescue
73
76
  @content
74
77
  end
@@ -157,6 +160,22 @@ module ReVIEW
157
160
  def headline_index
158
161
  @headline_index ||= HeadlineIndex.parse(lines(), self)
159
162
  end
163
+
164
+ def column(id)
165
+ column_index()[id]
166
+ end
167
+
168
+ def column_index
169
+ @column_index ||= ColumnIndex.parse(lines())
170
+ end
171
+
172
+ def next_chapter
173
+ book.next_chapter(self)
174
+ end
175
+
176
+ def prev_chapter
177
+ book.prev_chapter(self)
178
+ end
160
179
  end
161
180
  end
162
181
  end
@@ -0,0 +1,64 @@
1
+ #
2
+ # Copyright (c) 2014 Minero Aoki, Kenshi Muto, Masayoshi Takahashi
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
+ # For details of LGPL, see the file "COPYING".
8
+ #
9
+
10
+ require 'review/extentions'
11
+ require 'review/exception'
12
+
13
+ module ReVIEW
14
+ module Book
15
+ class ImageFinder
16
+ def initialize(basedir, chapid, builder, exts)
17
+ @basedir = basedir
18
+ @chapid = chapid
19
+ @builder = builder
20
+ @exts = exts
21
+ @entries = get_entries()
22
+ end
23
+
24
+ def get_entries
25
+ Dir.glob(File.join(@basedir, "**/*.*"))
26
+ end
27
+
28
+ def find_path(id)
29
+ targets = target_list(id)
30
+ targets.each do |target|
31
+ @exts.each do |ext|
32
+ if @entries.include?("#{target}#{ext}")
33
+ return "#{target}#{ext}"
34
+ end
35
+ end
36
+ end
37
+ nil
38
+ end
39
+
40
+ def target_list(id)
41
+ [
42
+ # 1. <basedir>/<builder>/<chapid>/<id>.<ext>
43
+ "#{@basedir}/#{@builder}/#{@chapid}/#{id}",
44
+
45
+ # 2. <basedir>/<builder>/<chapid>-<id>.<ext>
46
+ "#{@basedir}/#{@builder}/#{@chapid}-#{id}",
47
+
48
+ # 3. <basedir>/<builder>/<id>.<ext>
49
+ "#{@basedir}/#{@builder}/#{id}",
50
+
51
+ # 4. <basedir>/<chapid>/<id>.<ext>
52
+ "#{@basedir}/#{@chapid}/#{id}",
53
+
54
+ # 5. <basedir>/<chapid>-<id>.<ext>
55
+ "#{@basedir}/#{@chapid}-#{id}",
56
+
57
+ # 6. <basedir>/<id>.<ext>
58
+ "#{@basedir}/#{id}"
59
+ ]
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -11,6 +11,7 @@
11
11
 
12
12
  require 'review/extentions'
13
13
  require 'review/exception'
14
+ require 'review/book/image_finder'
14
15
 
15
16
  module ReVIEW
16
17
  module Book
@@ -49,12 +50,13 @@ module ReVIEW
49
50
  warn "warning: duplicate ID: #{i.id} (#{i})" unless @index[i.id].nil?
50
51
  @index[i.id] = i
51
52
  end
53
+ @image_finder = nil
52
54
  end
53
55
 
54
56
  def [](id)
55
57
  @index.fetch(id)
56
58
  rescue
57
- raise KeyError
59
+ raise KeyError, "not found key '#{id}' for #{self.class}"
58
60
  end
59
61
 
60
62
  def number(id)
@@ -78,17 +80,15 @@ module ReVIEW
78
80
 
79
81
  def number(id)
80
82
  chapter = @index.fetch(id)
81
- if chapter.on_CHAPS?
82
- "#{I18n.t("chapter", chapter.number)}"
83
- elsif chapter.on_PREDEF?
84
- "#{chapter.number}"
85
- elsif chapter.on_POSTDEF?
86
- "#{I18n.t("appendix", chapter.number)}"
87
- end
83
+ chapter.format_number
84
+ rescue # part
85
+ "#{I18n.t("part", chapter.number)}"
88
86
  end
89
87
 
90
88
  def title(id)
91
89
  @index.fetch(id).title
90
+ rescue # non-file part
91
+ @index.fetch(id).name
92
92
  end
93
93
 
94
94
  def display_string(id)
@@ -132,12 +132,11 @@ module ReVIEW
132
132
 
133
133
  class ImageIndex < Index
134
134
  class Item
135
- @@entries = nil
136
135
 
137
136
  def initialize(id, number)
138
137
  @id = id
139
138
  @number = number
140
- @pathes = nil
139
+ @path = nil
141
140
  end
142
141
 
143
142
  attr_reader :id
@@ -145,22 +144,21 @@ module ReVIEW
145
144
  attr_writer :index # internal use only
146
145
 
147
146
  def bound?
148
- not pathes().empty?
147
+ path
149
148
  end
150
149
 
151
150
  def path
152
- pathes().first
151
+ @path ||= @index.find_path(id)
153
152
  end
154
153
 
155
- def pathes
156
- @pathes ||= @index.find_pathes(id)
157
- end
158
154
  end
159
155
 
160
156
  def ImageIndex.item_type
161
157
  '(image|graph)'
162
158
  end
163
159
 
160
+ attr_reader :image_finder
161
+
164
162
  def initialize(items, chapid, basedir, types)
165
163
  super items
166
164
  items.each do |i|
@@ -170,46 +168,34 @@ module ReVIEW
170
168
  @basedir = basedir
171
169
  @types = types
172
170
 
173
- @@entries ||= get_entries
171
+ @image_finder = ReVIEW::Book::ImageFinder.new(basedir, chapid,
172
+ ReVIEW.book.config['builder'], types)
174
173
  end
175
174
 
176
- def get_entries
177
- Dir.glob(File.join(@basedir, "**/*.*"))
175
+ def find_path(id)
176
+ @image_finder.find_path(id)
178
177
  end
179
178
 
180
- # internal use only
181
- def find_pathes(id)
182
- pathes = []
183
-
184
- # 1. <basedir>/<builder>/<chapid>/<id>.<ext>
185
- target = "#{@basedir}/#{ReVIEW.book.param['builder']}/#{@chapid}/#{id}"
186
- @types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
187
-
188
- # 2. <basedir>/<builder>/<chapid>-<id>.<ext>
189
- target = "#{@basedir}/#{ReVIEW.book.param['builder']}/#{@chapid}-#{id}"
190
- @types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
191
-
192
- # 3. <basedir>/<builder>/<id>.<ext>
193
- target = "#{@basedir}/#{ReVIEW.book.param['builder']}/#{id}"
194
- @types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
195
-
196
- # 4. <basedir>/<chapid>/<id>.<ext>
197
- target = "#{@basedir}/#{@chapid}/#{id}"
198
- @types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
199
-
200
- # 5. <basedir>/<chapid>-<id>.<ext>
201
- target = "#{@basedir}/#{@chapid}-#{id}"
202
- @types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
179
+ end
203
180
 
204
- # 6. <basedir>/<id>.<ext>
205
- target = "#{@basedir}/#{id}"
206
- @types.each {|ext| pathes.push("#{target}#{ext}") if @@entries.include?("#{target}#{ext}")}
181
+ class IconIndex < ImageIndex
182
+ def initialize(items, chapid, basedir, types)
183
+ @items = items
184
+ @index = {}
185
+ items.each do |i|
186
+ ## warn "warning: duplicate ID: #{i.id} (#{i})" unless @index[i.id].nil?
187
+ @index[i.id] = i
188
+ end
189
+ items.each do |i|
190
+ i.index = self
191
+ end
192
+ @chapid = chapid
193
+ @basedir = basedir
194
+ @types = types
207
195
 
208
- return pathes
196
+ @image_finder = ImageFinder.new(basedir, chapid, ReVIEW.book.config['builder'], types)
209
197
  end
210
- end
211
198
 
212
- class IconIndex < ImageIndex
213
199
  def IconIndex.parse(src, *args)
214
200
  items = []
215
201
  seq = 1
@@ -268,7 +254,7 @@ module ReVIEW
268
254
  def initialize(id, number)
269
255
  @id = id
270
256
  @number = ""
271
- @pathes = nil
257
+ @path = nil
272
258
  end
273
259
  end
274
260
 
@@ -286,7 +272,7 @@ module ReVIEW
286
272
  def initialize(id, number)
287
273
  @id = id
288
274
  @number = ""
289
- @pathes = nil
275
+ @path = nil
290
276
  end
291
277
  end
292
278
 
@@ -300,14 +286,16 @@ module ReVIEW
300
286
  end
301
287
 
302
288
  class HeadlineIndex < Index
289
+ HEADLINE_PATTERN = /\A(=+)(?:\[(.+?)\])?(?:\{(.+?)\})?(.*)/
303
290
  Item = Struct.new(:id, :number, :caption)
291
+ attr_reader :items
304
292
 
305
293
  def HeadlineIndex.parse(src, chap)
306
294
  items = []
307
295
  indexs = []
308
296
  headlines = []
309
297
  src.each do |line|
310
- if m = /\A(=+)(?:\[(.+?)\])?(?:\{(.+?)\})?(.*)/.match(line)
298
+ if m = HEADLINE_PATTERN.match(line)
311
299
  next if m[2] == 'column'
312
300
  index = m[1].size - 2
313
301
  if index >= 0
@@ -341,5 +329,31 @@ module ReVIEW
341
329
  return ([@chap.number] + @index.fetch(id).number).join(".")
342
330
  end
343
331
  end
332
+
333
+ class ColumnIndex < Index
334
+ COLUMN_PATTERN = /\A(=+)\[column\](?:\{(.+?)\})?(.*)/
335
+ Item = Struct.new(:id, :number, :caption)
336
+
337
+ def ColumnIndex.parse(src, *args)
338
+ items = []
339
+ seq = 1
340
+ src.each do |line|
341
+ if m = COLUMN_PATTERN.match(line)
342
+ level = m[1] ## not use it yet
343
+ id = m[2]
344
+ caption = m[3].strip
345
+ if !id || id == ""
346
+ id = caption
347
+ end
348
+
349
+ items.push item_class().new(id, seq, caption)
350
+ seq += 1
351
+ end
352
+ end
353
+ new(items)
354
+ end
355
+
356
+ end
357
+
344
358
  end
345
359
  end
@@ -22,7 +22,7 @@ module ReVIEW
22
22
  def PageMetric.b5
23
23
  new(46, 80, 30, 74, 2)
24
24
  end
25
-
25
+
26
26
  def initialize(list_lines, list_columns, text_lines, text_columns, page_per_kbyte)
27
27
  @list = MetricData.new(list_lines, list_columns)
28
28
  @text = MetricData.new(text_lines, text_columns)
@@ -30,10 +30,6 @@ module ReVIEW
30
30
 
31
31
  def initialize(strict = false, *args)
32
32
  @strict = strict
33
- @tabwidth = nil
34
- if ReVIEW.book.param && ReVIEW.book.param["tabwidth"]
35
- @tabwidth = ReVIEW.book.param["tabwidth"]
36
- end
37
33
  builder_init(*args)
38
34
  end
39
35
 
@@ -47,6 +43,10 @@ module ReVIEW
47
43
  @location = location
48
44
  @output = StringIO.new
49
45
  @book = ReVIEW.book
46
+ @tabwidth = nil
47
+ if @book.config && @book.config["tabwidth"]
48
+ @tabwidth = @book.config["tabwidth"]
49
+ end
50
50
  builder_init_file
51
51
  end
52
52
 
@@ -58,17 +58,17 @@ module ReVIEW
58
58
  @output.string
59
59
  end
60
60
 
61
- alias :raw_result result
61
+ alias_method :raw_result, :result
62
62
 
63
63
  def print(*s)
64
64
  @output.print(*s.map{|i|
65
- convert_outencoding(i, ReVIEW.book.param["outencoding"])
65
+ convert_outencoding(i, @book.config["outencoding"])
66
66
  })
67
67
  end
68
68
 
69
69
  def puts(*s)
70
70
  @output.puts *s.map{|i|
71
- convert_outencoding(i, ReVIEW.book.param["outencoding"])
71
+ convert_outencoding(i, @book.config["outencoding"])
72
72
  }
73
73
  end
74
74
 
@@ -257,12 +257,19 @@ module ReVIEW
257
257
  end
258
258
 
259
259
  def inline_hd(id)
260
- m = /\A(\w+)\|(.+)/.match(id)
260
+ m = /\A([^|]+)\|(.+)/.match(id)
261
261
  chapter = @book.chapters.detect{|chap| chap.id == m[1]} if m && m[1]
262
262
  return inline_hd_chap(chapter, m[2]) if chapter
263
263
  return inline_hd_chap(@chapter, id)
264
264
  end
265
265
 
266
+ def inline_column(id)
267
+ @chapter.column(id).caption
268
+ rescue
269
+ error "unknown column: #{id}"
270
+ nofunc_text("[UnknownColumn:#{id}]")
271
+ end
272
+
266
273
  def raw(str)
267
274
  if matched = str.match(/\|(.*?)\|(.*)/)
268
275
  builders = matched[1].split(/,/).map{|i| i.gsub(/\s/, '') }
@@ -312,7 +319,7 @@ module ReVIEW
312
319
  end
313
320
 
314
321
  def get_chap(chapter = @chapter)
315
- if ReVIEW.book.param["secnolevel"] > 0 && !chapter.number.nil? && !chapter.number.to_s.empty?
322
+ if @book.config["secnolevel"] > 0 && !chapter.number.nil? && !chapter.number.to_s.empty?
316
323
  return "#{chapter.number}"
317
324
  end
318
325
  return nil
@@ -346,7 +353,7 @@ module ReVIEW
346
353
  file = "#{id}.#{image_ext}"
347
354
  file_path = File.join(dir, file)
348
355
 
349
- line = CGI.unescapeHTML(lines.join("\n"))
356
+ line = self.unescape(lines.join("\n"))
350
357
  cmds = {
351
358
  :graphviz => "echo '#{line}' | dot -T#{image_ext} -o#{file_path}",
352
359
  :gnuplot => "echo 'set terminal " +
@@ -369,12 +376,12 @@ module ReVIEW
369
376
 
370
377
  def inline_include(file_name)
371
378
  compile_inline convert_inencoding(File.open(file_name).read,
372
- ReVIEW.book.param["inencoding"])
379
+ @book.config["inencoding"])
373
380
  end
374
381
 
375
382
  def include(file_name)
376
383
  File.foreach(file_name) do |line|
377
- paragraph([convert_inencoding(line, ReVIEW.book.param["inencoding"])])
384
+ paragraph([convert_inencoding(line, @book.config["inencoding"])])
378
385
  end
379
386
  end
380
387