tmtms-review 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +9 -0
  3. data/COPYING +515 -0
  4. data/ChangeLog +2083 -0
  5. data/README.rdoc +50 -0
  6. data/Rakefile +56 -0
  7. data/VERSION +1 -0
  8. data/bin/review-check +178 -0
  9. data/bin/review-checkdep +63 -0
  10. data/bin/review-compile +205 -0
  11. data/bin/review-epubmaker +661 -0
  12. data/bin/review-epubmaker-ng +176 -0
  13. data/bin/review-index +118 -0
  14. data/bin/review-pdfmaker +208 -0
  15. data/bin/review-preproc +142 -0
  16. data/bin/review-validate +51 -0
  17. data/bin/review-vol +102 -0
  18. data/debian/README.Debian +12 -0
  19. data/debian/README.source +5 -0
  20. data/debian/changelog +5 -0
  21. data/debian/compat +1 -0
  22. data/debian/control +22 -0
  23. data/debian/copyright +62 -0
  24. data/debian/docs +6 -0
  25. data/debian/manpage.1.ex +59 -0
  26. data/debian/patches/path.diff +91 -0
  27. data/debian/patches/series +1 -0
  28. data/debian/review.install +13 -0
  29. data/debian/review.links +4 -0
  30. data/debian/rules +13 -0
  31. data/debian/source/format +1 -0
  32. data/doc/format.rdoc +582 -0
  33. data/doc/format_idg.rdoc +180 -0
  34. data/doc/libepubmaker/sample.yaml +90 -0
  35. data/doc/quickstart.rdoc +188 -0
  36. data/doc/ruby-uuid/README +11 -0
  37. data/doc/ruby-uuid/README.ja +34 -0
  38. data/doc/sample.css +108 -0
  39. data/doc/sample.yaml +62 -0
  40. data/lib/epubmaker.rb +28 -0
  41. data/lib/epubmaker/content.rb +82 -0
  42. data/lib/epubmaker/epubv2.rb +418 -0
  43. data/lib/epubmaker/epubv3.rb +249 -0
  44. data/lib/epubmaker/producer.rb +204 -0
  45. data/lib/epubmaker/resource.rb +66 -0
  46. data/lib/lineinput.rb +155 -0
  47. data/lib/review.rb +3 -0
  48. data/lib/review/book.rb +46 -0
  49. data/lib/review/book/base.rb +235 -0
  50. data/lib/review/book/chapter.rb +81 -0
  51. data/lib/review/book/compilable.rb +159 -0
  52. data/lib/review/book/index.rb +339 -0
  53. data/lib/review/book/page_metric.rb +38 -0
  54. data/lib/review/book/parameters.rb +97 -0
  55. data/lib/review/book/part.rb +44 -0
  56. data/lib/review/book/volume.rb +65 -0
  57. data/lib/review/builder.rb +444 -0
  58. data/lib/review/compiler.rb +550 -0
  59. data/lib/review/configure.rb +38 -0
  60. data/lib/review/epubbuilder.rb +18 -0
  61. data/lib/review/exception.rb +21 -0
  62. data/lib/review/extentions.rb +3 -0
  63. data/lib/review/extentions/object.rb +9 -0
  64. data/lib/review/extentions/string.rb +33 -0
  65. data/lib/review/htmlbuilder.rb +1097 -0
  66. data/lib/review/htmllayout.rb +19 -0
  67. data/lib/review/htmlutils.rb +36 -0
  68. data/lib/review/i18n.rb +30 -0
  69. data/lib/review/i18n.yaml +34 -0
  70. data/lib/review/idgxmlbuilder.rb +1145 -0
  71. data/lib/review/latexbuilder.rb +815 -0
  72. data/lib/review/latexindex.rb +35 -0
  73. data/lib/review/latexutils.rb +79 -0
  74. data/lib/review/preprocessor.rb +563 -0
  75. data/lib/review/review.tex.erb +232 -0
  76. data/lib/review/textbuilder.rb +17 -0
  77. data/lib/review/textutils.rb +66 -0
  78. data/lib/review/tocparser.rb +342 -0
  79. data/lib/review/tocprinter.rb +221 -0
  80. data/lib/review/topbuilder.rb +785 -0
  81. data/lib/review/unfold.rb +138 -0
  82. data/lib/uuid.rb +312 -0
  83. data/review.gemspec +141 -0
  84. data/test/CHAPS +2 -0
  85. data/test/bib.re +13 -0
  86. data/test/book_test_helper.rb +35 -0
  87. data/test/test.re +43 -0
  88. data/test/test_book.rb +598 -0
  89. data/test/test_book_chapter.rb +418 -0
  90. data/test/test_book_parameter.rb +42 -0
  91. data/test/test_book_part.rb +50 -0
  92. data/test/test_builder.rb +144 -0
  93. data/test/test_compiler.rb +44 -0
  94. data/test/test_epubmaker.rb +507 -0
  95. data/test/test_helper.rb +27 -0
  96. data/test/test_htmlbuilder.rb +554 -0
  97. data/test/test_htmlutils.rb +28 -0
  98. data/test/test_i18n.rb +64 -0
  99. data/test/test_idgxmlbuilder.rb +589 -0
  100. data/test/test_index.rb +31 -0
  101. data/test/test_latexbuilder.rb +656 -0
  102. data/test/test_lineinput.rb +198 -0
  103. data/test/test_preprocessor.rb +23 -0
  104. data/test/test_textutils.rb +68 -0
  105. data/test/test_topbuilder.rb +244 -0
  106. data/test/test_uuid.rb +156 -0
  107. metadata +161 -0
@@ -0,0 +1,550 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright (c) 2002-2007 Minero Aoki
4
+ # Copyright (c) 2009-2010 Minero Aoki, Kenshi Muto
5
+ #
6
+ # This program is free software.
7
+ # You can distribute or modify this program under the terms of
8
+ # the GNU LGPL, Lesser General Public License version 2.1.
9
+ #
10
+
11
+ require 'review/extentions'
12
+ require 'review/preprocessor'
13
+ require 'review/exception'
14
+ require 'lineinput'
15
+
16
+ module ReVIEW
17
+
18
+ class Location
19
+ def initialize(filename, f)
20
+ @filename = filename
21
+ @f = f
22
+ end
23
+
24
+ attr_reader :filename
25
+
26
+ def lineno
27
+ @f.lineno
28
+ end
29
+
30
+ def string
31
+ begin
32
+ "#{@filename}:#{@f.lineno}"
33
+ rescue
34
+ "#{@filename}:nil"
35
+ end
36
+ end
37
+
38
+ alias to_s string
39
+ end
40
+
41
+
42
+ class Compiler
43
+
44
+ def initialize(strategy)
45
+ @strategy = strategy
46
+ end
47
+
48
+ attr_reader :strategy
49
+
50
+ def compile(chap)
51
+ @chapter = chap
52
+ do_compile
53
+ @strategy.result
54
+ end
55
+
56
+ class SyntaxElement
57
+ def initialize(name, type, argc, &block)
58
+ @name = name
59
+ @type = type
60
+ @argc_spec = argc
61
+ @checker = block
62
+ end
63
+
64
+ attr_reader :name
65
+
66
+ def check_args(args)
67
+ unless @argc_spec === args.size
68
+ raise CompileError, "wrong # of parameters (block command //#{@name}, expect #{@argc_spec} but #{args.size})"
69
+ end
70
+ @checker.call(*args) if @checker
71
+ end
72
+
73
+ def min_argc
74
+ case @argc_spec
75
+ when Range then @argc_spec.begin
76
+ when Integer then @argc_spec
77
+ else
78
+ raise TypeError, "argc_spec is not Range/Integer: #{inspect()}"
79
+ end
80
+ end
81
+
82
+ def block_required?
83
+ @type == :block
84
+ end
85
+
86
+ def block_allowed?
87
+ @type == :block or @type == :optional
88
+ end
89
+ end
90
+
91
+ SYNTAX = {}
92
+
93
+ def Compiler.defblock(name, argc, optional = false, &block)
94
+ defsyntax name, (optional ? :optional : :block), argc, &block
95
+ end
96
+
97
+ def Compiler.defsingle(name, argc, &block)
98
+ defsyntax name, :line, argc, &block
99
+ end
100
+
101
+ def Compiler.defsyntax(name, type, argc, &block)
102
+ SYNTAX[name] = SyntaxElement.new(name, type, argc, &block)
103
+ end
104
+
105
+ def syntax_defined?(name)
106
+ SYNTAX.key?(name.to_sym)
107
+ end
108
+
109
+ def syntax_descriptor(name)
110
+ SYNTAX[name.to_sym]
111
+ end
112
+
113
+ class InlineSyntaxElement
114
+ def initialize(name)
115
+ @name = name
116
+ end
117
+
118
+ attr_reader :name
119
+ end
120
+
121
+ INLINE = {}
122
+
123
+ def Compiler.definline(name)
124
+ INLINE[name] = InlineSyntaxElement.new(name)
125
+ end
126
+
127
+ def inline_defined?(name)
128
+ INLINE.key?(name.to_sym)
129
+ end
130
+
131
+ defblock :read, 0
132
+ defblock :lead, 0
133
+ defblock :list, 2
134
+ defblock :emlist, 0..1
135
+ defblock :cmd, 0..1
136
+ defblock :table, 0..2
137
+ defblock :quote, 0
138
+ defblock :image, 2..3, true
139
+ defblock :source, 1
140
+ defblock :listnum, 2
141
+ defblock :emlistnum, 0..1
142
+ defblock :bibpaper, 2..3, true
143
+ defblock :doorquote, 1
144
+ defblock :talk, 0
145
+ defblock :texequation, 0
146
+ defblock :graph, 1..3
147
+
148
+ defblock :address, 0
149
+ defblock :blockquote, 0
150
+ defblock :bpo, 0
151
+ defblock :flushright, 0
152
+ defblock :centering, 0
153
+ defblock :note, 0..1
154
+ defblock :box, 0..1
155
+
156
+ defsingle :footnote, 2
157
+ defsingle :comment, 1
158
+ defsingle :noindent, 0
159
+ defsingle :linebreak, 0
160
+ defsingle :pagebreak, 0
161
+ defsingle :indepimage, 1..3
162
+ defsingle :numberlessimage, 1..3
163
+ defsingle :hr, 0
164
+ defsingle :parasep, 0
165
+ defsingle :label, 1
166
+ defsingle :raw, 1
167
+ defsingle :tsize, 1
168
+ defsingle :include, 1
169
+ defsingle :olnum, 1
170
+
171
+ definline :chapref
172
+ definline :chap
173
+ definline :title
174
+ definline :img
175
+ definline :icon
176
+ definline :list
177
+ definline :table
178
+ definline :fn
179
+ definline :kw
180
+ definline :ruby
181
+ definline :bou
182
+ definline :ami
183
+ definline :b
184
+ definline :dtp
185
+ definline :code
186
+ definline :bib
187
+ definline :hd
188
+ definline :href
189
+ definline :recipe
190
+
191
+ definline :abbr
192
+ definline :acronym
193
+ definline :cite
194
+ definline :dfn
195
+ definline :em
196
+ definline :kbd
197
+ definline :q
198
+ definline :samp
199
+ definline :strong
200
+ definline :var
201
+ definline :big
202
+ definline :small
203
+ definline :del
204
+ definline :ins
205
+ definline :sup
206
+ definline :sub
207
+ definline :tt
208
+ definline :i
209
+ definline :tti
210
+ definline :ttb
211
+ definline :u
212
+ definline :raw
213
+ definline :br
214
+ definline :m
215
+ definline :uchar
216
+ definline :idx
217
+ definline :hidx
218
+ definline :comment
219
+ definline :include
220
+
221
+ private
222
+
223
+ def do_compile
224
+ f = LineInput.new(Preprocessor::Strip.new(StringIO.new(@chapter.content)))
225
+ @strategy.bind self, @chapter, Location.new(@chapter.basename, f)
226
+ tagged_section_init
227
+ while f.next?
228
+ case f.peek
229
+ when /\A\#@/
230
+ f.gets # Nothing to do
231
+ when /\A=+[\[\s\{]/
232
+ compile_headline f.gets
233
+ when %r<\A\s+\*>
234
+ compile_ulist f
235
+ when %r<\A\s+\d+\.>
236
+ compile_olist f
237
+ when %r<\A\s*:\s>
238
+ compile_dlist f
239
+ when %r<\A//\}>
240
+ f.gets
241
+ error 'block end seen but not opened'
242
+ when %r<\A//[a-z]+>
243
+ name, args, lines = read_command(f)
244
+ syntax = syntax_descriptor(name)
245
+ unless syntax
246
+ error "unknown command: //#{name}"
247
+ compile_unknown_command args, lines
248
+ next
249
+ end
250
+ compile_command syntax, args, lines
251
+ when %r<\A//>
252
+ line = f.gets
253
+ warn "`//' seen but is not valid command: #{line.strip.inspect}"
254
+ if block_open?(line)
255
+ warn "skipping block..."
256
+ read_block(f)
257
+ end
258
+ else
259
+ if f.peek.strip.empty?
260
+ f.gets
261
+ next
262
+ end
263
+ compile_paragraph f
264
+ end
265
+ end
266
+ close_all_tagged_section
267
+ end
268
+
269
+ def compile_headline(line)
270
+ @headline_indexs ||= [@chapter.number.to_i - 1]
271
+ m = /\A(=+)(?:\[(.+?)\])?(?:\{(.+?)\})?(.*)/.match(line)
272
+ level = m[1].size
273
+ tag = m[2]
274
+ label = m[3]
275
+ caption = m[4].strip
276
+ index = level - 1
277
+ if tag
278
+ if tag !~ /\A\//
279
+ close_current_tagged_section(level)
280
+ open_tagged_section(tag, level, label, caption)
281
+ else
282
+ open_tag = tag[1..-1]
283
+ prev_tag_info = @tagged_section.pop
284
+ unless prev_tag_info.first == open_tag
285
+ raise CompileError, "#{open_tag} is not opened."
286
+ end
287
+ close_tagged_section(*prev_tag_info)
288
+ end
289
+ else
290
+ if @headline_indexs.size > (index + 1)
291
+ @headline_indexs = @headline_indexs[0..index]
292
+ end
293
+ @headline_indexs[index] = 0 if @headline_indexs[index].nil?
294
+ @headline_indexs[index] += 1
295
+ close_current_tagged_section(level)
296
+ if ReVIEW.book.param["hdnumberingmode"]
297
+ caption = @chapter.on_CHAPS? ? "#{@headline_indexs.join('.')} #{caption}" : caption
298
+ warn "--hdnumberingmode is deprecated. use --level option."
299
+ end
300
+ @strategy.headline level, label, caption
301
+ end
302
+ end
303
+
304
+ def close_current_tagged_section(level)
305
+ while @tagged_section.last and @tagged_section.last[1] >= level
306
+ close_tagged_section(* @tagged_section.pop)
307
+ end
308
+ end
309
+
310
+ def headline(level, label, caption)
311
+ @strategy.headline level, label, caption
312
+ end
313
+
314
+ def tagged_section_init
315
+ @tagged_section = []
316
+ end
317
+
318
+ def open_tagged_section(tag, level, label, caption)
319
+ mid = "#{tag}_begin"
320
+ unless @strategy.respond_to?(mid)
321
+ error "strategy does not support tagged section: #{tag}"
322
+ headline level, label, caption
323
+ return
324
+ end
325
+ @tagged_section.push [tag, level]
326
+ @strategy.__send__ mid, level, label, caption
327
+ end
328
+
329
+ def close_tagged_section(tag, level)
330
+ mid = "#{tag}_end"
331
+ if @strategy.respond_to?(mid)
332
+ @strategy.__send__ mid, level
333
+ else
334
+ error "strategy does not support block op: #{mid}"
335
+ end
336
+ end
337
+
338
+ def close_all_tagged_section
339
+ until @tagged_section.empty?
340
+ close_tagged_section(* @tagged_section.pop)
341
+ end
342
+ end
343
+
344
+ def compile_ulist(f)
345
+ level = 0
346
+ f.while_match(/\A\s+\*|\A\#@/) do |line|
347
+ next if line =~ /\A\#@/
348
+
349
+ buf = [text(line.sub(/\*+/, '').strip)]
350
+ f.while_match(/\A\s+(?!\*)\S/) do |cont|
351
+ buf.push text(cont.strip)
352
+ end
353
+
354
+ line =~ /\A\s+(\*+)/
355
+ current_level = $1.size
356
+ if level == current_level
357
+ @strategy.ul_item_end
358
+ # body
359
+ @strategy.ul_item_begin buf
360
+ elsif level < current_level # down
361
+ level_diff = current_level - level
362
+ level = current_level
363
+ (1..(level_diff - 1)).to_a.reverse.each do |i|
364
+ @strategy.ul_begin {i}
365
+ @strategy.ul_item_begin []
366
+ end
367
+ @strategy.ul_begin {level}
368
+ @strategy.ul_item_begin buf
369
+ elsif level > current_level # up
370
+ level_diff = level - current_level
371
+ level = current_level
372
+ (1..level_diff).to_a.reverse.each do |i|
373
+ @strategy.ul_item_end
374
+ @strategy.ul_end {level + i}
375
+ @strategy.ul_item_end
376
+ end
377
+ # body
378
+ @strategy.ul_item_begin buf
379
+ end
380
+ end
381
+
382
+ (1..level).to_a.reverse.each do |i|
383
+ @strategy.ul_item_end
384
+ @strategy.ul_end {i}
385
+ end
386
+ end
387
+
388
+ def compile_olist(f)
389
+ @strategy.ol_begin
390
+ f.while_match(/\A\s+\d+\.|\A\#@/) do |line|
391
+ next if line =~ /\A\#@/
392
+
393
+ num = line.match(/(\d+)\./)[1]
394
+ buf = [text(line.sub(/\d+\./, '').strip)]
395
+ f.while_match(/\A\s+(?!\d+\.)\S/) do |cont|
396
+ buf.push text(cont.strip)
397
+ end
398
+ @strategy.ol_item buf, num
399
+ end
400
+ @strategy.ol_end
401
+ end
402
+
403
+ def compile_dlist(f)
404
+ @strategy.dl_begin
405
+ while /\A\s*:/ =~ f.peek
406
+ @strategy.dt text(f.gets.sub(/\A\s*:/, '').strip)
407
+ @strategy.dd f.break(/\A(\S|\s*:)/).map {|line| text(line.strip) }
408
+ f.skip_blank_lines
409
+ end
410
+ @strategy.dl_end
411
+ end
412
+
413
+ def compile_paragraph(f)
414
+ buf = []
415
+ f.until_match(%r<\A//|\A\#@>) do |line|
416
+ break if line.strip.empty?
417
+ buf.push text(line.sub(/^(\t+)\s*/) {|m| "<!ESCAPETAB!>" * m.size}.strip.gsub(/<!ESCAPETAB!>/, "\t"))
418
+ end
419
+ @strategy.paragraph buf
420
+ end
421
+
422
+ def read_command(f)
423
+ line = f.gets
424
+ name = line.slice(/[a-z]+/).intern
425
+ args = parse_args(line.sub(%r<\A//[a-z]+>, '').rstrip.chomp('{'), name)
426
+ lines = block_open?(line) ? read_block(f) : nil
427
+ return name, args, lines
428
+ end
429
+
430
+ def block_open?(line)
431
+ line.rstrip[-1,1] == '{'
432
+ end
433
+
434
+ def read_block(f)
435
+ head = f.lineno
436
+ buf = []
437
+ f.until_match(%r<\A//\}>) do |line|
438
+ unless line =~ /\A\#@/
439
+ buf.push text(line.rstrip)
440
+ end
441
+ end
442
+ unless %r<\A//\}> =~ f.peek
443
+ error "unexpected EOF (block begins at: #{head})"
444
+ return buf
445
+ end
446
+ f.gets # discard terminator
447
+ buf
448
+ end
449
+
450
+ def parse_args(str, name=nil)
451
+ return [] if str.empty?
452
+ scanner = StringScanner.new(str)
453
+ words = []
454
+ while word = scanner.scan(/(\[\]|\[.*?[^\\]\])/)
455
+ w2 = word[1..-2].gsub(/\\(.)/){
456
+ ch = $1
457
+ (ch == "]" or ch == "\\") ? ch : "\\" + ch
458
+ }
459
+ words << w2
460
+ end
461
+ if !scanner.eos?
462
+ error "argument syntax error: #{scanner.rest} in #{str.inspect}"
463
+ return []
464
+ end
465
+ return words
466
+ end
467
+
468
+ def compile_command(syntax, args, lines)
469
+ unless @strategy.respond_to?(syntax.name)
470
+ error "strategy does not support command: //#{syntax.name}"
471
+ compile_unknown_command args, lines
472
+ return
473
+ end
474
+ begin
475
+ syntax.check_args args
476
+ rescue CompileError => err
477
+ error err.message
478
+ args = ['(NoArgument)'] * syntax.min_argc
479
+ end
480
+ if syntax.block_allowed?
481
+ compile_block syntax, args, lines
482
+ else
483
+ if lines
484
+ error "block is not allowed for command //#{syntax.name}; ignore"
485
+ end
486
+ compile_single syntax, args
487
+ end
488
+ end
489
+
490
+ def compile_unknown_command(args, lines)
491
+ @strategy.unknown_command args, lines
492
+ end
493
+
494
+ def compile_block(syntax, args, lines)
495
+ @strategy.__send__(syntax.name, (lines || default_block(syntax)), *args)
496
+ end
497
+
498
+ def default_block(syntax)
499
+ if syntax.block_required?
500
+ error "block is required for //#{syntax.name}; use empty block"
501
+ end
502
+ []
503
+ end
504
+
505
+ def compile_single(syntax, args)
506
+ @strategy.__send__(syntax.name, *args)
507
+ end
508
+
509
+ def text(str)
510
+ return '' if str.empty?
511
+ words = str.split(/(@<\w+>\{(?:[^\}\\]|\\.)*?\})/, -1)
512
+ words.each do |w|
513
+ error "`@<xxx>' seen but is not valid inline op: #{w}" if w.scan(/@<\w+>/).size > 1 && !/\A@<raw>/.match(w)
514
+ end
515
+ result = @strategy.nofunc_text(words.shift)
516
+ until words.empty?
517
+ result << compile_inline(words.shift.gsub(/\\\}/, '}'))
518
+ result << @strategy.nofunc_text(words.shift)
519
+ end
520
+ result
521
+ rescue => err
522
+ error err.message
523
+ end
524
+ public :text # called from strategy
525
+
526
+ def compile_inline(str)
527
+ op, arg = /\A@<(\w+)>\{(.*?)\}\z/.match(str).captures
528
+ unless inline_defined?(op)
529
+ raise CompileError, "no such inline op: #{op}"
530
+ end
531
+ unless @strategy.respond_to?("inline_#{op}")
532
+ raise "strategy does not support inline op: @<#{op}>"
533
+ end
534
+ @strategy.__send__("inline_#{op}", arg)
535
+ rescue => err
536
+ error err.message
537
+ @strategy.nofunc_text(str)
538
+ end
539
+
540
+ def warn(msg)
541
+ @strategy.warn msg
542
+ end
543
+
544
+ def error(msg)
545
+ @strategy.error msg
546
+ end
547
+
548
+ end
549
+
550
+ end # module ReVIEW