review 0.6.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 (50) hide show
  1. data/COPYING +515 -0
  2. data/ChangeLog +1278 -0
  3. data/README.rdoc +21 -0
  4. data/Rakefile +42 -0
  5. data/VERSION +1 -0
  6. data/bin/review-check +190 -0
  7. data/bin/review-checkdep +63 -0
  8. data/bin/review-compile +165 -0
  9. data/bin/review-epubmaker +525 -0
  10. data/bin/review-index +108 -0
  11. data/bin/review-preproc +140 -0
  12. data/bin/review-validate +51 -0
  13. data/bin/review-vol +106 -0
  14. data/doc/format.re +486 -0
  15. data/doc/format.txt +434 -0
  16. data/doc/format_idg.txt +194 -0
  17. data/doc/format_sjis.txt +313 -0
  18. data/doc/sample.css +91 -0
  19. data/doc/sample.yaml +46 -0
  20. data/lib/lineinput.rb +155 -0
  21. data/lib/review/book.rb +580 -0
  22. data/lib/review/builder.rb +274 -0
  23. data/lib/review/compat.rb +22 -0
  24. data/lib/review/compiler.rb +483 -0
  25. data/lib/review/epubbuilder.rb +692 -0
  26. data/lib/review/ewbbuilder.rb +382 -0
  27. data/lib/review/exception.rb +21 -0
  28. data/lib/review/htmlbuilder.rb +370 -0
  29. data/lib/review/htmllayout.rb +19 -0
  30. data/lib/review/htmlutils.rb +27 -0
  31. data/lib/review/idgxmlbuilder.rb +1078 -0
  32. data/lib/review/index.rb +224 -0
  33. data/lib/review/latexbuilder.rb +420 -0
  34. data/lib/review/latexindex.rb +35 -0
  35. data/lib/review/latexutils.rb +52 -0
  36. data/lib/review/preprocessor.rb +520 -0
  37. data/lib/review/textutils.rb +19 -0
  38. data/lib/review/tocparser.rb +333 -0
  39. data/lib/review/tocprinter.rb +220 -0
  40. data/lib/review/topbuilder.rb +572 -0
  41. data/lib/review/unfold.rb +138 -0
  42. data/lib/review/volume.rb +66 -0
  43. data/lib/review.rb +4 -0
  44. data/review.gemspec +93 -0
  45. data/setup.rb +1587 -0
  46. data/test/test_epubbuilder.rb +73 -0
  47. data/test/test_helper.rb +2 -0
  48. data/test/test_htmlbuilder.rb +42 -0
  49. data/test/test_latexbuilder.rb +74 -0
  50. metadata +122 -0
data/lib/lineinput.rb ADDED
@@ -0,0 +1,155 @@
1
+ #
2
+ # $Id: lineinput.rb 2226 2006-04-15 03:05:09Z aamine $
3
+ #
4
+ # Copyright (c) 2002-2005 Minero Aoki
5
+ #
6
+ # This program is free software.
7
+ # You can distribute/modify this program under the terms of
8
+ # the GNU LGPL, Lesser General Public License version 2.1.
9
+ #
10
+
11
+ class LineInput
12
+
13
+ def initialize(f)
14
+ @input = f
15
+ @buf = []
16
+ @lineno = 0
17
+ @eof_p = false
18
+ end
19
+
20
+ def inspect
21
+ "\#<#{self.class} file=#{@f.inspect} line=#{lineno()}>"
22
+ end
23
+
24
+ def eof?
25
+ @eof_p
26
+ end
27
+
28
+ def lineno
29
+ @lineno
30
+ end
31
+
32
+ def gets
33
+ unless @buf.empty?
34
+ @lineno += 1
35
+ return @buf.pop
36
+ end
37
+ return nil if @eof_p # to avoid ARGF blocking.
38
+ line = @input.gets
39
+ @eof_p = true unless line
40
+ @lineno += 1
41
+ line
42
+ end
43
+
44
+ def ungets(line)
45
+ return unless line
46
+ @lineno -= 1
47
+ @buf.push line
48
+ line
49
+ end
50
+
51
+ def peek
52
+ line = gets()
53
+ ungets line if line
54
+ line
55
+ end
56
+
57
+ def next?
58
+ peek() ? true : false
59
+ end
60
+
61
+ def skip_blank_lines
62
+ n = 0
63
+ while line = gets()
64
+ unless line.strip.empty?
65
+ ungets line
66
+ return n
67
+ end
68
+ n += 1
69
+ end
70
+ n
71
+ end
72
+
73
+ def gets_if(re)
74
+ line = gets()
75
+ if not line or not (re =~ line)
76
+ ungets line
77
+ return nil
78
+ end
79
+ line
80
+ end
81
+
82
+ def gets_unless(re)
83
+ line = gets()
84
+ if not line or re =~ line
85
+ ungets line
86
+ return nil
87
+ end
88
+ line
89
+ end
90
+
91
+ def each
92
+ while line = gets()
93
+ yield line
94
+ end
95
+ end
96
+
97
+ def while_match(re)
98
+ while line = gets()
99
+ unless re =~ line
100
+ ungets line
101
+ return
102
+ end
103
+ yield line
104
+ end
105
+ nil
106
+ end
107
+
108
+ def getlines_while(re)
109
+ buf = []
110
+ while_match(re) do |line|
111
+ buf.push line
112
+ end
113
+ buf
114
+ end
115
+
116
+ alias span getlines_while # from Haskell
117
+
118
+ def until_match(re)
119
+ while line = gets()
120
+ if re =~ line
121
+ ungets line
122
+ return
123
+ end
124
+ yield line
125
+ end
126
+ nil
127
+ end
128
+
129
+ def getlines_until(re)
130
+ buf = []
131
+ until_match(re) do |line|
132
+ buf.push line
133
+ end
134
+ buf
135
+ end
136
+
137
+ alias break getlines_until # from Haskell
138
+
139
+ def until_terminator(re)
140
+ while line = gets()
141
+ return if re =~ line # discard terminal line
142
+ yield line
143
+ end
144
+ nil
145
+ end
146
+
147
+ def getblock(term_re)
148
+ buf = []
149
+ until_terminator(term_re) do |line|
150
+ buf.push line
151
+ end
152
+ buf
153
+ end
154
+
155
+ end
@@ -0,0 +1,580 @@
1
+ #
2
+ # $Id: book.rb 4315 2009-09-02 04:15:24Z kmuto $
3
+ #
4
+ # Copyright (c) 2002-2008 Minero Aoki
5
+ # 2009 Minero Aoki, Kenshi Muto
6
+ #
7
+ # This program is free software.
8
+ # You can distribute or modify this program under the terms of
9
+ # the GNU LGPL, Lesser General Public License version 2.1.
10
+ # For details of the GNU LGPL, see the file "COPYING".
11
+ #
12
+
13
+ require 'review/index'
14
+ require 'review/volume'
15
+ require 'review/exception'
16
+ require 'review/compat'
17
+ require 'forwardable'
18
+ require 'nkf'
19
+
20
+ module ReVIEW
21
+
22
+ @default_book = nil
23
+
24
+ def ReVIEW.book
25
+ @default_book ||= Book.load_default
26
+ end
27
+
28
+ class Book
29
+
30
+ def Book.load_default
31
+ %w( . .. ../.. ).each do |basedir|
32
+ if File.file?("#{basedir}/PARAMS") or File.file?("#{basedir}/CHAPS")
33
+ return load(basedir)
34
+ end
35
+ end
36
+ new('.')
37
+ end
38
+
39
+ def Book.load(dir)
40
+ update_rubyenv dir
41
+ if File.file?("#{dir}/PARAMS")
42
+ then new(dir, Parameters.load("#{dir}/PARAMS"))
43
+ else new(dir)
44
+ end
45
+ end
46
+
47
+ def setParameter(param)
48
+ @param = param
49
+ end
50
+
51
+ @basedir_seen = {}
52
+
53
+ def Book.update_rubyenv(dir)
54
+ return if @basedir_seen.key?(dir)
55
+ if File.directory?("#{dir}/lib/review")
56
+ $LOAD_PATH.unshift "#{dir}/lib"
57
+ end
58
+ if File.file?("#{dir}/review-ext.rb")
59
+ Kernel.load File.expand_path("#{dir}/review-ext.rb")
60
+ end
61
+ @basedir_seen[dir] = true
62
+ end
63
+
64
+ def initialize(basedir, parameters = Parameters.default)
65
+ @basedir = basedir
66
+ @parameters = parameters
67
+ @parts = nil
68
+ @chapter_index = nil
69
+ end
70
+
71
+ extend Forwardable
72
+ def_delegators '@parameters',
73
+ :chapter_file,
74
+ :part_file,
75
+ :bib_file,
76
+ :index_file,
77
+ :reject_file,
78
+ :nocode_file,
79
+ :predef_file,
80
+ :postdef_file,
81
+ :ext,
82
+ :image_dir,
83
+ :image_types,
84
+ :page_metric
85
+
86
+ def no_part?
87
+ false
88
+ end
89
+
90
+ def parts
91
+ @parts ||= read_parts()
92
+ end
93
+
94
+ def part(n)
95
+ parts.detect {|part| part.number == n }
96
+ end
97
+
98
+ def each_part(&block)
99
+ parts.each(&block)
100
+ end
101
+
102
+ def chapters
103
+ parts().map {|p| p.chapters }.flatten
104
+ end
105
+
106
+ def each_chapter(&block)
107
+ chapters.each(&block)
108
+ end
109
+
110
+ def chapter_index
111
+ @chapter_index ||= ChapterIndex.new(chapters())
112
+ @chapter_index.setParameter(@param)
113
+ @chapter_index
114
+ end
115
+
116
+ def chapter(id)
117
+ chapter_index()[id]
118
+ end
119
+
120
+ def volume
121
+ Volume.sum(chapters.map {|chap| chap.volume })
122
+ end
123
+
124
+ def read_CHAPS
125
+ File.read("#{@basedir}/#{chapter_file}")
126
+ rescue Errno::ENOENT
127
+ Dir.glob("#{@basedir}/*#{ext()}").sort.join("\n")
128
+ end
129
+
130
+ def read_PART
131
+ @read_PART ||= File.read("#{@basedir}/#{part_file}")
132
+ end
133
+
134
+ def part_exist?
135
+ File.exist?("#{@basedir}/#{part_file}")
136
+ end
137
+
138
+ def read_bib
139
+ File.read("#{@basedir}/#{bib_file}")
140
+ end
141
+
142
+ def bib_exist?
143
+ File.exist?("#{@basedir}/#{bib_file}")
144
+ end
145
+
146
+ def prefaces
147
+ if File.file?("#{@basedir}/#{predef_file}")
148
+ begin
149
+ return mkpart_from_namelistfile("#{@basedir}/#{predef_file}")
150
+ rescue FileNotFound => err
151
+ raise FileNotFound, "preface #{err.message}"
152
+ end
153
+ else
154
+ mkpart_from_namelist(%w(preface))
155
+ end
156
+ end
157
+
158
+ def postscripts
159
+ if File.file?("#{@basedir}/#{postdef_file}")
160
+ begin
161
+ return mkpart_from_namelistfile("#{@basedir}/#{postdef_file}")
162
+ rescue FileNotFound => err
163
+ raise FileNotFound, "postscript #{err.message}"
164
+ end
165
+ else
166
+ mkpart_from_namelist(%w(appendix postscript))
167
+ end
168
+ end
169
+
170
+ def basedir
171
+ @basedir
172
+ end
173
+
174
+ private
175
+
176
+ def read_parts
177
+ list = parse_chapters
178
+ if pre = prefaces
179
+ list.unshift pre
180
+ end
181
+ if post = postscripts
182
+ list.push post
183
+ end
184
+ list
185
+ end
186
+
187
+ def parse_chapters
188
+ part = 0
189
+ num = 0
190
+ chap = read_CHAPS()\
191
+ .strip.lines.map {|line| line.strip }.join("\n").split(/\n{2,}/)\
192
+ .map {|part_chunk|
193
+ chaps = part_chunk.split.map {|chapid|
194
+ Chapter.new(self, (num += 1), chapid, "#{@basedir}/#{chapid}")
195
+ }
196
+ if part_exist? && read_PART.split("\n").size >= part
197
+ Part.new((part += 1), chaps, read_PART.split("\n")[part-1])
198
+ else
199
+ Part.new((part += 1), chaps)
200
+ end
201
+ }
202
+ return chap
203
+ end
204
+
205
+ def mkpart_from_namelistfile(path)
206
+ mkpart(File.read(path).split.map {|name| mkchap(name) })
207
+ end
208
+
209
+ def mkpart_from_namelist(names)
210
+ mkpart(names.map {|n| mkchap_ifexist(n) }.compact)
211
+ end
212
+
213
+ def mkpart(chaps)
214
+ chaps.empty? ? nil : Part.new(nil, chaps)
215
+ end
216
+
217
+ def mkchap(name)
218
+ name += ext unless File.extname(name) == ext
219
+ path = "#{@basedir}/#{name}"
220
+ raise FileNotFound, "file not exist: #{path}" unless File.file?(path)
221
+ Chapter.new(self, nil, name, path)
222
+ end
223
+
224
+ def mkchap_ifexist(id)
225
+ name = "#{id}#{ext()}"
226
+ path = "#{@basedir}/#{name}"
227
+ File.file?(path) ? Chapter.new(self, nil, name, path) : nil
228
+ end
229
+
230
+ end
231
+
232
+
233
+ class ChapterSet
234
+
235
+ def ChapterSet.for_argv
236
+ if ARGV.empty?
237
+ new([Chapter.for_stdin])
238
+ else
239
+ for_pathes(ARGV)
240
+ end
241
+ end
242
+
243
+ def ChapterSet.for_pathes(pathes)
244
+ new(Chapter.intern_pathes(pathes))
245
+ end
246
+
247
+ def initialize(chapters)
248
+ @chapters = chapters
249
+ end
250
+
251
+ def no_part?
252
+ true
253
+ end
254
+
255
+ attr_reader :chapters
256
+
257
+ def each_chapter(&block)
258
+ @chapters.each(&block)
259
+ end
260
+
261
+ def ext
262
+ '.re'
263
+ end
264
+
265
+ end
266
+
267
+
268
+ class Parameters
269
+
270
+ def Parameters.default
271
+ new()
272
+ end
273
+
274
+ def Parameters.load(path)
275
+ mod = Module.new
276
+ mod.module_eval File.read(path), path
277
+ new(
278
+ :chapter_file => const_get_safe(mod, :CHAPS_FILE),
279
+ :part_file => const_get_safe(mod, :PART_FILE),
280
+ :bib_file => const_get_safe(mod, :BIB_FILE),
281
+ :index_file => const_get_safe(mod, :INDEX_FILE),
282
+ :reject_file => const_get_safe(mod, :REJECT_FILE) ||
283
+ const_get_safe(mod, :WORDS_FILE),
284
+ :nocode_file => const_get_safe(mod, :NOCODE_FILE),
285
+ :predef_file => const_get_safe(mod, :PREDEF_FILE),
286
+ :postdef_file => const_get_safe(mod, :POSTDEF_FILE),
287
+ :ext => const_get_safe(mod, :EXT),
288
+ :image_dir => const_get_safe(mod, :IMAGE_DIR),
289
+ :image_types => const_get_safe(mod, :IMAGE_TYPES),
290
+ :page_metric => get_page_metric(mod)
291
+ )
292
+ end
293
+
294
+ def Parameters.get_page_metric(mod)
295
+ if paper = const_get_safe(mod, :PAPER)
296
+ unless PageMetric.respond_to?(paper.downcase)
297
+ raise ConfigError, "unknown paper size: #{paper}"
298
+ end
299
+ return PageMetric.send(paper.downcase)
300
+ end
301
+ PageMetric.new(const_get_safe(mod, :LINES_PER_PAGE_list) || 46,
302
+ const_get_safe(mod, :COLUMNS_list) || 80,
303
+ const_get_safe(mod, :LINES_PER_PAGE_text) || 30,
304
+ const_get_safe(mod, :COLUMNS_text) || 74) # 37zw
305
+ end
306
+
307
+ def Parameters.const_get_safe(mod, name)
308
+ return nil unless mod.const_defined?(name)
309
+ mod.const_get(name)
310
+ end
311
+ private_class_method :const_get_safe
312
+
313
+ def initialize(params = {})
314
+ @chapter_file = params[:chapter_file] || 'CHAPS'
315
+ @part_file = params[:part_file] || 'CHAPS'
316
+ @index_file = params[:index_file] || 'INDEX'
317
+ @reject_file = params[:reject_file] || 'REJECT'
318
+ @nocode_file = params[:nocode_file] || 'NOCODE'
319
+ @predef_file = params[:predef_file] || 'PREDEF'
320
+ @postdef_file = params[:postdef_file] || 'POSTDEF'
321
+ @page_metric = params[:page_metric] || PageMetric.a5
322
+ @ext = params[:ext] || '.re'
323
+ @image_dir = params[:image_dir] || 'images'
324
+ @image_types = unify_exts(params[:image_types] ||
325
+ %w( eps tif tiff png bmp jpg jpeg gif svg ))
326
+ @bib_file = params[:bib_file] || "bib#{@ext}"
327
+ end
328
+
329
+ def unify_exts(list)
330
+ list.map {|ext| (ext[0] == '.') ? ext : ".#{ext}" }
331
+ end
332
+ private :unify_exts
333
+
334
+ def self.path_param(name)
335
+ module_eval(<<-End, __FILE__, __LINE__ + 1)
336
+ def #{name}
337
+ "\#{@basedir}/\#{@#{name}}"
338
+ end
339
+ End
340
+ end
341
+
342
+ path_param :chapter_file
343
+ path_param :part_file
344
+ path_param :bib_file
345
+ path_param :index_file
346
+ path_param :reject_file
347
+ path_param :nocode_file
348
+ path_param :predef_file
349
+ path_param :postdef_file
350
+ attr_reader :ext
351
+ path_param :image_dir
352
+ attr_reader :image_types
353
+ attr_reader :page_metric
354
+
355
+ end
356
+
357
+
358
+ class PageMetric
359
+
360
+ MetricData = Struct.new(:n_lines, :n_columns)
361
+
362
+ def PageMetric.a5
363
+ new(46, 80, 30, 74, 1)
364
+ end
365
+
366
+ def PageMetric.b5
367
+ new(46, 80, 30, 74, 2)
368
+ end
369
+
370
+ def initialize(list_lines, list_columns, text_lines, text_columns, page_per_kbyte)
371
+ @list = MetricData.new(list_lines, list_columns)
372
+ @text = MetricData.new(text_lines, text_columns)
373
+ @page_per_kbyte = page_per_kbyte
374
+ end
375
+
376
+ attr_reader :list
377
+ attr_reader :text
378
+ attr_reader :page_per_kbyte
379
+
380
+ end
381
+
382
+
383
+ class Part
384
+
385
+ def initialize(number, chapters, name="")
386
+ @number = number
387
+ @chapters = chapters
388
+ @name = name
389
+ end
390
+
391
+ attr_reader :number
392
+ attr_reader :chapters
393
+ attr_reader :name
394
+
395
+ def each_chapter(&block)
396
+ @chapters.each(&block)
397
+ end
398
+
399
+ def volume
400
+ Volume.sum(@chapters.map {|chap| chap.volume })
401
+ end
402
+
403
+ end
404
+
405
+
406
+ class Chapter
407
+
408
+ def Chapter.intern_pathes(pathes)
409
+ books = {}
410
+ pathes.map {|path|
411
+ basedir = File.dirname(path)
412
+ book = (books[File.expand_path(basedir)] ||= Book.load(basedir))
413
+ begin
414
+ book.chapter(File.basename(path, '.*'))
415
+ rescue KeyError => err
416
+ raise FileNotFound, "no such file: #{path}"
417
+ end
418
+ }
419
+ end
420
+
421
+ def Chapter.for_stdin
422
+ new(nil, nil, '-', nil, $stdin)
423
+ end
424
+
425
+ def Chapter.for_path(number, path)
426
+ new(nil, number, File.basename(path), path)
427
+ end
428
+
429
+ def initialize(book, number, name, path, io = nil)
430
+ @book = book
431
+ @number = number
432
+ @name = name
433
+ @path = path
434
+ @io = io
435
+ @title = nil
436
+ @content = nil
437
+ @list_index = nil
438
+ @table_index = nil
439
+ @footnote_index = nil
440
+ @image_index = nil
441
+ end
442
+
443
+ def setParameter(param)
444
+ @param = param
445
+ end
446
+
447
+ def env
448
+ @book
449
+ end
450
+
451
+ def inspect
452
+ "\#<#{self.class} #{@number} #{@path}>"
453
+ end
454
+
455
+ attr_reader :book
456
+ attr_reader :number
457
+ attr_reader :path
458
+
459
+ def dirname
460
+ return nil unless @path
461
+ File.dirname(@path)
462
+ end
463
+
464
+ def basename
465
+ return nil unless @path
466
+ File.basename(@path)
467
+ end
468
+
469
+ def name
470
+ File.basename(@name, '.*')
471
+ end
472
+
473
+ alias id name
474
+
475
+ def title
476
+ @title = ""
477
+ open {|f|
478
+ f.each_line {|l|
479
+ if l =~ /\A=+/
480
+ @title = l.sub(/\A=+/, '').strip
481
+ break
482
+ end
483
+ }
484
+ }
485
+ if @param["inencoding"] =~ /^EUC$/
486
+ @title = NKF.nkf("-E -w", @title)
487
+ elsif @param["inencoding"] =~ /^SJIS$/
488
+ @title = NKF.nkf("-S -w", @title)
489
+ elsif @param["inencoding"] =~ /^JIS$/
490
+ @title = NKF.nkf("-J -w", @title)
491
+ else
492
+ @title = NKF.nkf("-w", @title)
493
+ end
494
+ end
495
+
496
+ def size
497
+ File.size(path())
498
+ end
499
+
500
+ def volume
501
+ @volume ||= Volume.count_file(path())
502
+ end
503
+
504
+ def open(&block)
505
+ return (block_given?() ? yield(@io) : @io) if @io
506
+ File.open(path(), &block)
507
+ end
508
+
509
+ def content
510
+ if @param["inencoding"] =~ /^EUC$/i
511
+ @content = NKF.nkf("-E -w", File.read(path()))
512
+ elsif @param["inencoding"] =~ /^SJIS$/i
513
+ @content = NKF.nkf("-S -w", File.read(path()))
514
+ elsif @param["inencoding"] =~ /^JIS$/i
515
+ @content = NKF.nkf("-J -w", File.read(path()))
516
+ else
517
+ @content = NKF.nkf("-w", File.read(path())) # auto detect
518
+ end
519
+ end
520
+
521
+ def lines
522
+ # FIXME: we cannot duplicate Enumerator on ruby 1.9 HEAD
523
+ (@lines ||= content().lines.to_a).dup
524
+ end
525
+
526
+ def list(id)
527
+ list_index()[id]
528
+ end
529
+
530
+ def list_index
531
+ @list_index ||= ListIndex.parse(lines())
532
+ @list_index.setParameter(@param)
533
+ @list_index
534
+ end
535
+
536
+ def table(id)
537
+ table_index()[id]
538
+ end
539
+
540
+ def table_index
541
+ @table_index ||= TableIndex.parse(lines())
542
+ @table_index.setParameter(@param)
543
+ @table_index
544
+ end
545
+
546
+ def footnote(id)
547
+ footnote_index()[id]
548
+ end
549
+
550
+ def footnote_index
551
+ @footnote_index ||= FootnoteIndex.parse(lines())
552
+ @footnote_index.setParameter(@param)
553
+ @footnote_index
554
+ end
555
+
556
+ def image(id)
557
+ image_index()[id]
558
+ end
559
+
560
+ def image_index
561
+ @image_index ||= ImageIndex.parse(lines(), id(),
562
+ "#{book.basedir}#{@book.image_dir}",
563
+ @book.image_types)
564
+ @image_index.setParameter(@param)
565
+ @image_index
566
+ end
567
+
568
+ def bibpaper(id)
569
+ bibpaper_index()[id]
570
+ end
571
+
572
+ def bibpaper_index
573
+ raise FileNotFound, "no such bib file: #{@book.bib_file}" unless @book.bib_exist?
574
+ @bibpaper_index ||= BibpaperIndex.parse(@book.read_bib.lines.to_a)
575
+ @bibpaper_index.setParameter(@param)
576
+ @bibpaper_index
577
+ end
578
+ end
579
+
580
+ end