review-peg 0.1.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 (174) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/.rubocop.yml +47 -0
  4. data/.rubocop_todo.yml +605 -0
  5. data/.travis.yml +18 -0
  6. data/COPYING +515 -0
  7. data/ChangeLog +2449 -0
  8. data/Dockerfile +22 -0
  9. data/Gemfile +6 -0
  10. data/README.rdoc +81 -0
  11. data/Rakefile +51 -0
  12. data/bin/review-catalog-converter-peg +129 -0
  13. data/bin/review-check-peg +169 -0
  14. data/bin/review-checkdep-peg +63 -0
  15. data/bin/review-compile-peg +202 -0
  16. data/bin/review-epubmaker-legacy-peg +1024 -0
  17. data/bin/review-epubmaker-peg +44 -0
  18. data/bin/review-index-peg +110 -0
  19. data/bin/review-init-peg +151 -0
  20. data/bin/review-pdfmaker-peg +18 -0
  21. data/bin/review-preproc-peg +131 -0
  22. data/bin/review-validate-peg +51 -0
  23. data/bin/review-vol-peg +100 -0
  24. data/debian/README.Debian +12 -0
  25. data/debian/README.source +5 -0
  26. data/debian/changelog +5 -0
  27. data/debian/compat +1 -0
  28. data/debian/control +22 -0
  29. data/debian/copyright +62 -0
  30. data/debian/docs +6 -0
  31. data/debian/manpage.1.ex +59 -0
  32. data/debian/patches/path.diff +91 -0
  33. data/debian/patches/series +1 -0
  34. data/debian/review.install +13 -0
  35. data/debian/review.links +4 -0
  36. data/debian/rules +13 -0
  37. data/debian/source/format +1 -0
  38. data/doc/NEWS.ja.md +350 -0
  39. data/doc/NEWS.md +354 -0
  40. data/doc/catalog.ja.md +53 -0
  41. data/doc/catalog.md +52 -0
  42. data/doc/format.ja.md +734 -0
  43. data/doc/format.md +746 -0
  44. data/doc/format_idg.ja.md +203 -0
  45. data/doc/quickstart.ja.md +222 -0
  46. data/doc/quickstart.md +252 -0
  47. data/doc/ruby-uuid/README +11 -0
  48. data/doc/ruby-uuid/README.ja +34 -0
  49. data/doc/sample.css +108 -0
  50. data/doc/sample.yml +238 -0
  51. data/lib/epubmaker.rb +24 -0
  52. data/lib/epubmaker/content.rb +93 -0
  53. data/lib/epubmaker/epubcommon.rb +424 -0
  54. data/lib/epubmaker/epubv2.rb +139 -0
  55. data/lib/epubmaker/epubv3.rb +222 -0
  56. data/lib/epubmaker/producer.rb +330 -0
  57. data/lib/lineinput.rb +107 -0
  58. data/lib/review.rb +3 -0
  59. data/lib/review/book.rb +43 -0
  60. data/lib/review/book/base.rb +401 -0
  61. data/lib/review/book/chapter.rb +100 -0
  62. data/lib/review/book/compilable.rb +184 -0
  63. data/lib/review/book/image_finder.rb +71 -0
  64. data/lib/review/book/index.rb +413 -0
  65. data/lib/review/book/page_metric.rb +47 -0
  66. data/lib/review/book/part.rb +54 -0
  67. data/lib/review/book/volume.rb +67 -0
  68. data/lib/review/builder.rb +452 -0
  69. data/lib/review/catalog.rb +52 -0
  70. data/lib/review/compiler.rb +5183 -0
  71. data/lib/review/compiler/literals_1_9.kpeg +22 -0
  72. data/lib/review/compiler/literals_1_9.rb +435 -0
  73. data/lib/review/configure.rb +64 -0
  74. data/lib/review/epubbuilder.rb +18 -0
  75. data/lib/review/epubmaker.rb +480 -0
  76. data/lib/review/ewbbuilder.rb +381 -0
  77. data/lib/review/exception.rb +21 -0
  78. data/lib/review/extentions.rb +4 -0
  79. data/lib/review/extentions/array.rb +25 -0
  80. data/lib/review/extentions/object.rb +9 -0
  81. data/lib/review/extentions/string.rb +33 -0
  82. data/lib/review/htmlbuilder.rb +1166 -0
  83. data/lib/review/htmllayout.rb +41 -0
  84. data/lib/review/htmltoc.rb +45 -0
  85. data/lib/review/htmlutils.rb +90 -0
  86. data/lib/review/i18n.rb +96 -0
  87. data/lib/review/i18n.yml +169 -0
  88. data/lib/review/idgxmlbuilder.rb +1233 -0
  89. data/lib/review/inaobuilder.rb +357 -0
  90. data/lib/review/latexbuilder.rb +941 -0
  91. data/lib/review/latexindex.rb +35 -0
  92. data/lib/review/latexutils.rb +95 -0
  93. data/lib/review/layout.tex.erb +340 -0
  94. data/lib/review/lineinput.rb +17 -0
  95. data/lib/review/location.rb +24 -0
  96. data/lib/review/makerhelper.rb +67 -0
  97. data/lib/review/markdownbuilder.rb +339 -0
  98. data/lib/review/node.rb +288 -0
  99. data/lib/review/pdfmaker.rb +332 -0
  100. data/lib/review/preprocessor.rb +530 -0
  101. data/lib/review/review.kpeg +745 -0
  102. data/lib/review/sec_counter.rb +69 -0
  103. data/lib/review/template.rb +21 -0
  104. data/lib/review/textbuilder.rb +17 -0
  105. data/lib/review/textutils.rb +16 -0
  106. data/lib/review/tocparser.rb +348 -0
  107. data/lib/review/tocprinter.rb +205 -0
  108. data/lib/review/topbuilder.rb +796 -0
  109. data/lib/review/unfold.rb +138 -0
  110. data/lib/review/version.rb +3 -0
  111. data/lib/uuid.rb +312 -0
  112. data/review.gemspec +32 -0
  113. data/templates/html/layout-html5.html.erb +17 -0
  114. data/templates/html/layout-xhtml1.html.erb +20 -0
  115. data/templates/ncx/epubv2.ncx.erb +11 -0
  116. data/templates/opf/epubv2.opf.erb +21 -0
  117. data/templates/opf/epubv3.opf.erb +18 -0
  118. data/templates/xml/container.xml.erb +6 -0
  119. data/test/CHAPS +2 -0
  120. data/test/assets/test.xml.erb +3 -0
  121. data/test/assets/test_template.tex +255 -0
  122. data/test/assets/test_template_backmatter.tex +32 -0
  123. data/test/bib.re +13 -0
  124. data/test/book_test_helper.rb +35 -0
  125. data/test/sample-book/README.md +7 -0
  126. data/test/sample-book/src/Rakefile +58 -0
  127. data/test/sample-book/src/_cover.html +3 -0
  128. data/test/sample-book/src/catalog.yml +10 -0
  129. data/test/sample-book/src/ch01.re +71 -0
  130. data/test/sample-book/src/ch02.re +3 -0
  131. data/test/sample-book/src/config.yml +186 -0
  132. data/test/sample-book/src/images/ch01-imgsample.jpg +0 -0
  133. data/test/sample-book/src/images/cover.jpg +0 -0
  134. data/test/sample-book/src/preface.re +15 -0
  135. data/test/sample-book/src/sty/jumoline.sty +310 -0
  136. data/test/sample-book/src/sty/reviewmacro.sty +39 -0
  137. data/test/sample-book/src/style.css +251 -0
  138. data/test/sample-book/src/vendor/jumoline/README +29 -0
  139. data/test/sample-book/src/vendor/jumoline/jumoline.dtx +2988 -0
  140. data/test/sample-book/src/vendor/jumoline/jumoline.ins +6 -0
  141. data/test/test.re +43 -0
  142. data/test/test_book.rb +556 -0
  143. data/test/test_book_chapter.rb +280 -0
  144. data/test/test_book_part.rb +54 -0
  145. data/test/test_builder.rb +80 -0
  146. data/test/test_catalog.rb +119 -0
  147. data/test/test_catalog_converter_cmd.rb +73 -0
  148. data/test/test_compiler.rb +92 -0
  149. data/test/test_configure.rb +50 -0
  150. data/test/test_epub3maker.rb +529 -0
  151. data/test/test_epubmaker.rb +569 -0
  152. data/test/test_epubmaker_cmd.rb +40 -0
  153. data/test/test_helper.rb +92 -0
  154. data/test/test_htmlbuilder.rb +1114 -0
  155. data/test/test_htmltoc.rb +32 -0
  156. data/test/test_htmlutils.rb +50 -0
  157. data/test/test_i18n.rb +180 -0
  158. data/test/test_idgxmlbuilder.rb +608 -0
  159. data/test/test_image_finder.rb +82 -0
  160. data/test/test_inaobuilder.rb +245 -0
  161. data/test/test_index.rb +174 -0
  162. data/test/test_latexbuilder.rb +732 -0
  163. data/test/test_lineinput.rb +182 -0
  164. data/test/test_makerhelper.rb +66 -0
  165. data/test/test_markdownbuilder.rb +125 -0
  166. data/test/test_pdfmaker.rb +171 -0
  167. data/test/test_pdfmaker_cmd.rb +40 -0
  168. data/test/test_preprocessor.rb +23 -0
  169. data/test/test_review_ext.rb +31 -0
  170. data/test/test_template.rb +26 -0
  171. data/test/test_textutils.rb +32 -0
  172. data/test/test_topbuilder.rb +291 -0
  173. data/test/test_uuid.rb +157 -0
  174. metadata +357 -0
@@ -0,0 +1,530 @@
1
+ #
2
+ # $Id: preprocessor.rb 4250 2009-05-24 14:03:01Z aamine $
3
+ #
4
+ # Copyright (c) 2002-2009 Minero Aoki
5
+ # Copyright (c) 2010 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/textutils'
14
+ require 'review/exception'
15
+ require 'nkf'
16
+
17
+ module ReVIEW
18
+
19
+ module ErrorUtils
20
+
21
+ def init_ErrorUtils(f)
22
+ @errutils_file = f
23
+ @errutils_err = false
24
+ end
25
+
26
+ def warn(msg)
27
+ $stderr.puts "#{location()}: warning: #{msg}"
28
+ end
29
+
30
+ def error(msg)
31
+ @errutils_err = true
32
+ raise ApplicationError, "#{location()}: #{msg}"
33
+ end
34
+
35
+ def location
36
+ "#{filename()}:#{lineno()}"
37
+ end
38
+
39
+ def filename
40
+ @errutils_file.path
41
+ end
42
+
43
+ def lineno
44
+ @errutils_file.lineno
45
+ end
46
+
47
+ end
48
+
49
+
50
+ class Preprocessor
51
+
52
+ include ErrorUtils
53
+
54
+ def Preprocessor.strip(f)
55
+ buf = ''
56
+ Strip.new(f).each do |line|
57
+ buf << line.rstrip << "\n"
58
+ end
59
+ buf
60
+ end
61
+
62
+ class Strip
63
+ def initialize(f)
64
+ @f = f
65
+ end
66
+
67
+ def path
68
+ @f.path
69
+ end
70
+
71
+ def lineno
72
+ @f.lineno
73
+ end
74
+
75
+ def gets
76
+ while line = @f.gets
77
+ if /\A\#@/ =~ line
78
+ return "\#@\#\n"
79
+ else
80
+ return line
81
+ end
82
+ end
83
+ nil
84
+ end
85
+
86
+ def each
87
+ @f.each do |line|
88
+ yield line unless /\A\#@/ =~ line
89
+ end
90
+ end
91
+ end
92
+
93
+ def initialize(repo, param)
94
+ @repository = repo
95
+ @config = param
96
+ end
97
+
98
+ def process(inf, outf)
99
+ init_ErrorUtils inf
100
+ @f = outf
101
+ begin
102
+ preproc inf
103
+ rescue Errno::ENOENT => err
104
+ error err.message
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ TYPES = %w( file range )
111
+
112
+ def preproc(f)
113
+ init_vars
114
+ while line = f.gets
115
+ case line
116
+ when /\A\#@\#/, /\A\#\#\#\#/
117
+ @f.print line
118
+
119
+ when /\A\#@defvar/
120
+ @f.print line
121
+ direc = parse_directive(line, 2)
122
+ defvar(*direc.args)
123
+
124
+ when /\A\#@mapoutput/
125
+ direc = parse_directive(line, 1, 'stderr')
126
+ @f.print line
127
+ get_output(expand(direc.arg), direc['stderr']).each do |out|
128
+ @f.print out.string
129
+ end
130
+ skip_list f
131
+
132
+ when /\A\#@mapfile/
133
+ direc = parse_directive(line, 1, 'eval')
134
+ path = expand(direc.arg)
135
+ ent = @repository.fetch_file(path)
136
+ ent = evaluate(path, ent) if direc['eval']
137
+ replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp
138
+
139
+ when /\A\#@map(?:range)?/
140
+ direc = parse_directive(line, 2, 'unindent')
141
+ path = expand(direc.args[0])
142
+ ent = @repository.fetch_range(path, direc.args[1]) or
143
+ error "unknown range: #{path}: #{direc.args[1]}"
144
+ ent = (direc['unindent'] ? unindent(ent, direc['unindent']) : ent)
145
+ replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp
146
+
147
+ when /\A\#@end/
148
+ error 'unbaranced #@end'
149
+
150
+ when /\A\#@/
151
+ op = line.slice(/@(\w+)/, 1)
152
+ #error "unkown directive: #{line.strip}" unless known_directive?(op)
153
+ warn "unkown directive: #{line.strip}" unless known_directive?(op)
154
+ @f.print line
155
+
156
+ when /\A\s*\z/ # empty line
157
+ @f.puts
158
+ else
159
+ @f.print line
160
+ end
161
+ end
162
+ end
163
+
164
+ private
165
+
166
+ KNOWN_DIRECTIVES = %w( require provide warn ok )
167
+
168
+ def known_directive?(op)
169
+ KNOWN_DIRECTIVES.index(op)
170
+ end
171
+
172
+ def replace_block(f, directive_line, newlines, with_lineno)
173
+ @f.print directive_line
174
+ newlines.each do |line|
175
+ print_number line.number if with_lineno
176
+ @f.print line.string
177
+ end
178
+ skip_list f
179
+ end
180
+
181
+ def print_number(num)
182
+ @f.printf '%4s ', (num ? num.to_s : '')
183
+ end
184
+
185
+ def skip_list(f)
186
+ begline = f.lineno
187
+ while line = f.gets
188
+ case line
189
+ when %r[\A\#@end]
190
+ @f.print line
191
+ return
192
+ when %r[\A//\}]
193
+ warn '//} seen in list'
194
+ @f.print line
195
+ return
196
+ when %r[\A\#@\w]
197
+ warn "#{line.slice(/\A\#@\w+/)} seen in list"
198
+ @f.print line
199
+ when %r[\A\#@]
200
+ @f.print line
201
+ end
202
+ end
203
+ error "list reached end of file (beginning line = #{begline})"
204
+ end
205
+
206
+ class Directive
207
+ def initialize(op, args, opts)
208
+ @op = op
209
+ @args = args
210
+ @opts = opts
211
+ end
212
+
213
+ attr_reader :op
214
+ attr_reader :args
215
+ attr_reader :opts
216
+
217
+ def arg
218
+ @args.first
219
+ end
220
+
221
+ def opt
222
+ @opts.first
223
+ end
224
+
225
+ def [](key)
226
+ @opts[key]
227
+ end
228
+ end
229
+
230
+ def parse_directive(line, argc, *optdecl)
231
+ m = /\A\#@(\w+)\((.*?)\)(?:\[(.*?)\])?\z/.match(line.strip) or
232
+ error "wrong directive: #{line.strip}"
233
+ op = m[1]
234
+ args = m[2].split(/,\s*/)
235
+ opts = parse_optargs(m[3])
236
+ return if argc == 0 and args.empty?
237
+ if argc == -1
238
+ # Any number of arguments are allowed.
239
+ elsif args.size != argc
240
+ error "wrong arg size"
241
+ end
242
+ if opts
243
+ wrong_opts = opts.keys - optdecl
244
+ unless wrong_opts.empty?
245
+ error "wrong option: #{wrong_opts.keys.join(' ')}"
246
+ end
247
+ end
248
+ Directive.new(op, args, opts || {})
249
+ end
250
+
251
+ def parse_optargs(str)
252
+ return nil unless str
253
+ table = {}
254
+ str.split(/,\s*/).each do |a|
255
+ name, spec = a.split(/=/, 2)
256
+ table[name] = optarg_value(spec)
257
+ end
258
+ table
259
+ end
260
+
261
+ def optarg_value(spec)
262
+ case spec
263
+ when 'true' then true # [name=true]
264
+ when 'false' then false # [name=false]
265
+ when 'nil' then nil # [name=nil]
266
+ when nil then true # [name]
267
+ when /^\d+$/ then $&.to_i # [name=8]
268
+ else # [name=val]
269
+ spec
270
+ end
271
+ end
272
+
273
+ def init_vars
274
+ @vartable = {}
275
+ end
276
+
277
+ def defvar(name, value)
278
+ @vartable[name] = value
279
+ end
280
+
281
+ def expand(str)
282
+ str.gsub(/\$\w+/) {|name|
283
+ s = @vartable[name.sub('$', '')]
284
+ s ? expand(s) : name
285
+ }
286
+ end
287
+
288
+ def unindent(chunk, n)
289
+ n = minimum_indent(chunk) unless n.kind_of?(Integer)
290
+ re = /\A#{' ' * n}/
291
+ chunk.map {|line| line.edit {|s| s.sub(re,'') } }
292
+ end
293
+
294
+ INF_INDENT = 9999
295
+
296
+ def minimum_indent(chunk)
297
+ n = chunk.map {|line| line.empty? ? INF_INDENT : line.num_indent }.min
298
+ n == INF_INDENT ? 0 : n
299
+ end
300
+
301
+ def check_ruby_syntax(rbfile)
302
+ status = spawn {
303
+ exec("ruby -c #{rbfile} 2>&1 > /dev/null")
304
+ }
305
+ error "syntax check failed: #{rbfile}" unless status.exitstatus == 0
306
+ end
307
+
308
+ def spawn
309
+ pid, status = *Process.waitpid2(fork { yield })
310
+ status
311
+ end
312
+
313
+ def evaluate(path, chunk)
314
+ outputs = get_output("ruby #{path}", false).split(/\n/).map {|s| s.strip }
315
+ chunk.map {|line|
316
+ if /\# \$\d+/ =~ line.string
317
+ # map result into source.
318
+ line.edit {|s|
319
+ s.sub(/\$(\d+)/) { outputs[$1.to_i - 1] }
320
+ }
321
+ else
322
+ line
323
+ end
324
+ }
325
+ end
326
+
327
+ require 'open3'
328
+
329
+ def get_output(cmd, use_stderr)
330
+ out = err = nil
331
+ Open3.popen3(cmd) {|stdin, stdout, stderr|
332
+ out = stdout.readlines
333
+ if use_stderr
334
+ out.concat stderr.readlines
335
+ else
336
+ err = stderr.readlines
337
+ end
338
+ }
339
+ if err and not err.empty?
340
+ $stderr.puts "[unexpected stderr message]"
341
+ err.each do |line|
342
+ $stderr.print line
343
+ end
344
+ error "get_output: got unexpected output"
345
+ end
346
+ num = 0
347
+ out.map {|line| Line.new(num += 1, line) }
348
+ end
349
+
350
+ end
351
+
352
+
353
+ class Line
354
+ def initialize(number, string)
355
+ @number = number
356
+ @string = string
357
+ end
358
+
359
+ attr_reader :number
360
+ attr_reader :string
361
+ alias_method :to_s, :string
362
+
363
+ def edit
364
+ self.class.new(@number, yield(@string))
365
+ end
366
+
367
+ def empty?
368
+ @string.strip.empty?
369
+ end
370
+
371
+ def num_indent
372
+ @string.slice(/\A\s*/).size
373
+ end
374
+ end
375
+
376
+
377
+ class Repository
378
+
379
+ include TextUtils
380
+ include ErrorUtils
381
+
382
+ def initialize(param)
383
+ @repository = {}
384
+ @config = param
385
+ end
386
+
387
+ def fetch_file(file)
388
+ file_descripter(file)['file']
389
+ end
390
+
391
+ def fetch_range(file, name)
392
+ fetch(file, 'range', name)
393
+ end
394
+
395
+ def fetch(file, type, name)
396
+ table = file_descripter(file)[type] or return nil
397
+ table[name]
398
+ end
399
+
400
+ private
401
+
402
+ def file_descripter(fname)
403
+ return @repository[fname] if @repository[fname]
404
+
405
+ @repository[fname] = git?(fname) ? parse_git_blob(fname) : parse_file(fname)
406
+ end
407
+
408
+ def git?(fname)
409
+ fname =~ /\Agit\|/
410
+ end
411
+
412
+ def parse_git_blob(g_obj)
413
+ IO.popen('git show ' + g_obj.sub(/\Agit\|/, ''), 'r') do |f|
414
+ init_ErrorUtils f
415
+ return _parse_file(f)
416
+ end
417
+ end
418
+
419
+ def parse_file(fname)
420
+ File.open(fname) {|f|
421
+ init_ErrorUtils f
422
+ return _parse_file(f)
423
+ }
424
+ end
425
+
426
+ def _parse_file(f)
427
+ whole = []
428
+ repo = {'file' => whole}
429
+ curr = {'WHOLE' => whole}
430
+ lineno = 1
431
+ yacchack = false # remove ';'-only lines.
432
+ opened = [['(not opened)', '(not opened)']] * 3
433
+
434
+ f.each do |line|
435
+ case line
436
+ when /(?:\A\#@|\#@@)([a-z]+)_(begin|end)\((.*)\)/
437
+ type = check_type($1)
438
+ direction = $2
439
+ spec = check_spec($3)
440
+ case direction
441
+ when 'begin'
442
+ key = "#{type}/#{spec}"
443
+ error "begin x2: #{key}" if curr[key]
444
+ (repo[type] ||= {})[spec] = curr[key] = []
445
+ when 'end'
446
+ curr.delete("#{type}/#{spec}") or
447
+ error "end before begin: #{type}/#{spec}"
448
+ else
449
+ raise 'must not happen'
450
+ end
451
+
452
+ when %r<(?:\A\#@|\#@@)([a-z]+)/(\w+)\{>
453
+ type = check_type($1)
454
+ spec = check_spec($2)
455
+ key = "#{type}/#{spec}"
456
+ error "begin x2: #{key}" if curr[key]
457
+ (repo[type] ||= {})[spec] = curr[key] = []
458
+ opened.push [type, spec]
459
+
460
+ when %r<(?:\A\#@|\#@@)([a-z]+)/(\w+)\}>
461
+ type = check_type($1)
462
+ spec = check_spec($2)
463
+ curr.delete("#{type}/#{spec}") or
464
+ error "end before begin: #{type}/#{spec}"
465
+ opened.delete "#{type}/#{spec}"
466
+
467
+ when %r<(?:\A\#@|\#@@)\}>
468
+ type, spec = opened.last
469
+ curr.delete("#{type}/#{spec}") or
470
+ error "closed before open: #{type}/#{spec}"
471
+ opened.pop
472
+
473
+ when /(?:\A\#@|\#@@)yacchack/
474
+ yacchack = true
475
+
476
+ when /\A\#@-/ # does not increment line number.
477
+ line = canonical($')
478
+ curr.each_value do |list|
479
+ list.push Line.new(nil, line)
480
+ end
481
+
482
+ else
483
+ next if yacchack and line.strip == ';'
484
+ line = canonical(line)
485
+ curr.each_value do |list|
486
+ list.push Line.new(lineno, line)
487
+ end
488
+ lineno += 1
489
+ end
490
+ end
491
+ if curr.size > 1
492
+ curr.delete 'WHOLE'
493
+ curr.each do |range, lines|
494
+ $stderr.puts "#{filename()}: unclosed range: #{range} (begin @#{lines.first.number})"
495
+ end
496
+ raise ApplicationError, "ERROR"
497
+ end
498
+
499
+ repo
500
+ end
501
+
502
+ def canonical(line)
503
+ tabwidth = 8
504
+ if @config['tabwidth']
505
+ tabwidth = @config['tabwidth']
506
+ end
507
+ if tabwidth > 0
508
+ detab(line, tabwidth).rstrip + "\n"
509
+ else
510
+ line
511
+ end
512
+ end
513
+
514
+ def check_type(type)
515
+ unless Preprocessor::TYPES.index(type)
516
+ error "wrong type: #{type.inspect}"
517
+ end
518
+ type
519
+ end
520
+
521
+ def check_spec(spec)
522
+ unless /\A\w+\z/ =~ spec
523
+ error "wrong spec: #{spec.inspect}"
524
+ end
525
+ spec
526
+ end
527
+
528
+ end
529
+
530
+ end