review 0.6.0

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