rufus-treechecker 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/rufus/treechecker.rb +210 -247
- data/test/bm.rb +95 -0
- data/test/ft_0_basic.rb +6 -16
- data/test/ft_1_old_treechecker.rb +1 -1
- data/test/ft_2_clone.rb +32 -0
- data/test/test.rb +1 -0
- metadata +4 -2
data/lib/rufus/treechecker.rb
CHANGED
@@ -125,7 +125,7 @@ module Rufus
|
|
125
125
|
#
|
126
126
|
class TreeChecker
|
127
127
|
|
128
|
-
VERSION = '1.0.
|
128
|
+
VERSION = '1.0.2'
|
129
129
|
|
130
130
|
#
|
131
131
|
# pretty-prints the sexp tree of the given rubycode
|
@@ -142,20 +142,19 @@ module Rufus
|
|
142
142
|
#
|
143
143
|
def initialize (&block)
|
144
144
|
|
145
|
-
@
|
146
|
-
@
|
147
|
-
|
148
|
-
@current_checks = @checks
|
145
|
+
@root_set = RuleSet.new
|
146
|
+
@set = RuleSet.new
|
147
|
+
@current_set = @set
|
149
148
|
|
150
149
|
add_rules(&block)
|
151
150
|
end
|
152
151
|
|
153
152
|
def to_s
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
153
|
+
s = "#{self.class} (#{self.object_id})\n"
|
154
|
+
s << "root_set :\n"
|
155
|
+
s << @root_set.to_s
|
156
|
+
s << "set :\n"
|
157
|
+
s << @set.to_s
|
159
158
|
end
|
160
159
|
|
161
160
|
#
|
@@ -167,9 +166,10 @@ module Rufus
|
|
167
166
|
|
168
167
|
sexp = parse(rubycode)
|
169
168
|
|
170
|
-
|
171
|
-
|
172
|
-
end
|
169
|
+
#@root_checks.each do |meth, *args|
|
170
|
+
# send meth, sexp, args
|
171
|
+
#end
|
172
|
+
@root_set.check(sexp)
|
173
173
|
|
174
174
|
do_check(sexp)
|
175
175
|
end
|
@@ -179,9 +179,10 @@ module Rufus
|
|
179
179
|
#
|
180
180
|
def clone
|
181
181
|
|
182
|
-
|
183
|
-
|
184
|
-
|
182
|
+
tc = TreeChecker.new
|
183
|
+
tc.instance_variable_set(:@root_set, @root_set.clone)
|
184
|
+
tc.instance_variable_set(:@set, @set.clone)
|
185
|
+
tc
|
185
186
|
end
|
186
187
|
|
187
188
|
#
|
@@ -199,46 +200,117 @@ module Rufus
|
|
199
200
|
#
|
200
201
|
def freeze
|
201
202
|
super
|
202
|
-
@
|
203
|
-
@
|
204
|
-
@checks.freeze
|
205
|
-
@checks.each { |c| c.freeze }
|
206
|
-
end
|
207
|
-
|
208
|
-
#
|
209
|
-
# generates a 'classic' tree checker
|
210
|
-
#
|
211
|
-
# Here is how it's built :
|
212
|
-
#
|
213
|
-
# return TreeChecker.new do
|
214
|
-
# exclude_fvccall :abort
|
215
|
-
# exclude_fvccall :exit, :exit!
|
216
|
-
# exclude_fvccall :system
|
217
|
-
# exclude_eval
|
218
|
-
# exclude_alias
|
219
|
-
# exclude_global_vars
|
220
|
-
# exclude_call_on File, FileUtils
|
221
|
-
# exclude_class_tinkering
|
222
|
-
# exclude_module_tinkering
|
223
|
-
# end
|
224
|
-
#
|
225
|
-
def self.new_classic_tree_checker
|
226
|
-
|
227
|
-
return TreeChecker.new do
|
228
|
-
exclude_fvccall :abort
|
229
|
-
exclude_fvccall :exit, :exit!
|
230
|
-
exclude_fvccall :system
|
231
|
-
exclude_eval
|
232
|
-
exclude_alias
|
233
|
-
exclude_global_vars
|
234
|
-
exclude_call_on File, FileUtils
|
235
|
-
exclude_class_tinkering
|
236
|
-
exclude_module_tinkering
|
237
|
-
end
|
203
|
+
@root_set.freeze
|
204
|
+
@set.freeze
|
238
205
|
end
|
239
206
|
|
240
207
|
protected
|
241
208
|
|
209
|
+
class RuleSet
|
210
|
+
|
211
|
+
def initialize
|
212
|
+
|
213
|
+
@excluded_symbols = {} # symbol => exclusion_message
|
214
|
+
@accepted_patterns = {} # 1st elt of pattern => pattern
|
215
|
+
@excluded_patterns = {} # 1st elt of pattern => pattern, excl_message
|
216
|
+
end
|
217
|
+
|
218
|
+
def clone
|
219
|
+
rs = RuleSet.new
|
220
|
+
rs.instance_variable_set(:@excluded_symbols, @excluded_symbols.dup)
|
221
|
+
rs.instance_variable_set(:@accepted_patterns, @accepted_patterns.dup)
|
222
|
+
rs.instance_variable_set(:@excluded_patterns, @excluded_patterns.dup)
|
223
|
+
rs
|
224
|
+
end
|
225
|
+
|
226
|
+
def exclude_symbol (s, message)
|
227
|
+
|
228
|
+
@excluded_symbols[s] = (message || ":#{s} is excluded")
|
229
|
+
end
|
230
|
+
|
231
|
+
def accept_pattern (pat)
|
232
|
+
|
233
|
+
(@accepted_patterns[pat.first] ||= []) << pat
|
234
|
+
end
|
235
|
+
|
236
|
+
def exclude_pattern (pat, message)
|
237
|
+
|
238
|
+
(@excluded_patterns[pat.first] ||= []) << [
|
239
|
+
pat, message || "#{pat.inspect} is excluded" ]
|
240
|
+
end
|
241
|
+
|
242
|
+
def check (sexp)
|
243
|
+
|
244
|
+
if sexp.is_a?(Symbol)
|
245
|
+
|
246
|
+
m = @excluded_symbols[sexp]
|
247
|
+
raise SecurityError.new(m) if m
|
248
|
+
|
249
|
+
elsif sexp.is_a?(Array)
|
250
|
+
|
251
|
+
# accepted patterns are evaluated before excluded patterns
|
252
|
+
# if one is found the excluded patterns are skipped
|
253
|
+
|
254
|
+
pats = @accepted_patterns[sexp.first]
|
255
|
+
pats.each { |pat| return if check_pattern(sexp, pat) } if pats
|
256
|
+
|
257
|
+
pats = @excluded_patterns[sexp.first]
|
258
|
+
return unless pats
|
259
|
+
|
260
|
+
pats.each do |pat, msg|
|
261
|
+
raise SecurityError.new(msg) if check_pattern(sexp, pat)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def freeze
|
267
|
+
|
268
|
+
super
|
269
|
+
|
270
|
+
@excluded_symbols.freeze
|
271
|
+
@excluded_symbols.each { |k, v| k.freeze; v.freeze }
|
272
|
+
@accepted_patterns.freeze
|
273
|
+
@accepted_patterns.each { |k, v| k.freeze; v.freeze }
|
274
|
+
@excluded_patterns.freeze
|
275
|
+
@excluded_patterns.each { |k, v| k.freeze; v.freeze }
|
276
|
+
end
|
277
|
+
|
278
|
+
def to_s
|
279
|
+
|
280
|
+
s = "#{self.class} (#{self.object_id})\n"
|
281
|
+
s << " excluded symbols :\n"
|
282
|
+
@excluded_symbols.each do |k, v|
|
283
|
+
s << " - #{k.inspect}, #{v}\n"
|
284
|
+
end
|
285
|
+
s << " accepted patterns :\n"
|
286
|
+
@accepted_patterns.each do |k, v|
|
287
|
+
v.each do |p|
|
288
|
+
s << " - #{k.inspect}, #{p.inspect}\n"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
s << " excluded patterns :\n"
|
292
|
+
@excluded_patterns.each do |k, v|
|
293
|
+
v.each do |p|
|
294
|
+
s << " - #{k.inspect}, #{p.inspect}\n"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
s
|
298
|
+
end
|
299
|
+
|
300
|
+
protected
|
301
|
+
|
302
|
+
def check_pattern (sexp, pat)
|
303
|
+
|
304
|
+
return false if sexp.length < pat.length
|
305
|
+
|
306
|
+
(1..pat.length-1).each do |i|
|
307
|
+
return false if (pat[i] != :any and pat[i] != sexp[i])
|
308
|
+
end
|
309
|
+
|
310
|
+
return true # we have a match
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
242
314
|
#--
|
243
315
|
# the methods used to define the checks
|
244
316
|
#++
|
@@ -249,9 +321,26 @@ module Rufus
|
|
249
321
|
#
|
250
322
|
def at_root (&block)
|
251
323
|
|
252
|
-
@
|
324
|
+
@current_set = @root_set
|
253
325
|
add_rules(&block)
|
254
|
-
@
|
326
|
+
@current_set = @set
|
327
|
+
end
|
328
|
+
|
329
|
+
def extract_message (args)
|
330
|
+
|
331
|
+
message = nil
|
332
|
+
args = args.dup
|
333
|
+
message = args.pop if args.last.is_a?(String)
|
334
|
+
[ args, message ]
|
335
|
+
end
|
336
|
+
|
337
|
+
def expand_class (arg)
|
338
|
+
|
339
|
+
if arg.is_a?(Class) or arg.is_a?(Module)
|
340
|
+
[ parse(arg.to_s), parse("::#{arg.to_s}") ]
|
341
|
+
else
|
342
|
+
[ arg ]
|
343
|
+
end
|
255
344
|
end
|
256
345
|
|
257
346
|
#
|
@@ -266,33 +355,39 @@ module Rufus
|
|
266
355
|
#
|
267
356
|
def exclude_head (head, message=nil)
|
268
357
|
|
269
|
-
@
|
358
|
+
@current_set.exclude_pattern(head, message)
|
270
359
|
end
|
271
360
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
:exclude_fvcall,
|
277
|
-
:exclude_fvccall,
|
278
|
-
:exclude_call_on,
|
279
|
-
:exclude_call_to
|
361
|
+
def exclude_symbol (*args)
|
362
|
+
args, message = extract_message(args)
|
363
|
+
args.each { |a| @current_set.exclude_symbol(a, message) }
|
364
|
+
end
|
280
365
|
|
281
|
-
|
282
|
-
|
283
|
-
|
366
|
+
def exclude_fcall (*args)
|
367
|
+
do_exclude_pair(:fcall, args)
|
368
|
+
end
|
284
369
|
|
285
|
-
|
370
|
+
def exclude_vcall (*args)
|
371
|
+
do_exclude_pair(:vcall, args)
|
372
|
+
end
|
286
373
|
|
287
|
-
|
374
|
+
def exclude_fvcall (*args)
|
375
|
+
do_exclude_pair(:fcall, args)
|
376
|
+
do_exclude_pair(:vcall, args)
|
377
|
+
end
|
288
378
|
|
289
|
-
|
290
|
-
|
379
|
+
def exclude_call_on (*args)
|
380
|
+
do_exclude_pair(:call, args)
|
381
|
+
end
|
291
382
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
383
|
+
def exclude_call_to (*args)
|
384
|
+
args, message = extract_message(args)
|
385
|
+
args.each { |a| @current_set.exclude_pattern([ :call, :any, a], message) }
|
386
|
+
end
|
387
|
+
|
388
|
+
def exclude_fvccall (*args)
|
389
|
+
exclude_fvcall(*args)
|
390
|
+
exclude_call_to(*args)
|
296
391
|
end
|
297
392
|
|
298
393
|
#
|
@@ -306,14 +401,11 @@ module Rufus
|
|
306
401
|
# k = ::Kernel
|
307
402
|
#
|
308
403
|
def exclude_rebinding (*args)
|
309
|
-
|
310
|
-
message = args.last.is_a?(String) ? args.pop : nil
|
311
|
-
|
404
|
+
args, message = extract_message(args)
|
312
405
|
args.each do |a|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
@current_checks << [ :do_exclude_rebinding, c1, message ]
|
406
|
+
expand_class(a).each do |c|
|
407
|
+
@current_set.exclude_pattern([ :lasgn, :any, c], message)
|
408
|
+
end
|
317
409
|
end
|
318
410
|
end
|
319
411
|
|
@@ -322,7 +414,6 @@ module Rufus
|
|
322
414
|
# of classes
|
323
415
|
#
|
324
416
|
def exclude_access_to (*args)
|
325
|
-
|
326
417
|
exclude_call_on *args
|
327
418
|
exclude_rebinding *args
|
328
419
|
end
|
@@ -332,8 +423,7 @@ module Rufus
|
|
332
423
|
#
|
333
424
|
def exclude_def
|
334
425
|
|
335
|
-
@
|
336
|
-
:do_exclude_symbol, :defn, 'method definitions are forbidden' ]
|
426
|
+
@current_set.exclude_symbol(:defn, 'method definitions are forbidden')
|
337
427
|
end
|
338
428
|
|
339
429
|
#
|
@@ -342,23 +432,21 @@ module Rufus
|
|
342
432
|
# a list of exceptions (classes) can be passed. Subclassing those
|
343
433
|
# exceptions is permitted.
|
344
434
|
#
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
# :class
|
435
|
+
# exclude_class_tinkering :except => [ String, Array ]
|
436
|
+
#
|
437
|
+
def exclude_class_tinkering (*args)
|
349
438
|
|
350
|
-
@
|
351
|
-
:
|
352
|
-
] + exceptions.collect { |e| parse(e.to_s) }
|
439
|
+
@current_set.exclude_pattern(
|
440
|
+
[ :sclass ], 'opening the metaclass of an instance is forbidden')
|
353
441
|
|
354
|
-
|
355
|
-
|
442
|
+
Array(args.last[:except]).each { |e|
|
443
|
+
expand_class(e).each do |c|
|
444
|
+
@current_set.accept_pattern([ :class, :any, c ])
|
445
|
+
end
|
446
|
+
} if args.last.is_a?(Hash)
|
356
447
|
|
357
|
-
@
|
358
|
-
:
|
359
|
-
:sclass,
|
360
|
-
'opening the metaclass of an instance is forbidde'
|
361
|
-
]
|
448
|
+
@current_set.exclude_pattern(
|
449
|
+
[ :class ], 'defining a class is forbidden')
|
362
450
|
end
|
363
451
|
|
364
452
|
#
|
@@ -366,9 +454,8 @@ module Rufus
|
|
366
454
|
#
|
367
455
|
def exclude_module_tinkering
|
368
456
|
|
369
|
-
@
|
370
|
-
:
|
371
|
-
]
|
457
|
+
@current_set.exclude_symbol(
|
458
|
+
:module, 'defining or opening a module is forbidden')
|
372
459
|
end
|
373
460
|
|
374
461
|
#
|
@@ -376,10 +463,8 @@ module Rufus
|
|
376
463
|
#
|
377
464
|
def exclude_global_vars
|
378
465
|
|
379
|
-
@
|
380
|
-
|
381
|
-
@current_checks << [
|
382
|
-
:do_exclude_symbol, :gasgn, "global vars are forbidden" ]
|
466
|
+
@current_set.exclude_symbol(:gvar, 'global vars are forbidden')
|
467
|
+
@current_set.exclude_symbol(:gasgn, 'global vars are forbidden')
|
383
468
|
end
|
384
469
|
|
385
470
|
#
|
@@ -387,10 +472,8 @@ module Rufus
|
|
387
472
|
#
|
388
473
|
def exclude_alias
|
389
474
|
|
390
|
-
@
|
391
|
-
|
392
|
-
@current_checks << [
|
393
|
-
:do_exclude_symbol, :alias_method, "'alias_method' is forbidden" ]
|
475
|
+
@current_set.exclude_symbol(:alias, "'alias' is forbidden")
|
476
|
+
@current_set.exclude_symbol(:alias_method, "'alias_method' is forbidden")
|
394
477
|
end
|
395
478
|
|
396
479
|
#
|
@@ -398,26 +481,17 @@ module Rufus
|
|
398
481
|
#
|
399
482
|
def exclude_eval
|
400
483
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
"eval() is forbidden" ]
|
405
|
-
@current_checks << [
|
406
|
-
:do_exclude_call_to,
|
407
|
-
:instance_eval,
|
408
|
-
"instance_eval() is forbidden" ]
|
409
|
-
@current_checks << [
|
410
|
-
:do_exclude_call_to,
|
411
|
-
:module_eval,
|
412
|
-
"module_eval() is forbidden" ]
|
484
|
+
exclude_fcall(:eval, 'eval() is forbidden')
|
485
|
+
exclude_call_to(:module_eval, 'module_eval() is forbidden')
|
486
|
+
exclude_call_to(:instance_eval, 'instance_eval() is forbidden')
|
413
487
|
end
|
414
488
|
|
415
489
|
#
|
416
490
|
# bans the use of backquotes
|
417
491
|
#
|
418
492
|
def exclude_backquotes
|
419
|
-
|
420
|
-
|
493
|
+
|
494
|
+
@current_set.exclude_symbol(:xstr, 'backquotes are forbidden')
|
421
495
|
end
|
422
496
|
|
423
497
|
#
|
@@ -425,8 +499,18 @@ module Rufus
|
|
425
499
|
#
|
426
500
|
def exclude_raise
|
427
501
|
|
428
|
-
|
429
|
-
|
502
|
+
exclude_fvccall(:raise, 'raise is forbidden')
|
503
|
+
exclude_fvccall(:throw, 'throw is forbidden')
|
504
|
+
end
|
505
|
+
|
506
|
+
def do_exclude_pair (first, args)
|
507
|
+
|
508
|
+
args, message = extract_message(args)
|
509
|
+
args.each do |a|
|
510
|
+
expand_class(a).each do |c|
|
511
|
+
@current_set.exclude_pattern([ first, c ], message)
|
512
|
+
end
|
513
|
+
end
|
430
514
|
end
|
431
515
|
|
432
516
|
#
|
@@ -434,9 +518,7 @@ module Rufus
|
|
434
518
|
#
|
435
519
|
def do_check (sexp)
|
436
520
|
|
437
|
-
@
|
438
|
-
send exclusion_method, sexp, args
|
439
|
-
end
|
521
|
+
@set.check(sexp)
|
440
522
|
|
441
523
|
return unless sexp.is_a?(Array) # check over, seems fine...
|
442
524
|
|
@@ -445,125 +527,6 @@ module Rufus
|
|
445
527
|
sexp.each { |c| do_check c }
|
446
528
|
end
|
447
529
|
|
448
|
-
#
|
449
|
-
# the methods that actually perform the checks
|
450
|
-
# (and potentially raise security exceptions)
|
451
|
-
|
452
|
-
#
|
453
|
-
# constructs a new set of arguments by inserting the newhead at the
|
454
|
-
# beginning of the arguments
|
455
|
-
#
|
456
|
-
def cons (newhead, args)
|
457
|
-
|
458
|
-
newhead = Array(newhead)
|
459
|
-
newhead << args[0]
|
460
|
-
|
461
|
-
[ newhead ] + (args[1, -1] || [])
|
462
|
-
end
|
463
|
-
|
464
|
-
def do_exclude_fcall (sexp, args)
|
465
|
-
|
466
|
-
do_exclude_head(sexp, cons(:fcall, args))
|
467
|
-
end
|
468
|
-
|
469
|
-
def do_exclude_vcall (sexp, args)
|
470
|
-
|
471
|
-
do_exclude_head(sexp, cons(:vcall, args))
|
472
|
-
end
|
473
|
-
|
474
|
-
#
|
475
|
-
# excludes :fcall and :vcall
|
476
|
-
#
|
477
|
-
def do_exclude_fvcall (sexp, args)
|
478
|
-
|
479
|
-
do_exclude_fcall(sexp, args)
|
480
|
-
do_exclude_vcall(sexp, args)
|
481
|
-
end
|
482
|
-
|
483
|
-
#
|
484
|
-
# excludes :fcall and :vcall and :call (to)
|
485
|
-
#
|
486
|
-
def do_exclude_fvccall (sexp, args)
|
487
|
-
|
488
|
-
do_exclude_fvcall(sexp, args)
|
489
|
-
#do_exclude_head(sexp, cons([ :call, [ :const, :Kernel ] ], args))
|
490
|
-
do_exclude_call_to(sexp, args)
|
491
|
-
end
|
492
|
-
|
493
|
-
#
|
494
|
-
# raises a Rufus::SecurityError if the sexp is a reference to
|
495
|
-
# a certain symbol (like :gvar or :alias).
|
496
|
-
#
|
497
|
-
def do_exclude_symbol (sexp, args)
|
498
|
-
|
499
|
-
raise SecurityError.new(
|
500
|
-
args[1] || "symbol :#{excluded_symbol} is forbidden"
|
501
|
-
) if sexp == args[0]
|
502
|
-
end
|
503
|
-
|
504
|
-
#
|
505
|
-
# raises a security error if the sexp is a call on a given constant or
|
506
|
-
# module (class)
|
507
|
-
#
|
508
|
-
def do_exclude_call_on (sexp, args)
|
509
|
-
|
510
|
-
do_exclude_head(sexp, [ [:call, args[0]] ] + (args[1, -1] || []))
|
511
|
-
end
|
512
|
-
|
513
|
-
#
|
514
|
-
# this method is called by all the methods checking composite sexps.
|
515
|
-
#
|
516
|
-
def do__exclude (sexp, args, default_error_message, &block)
|
517
|
-
|
518
|
-
return unless sexp.is_a?(Array)
|
519
|
-
|
520
|
-
raise SecurityError.new(
|
521
|
-
args[1] || default_error_message
|
522
|
-
) if block.call(args)
|
523
|
-
end
|
524
|
-
|
525
|
-
#
|
526
|
-
# raises a security error if a call to a given method of any instance
|
527
|
-
# is found
|
528
|
-
#
|
529
|
-
def do_exclude_call_to (sexp, args)
|
530
|
-
|
531
|
-
do__exclude(sexp, args, "calls to '#{args[0]}' are forbidden") do
|
532
|
-
|
533
|
-
(sexp[0] == :call and sexp[2] == args[0])
|
534
|
-
end
|
535
|
-
end
|
536
|
-
|
537
|
-
def do_exclude_rebinding (sexp, args)
|
538
|
-
|
539
|
-
do__exclude(sexp, args, "rebinding '#{args[0]}' is forbidden") do
|
540
|
-
|
541
|
-
(sexp[0] == :lasgn and sexp[2] == args[0])
|
542
|
-
end
|
543
|
-
end
|
544
|
-
|
545
|
-
def do_exclude_head (sexp, args)
|
546
|
-
|
547
|
-
do__exclude(sexp, args, "#{args[0].inspect} is forbidden") do
|
548
|
-
|
549
|
-
(sexp[0, args[0].length] == args[0])
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
def do_exclude_class_tinkering (sexp, args)
|
554
|
-
|
555
|
-
return unless sexp.is_a?(Array) # lonely symbols are not class definitions
|
556
|
-
|
557
|
-
return unless sexp[0] == :class
|
558
|
-
|
559
|
-
raise SecurityError.new(
|
560
|
-
'defining or opening a class is forbidden'
|
561
|
-
) if args.length == 0 or ( ! args.include?(sexp[2]))
|
562
|
-
#
|
563
|
-
# raise error if there are no exceptions or
|
564
|
-
# if the parent class is not a member of the exception list
|
565
|
-
end
|
566
|
-
|
567
530
|
#
|
568
531
|
# a simple parse (relies on ruby_parser currently)
|
569
532
|
#
|
data/test/bm.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
require 'benchmark'
|
5
|
+
include Benchmark
|
6
|
+
|
7
|
+
require 'rufus/treechecker'
|
8
|
+
|
9
|
+
Benchmark.benchmark do |b|
|
10
|
+
|
11
|
+
tc = nil
|
12
|
+
|
13
|
+
b.report do
|
14
|
+
tc = Rufus::TreeChecker.new do
|
15
|
+
|
16
|
+
exclude_fvccall :abort, :exit, :exit!
|
17
|
+
exclude_fvccall :system, :fork, :syscall, :trap, :require, :load
|
18
|
+
|
19
|
+
#exclude_call_to :class
|
20
|
+
exclude_fvcall :private, :public, :protected
|
21
|
+
|
22
|
+
#exclude_def # no method definition
|
23
|
+
exclude_eval # no eval, module_eval or instance_eval
|
24
|
+
exclude_backquotes # no `rm -fR the/kitchen/sink`
|
25
|
+
exclude_alias # no alias or aliast_method
|
26
|
+
exclude_global_vars # $vars are off limits
|
27
|
+
exclude_module_tinkering # no module opening
|
28
|
+
exclude_raise # no raise or throw
|
29
|
+
|
30
|
+
exclude_rebinding Kernel # no 'k = Kernel'
|
31
|
+
|
32
|
+
exclude_access_to(
|
33
|
+
IO, File, FileUtils, Process, Signal, Thread, ThreadGroup)
|
34
|
+
|
35
|
+
#exclude_class_tinkering :except => OpenWFE::ProcessDefinition
|
36
|
+
exclude_class_tinkering :except => Rufus::TreeChecker
|
37
|
+
#
|
38
|
+
# excludes defining/opening any class except
|
39
|
+
# OpenWFE::ProcessDefinition
|
40
|
+
|
41
|
+
exclude_call_to :instance_variable_get, :instance_variable_set
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
DEF0 = <<-EOS
|
46
|
+
#class MyDef0 < OpenWFE::ProcessDefinition
|
47
|
+
class MyDef0 < Rufus::TreeChecker
|
48
|
+
sequence do
|
49
|
+
participant "alpha"
|
50
|
+
participant 'alpha'
|
51
|
+
alpha
|
52
|
+
end
|
53
|
+
end
|
54
|
+
EOS
|
55
|
+
|
56
|
+
N = 100
|
57
|
+
#N = 1
|
58
|
+
|
59
|
+
b.report do
|
60
|
+
N.times { tc.check(DEF0) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# before RuleSet (N=100)
|
66
|
+
#
|
67
|
+
# mettraux:rufus-treechecker[master]/$ date
|
68
|
+
# Tue Sep 2 09:33:06 JST 2008
|
69
|
+
# mettraux:rufus-treechecker[master]/$ ruby -Ilib test/bm.rb
|
70
|
+
# 0.000000 0.000000 0.000000 ( 0.004252)
|
71
|
+
# 5.680000 0.040000 5.720000 ( 5.745755)
|
72
|
+
# mettraux:rufus-treechecker[master]/$ ruby -Ilib test/bm.rb
|
73
|
+
# 0.010000 0.000000 0.010000 ( 0.004367)
|
74
|
+
# 5.670000 0.040000 5.710000 ( 5.731221)
|
75
|
+
# mettraux:rufus-treechecker[master]/$ ruby -Ilib test/bm.rb
|
76
|
+
# 0.010000 0.000000 0.010000 ( 0.004247)
|
77
|
+
# 5.670000 0.040000 5.710000 ( 5.727363)
|
78
|
+
#
|
79
|
+
|
80
|
+
#
|
81
|
+
# with RuleSet (N=100)
|
82
|
+
#
|
83
|
+
# mettraux:rufus-treechecker[master]/$ date
|
84
|
+
# Tue Sep 2 13:25:24 JST 2008
|
85
|
+
# mettraux:rufus-treechecker[master]/$ ruby -Ilib test/bm.rb
|
86
|
+
# 0.000000 0.000000 0.000000 ( 0.006439)
|
87
|
+
# 0.340000 0.000000 0.340000 ( 0.342302)
|
88
|
+
# mettraux:rufus-treechecker[master]/$ ruby -Ilib test/bm.rb
|
89
|
+
# 0.000000 0.000000 0.000000 ( 0.006269)
|
90
|
+
# 0.340000 0.000000 0.340000 ( 0.342301)
|
91
|
+
# mettraux:rufus-treechecker[master]/$ ruby -Ilib test/bm.rb
|
92
|
+
# 0.000000 0.000000 0.000000 ( 0.006350)
|
93
|
+
# 0.340000 0.000000 0.340000 ( 0.342841)
|
94
|
+
#
|
95
|
+
|
data/test/ft_0_basic.rb
CHANGED
@@ -68,6 +68,7 @@ class BasicTest < Test::Unit::TestCase
|
|
68
68
|
exclude_call_on File, FileUtils
|
69
69
|
exclude_call_on IO
|
70
70
|
end
|
71
|
+
#puts tc.to_s
|
71
72
|
|
72
73
|
assert_nok(tc, 'data = File.read("surf.txt")')
|
73
74
|
assert_nok(tc, 'f = File.new("surf.txt")')
|
@@ -99,23 +100,9 @@ class BasicTest < Test::Unit::TestCase
|
|
99
100
|
def test_5b_exclude_class_tinkering_with_exceptions
|
100
101
|
|
101
102
|
tc = Rufus::TreeChecker.new do
|
102
|
-
exclude_class_tinkering String, Rufus::TreeChecker
|
103
|
-
end
|
104
|
-
|
105
|
-
assert_nok(tc, 'class String; def length; 3; end; end')
|
106
|
-
|
107
|
-
assert_ok(tc, 'class S2 < String; def length; 3; end; end')
|
108
|
-
assert_ok(tc, 'class Toto < Rufus::TreeChecker; def length; 3; end; end')
|
109
|
-
|
110
|
-
assert_nok(tc, 'class Toto; end')
|
111
|
-
assert_nok(tc, 'class Alpha::Toto; end')
|
112
|
-
end
|
113
|
-
|
114
|
-
def test_5c_exclude_class_tinkering_with_exceptions
|
115
|
-
|
116
|
-
tc = Rufus::TreeChecker.new do
|
117
|
-
exclude_class_tinkering 'String', 'Rufus::TreeChecker'
|
103
|
+
exclude_class_tinkering :except => [ String, Rufus::TreeChecker ]
|
118
104
|
end
|
105
|
+
#puts tc.to_s
|
119
106
|
|
120
107
|
assert_nok(tc, 'class String; def length; 3; end; end')
|
121
108
|
|
@@ -238,9 +225,12 @@ class BasicTest < Test::Unit::TestCase
|
|
238
225
|
exclude_access_to File
|
239
226
|
end
|
240
227
|
|
228
|
+
#puts tc.to_s
|
229
|
+
|
241
230
|
assert_nok(tc, 'f = File')
|
242
231
|
assert_nok(tc, 'f = ::File')
|
243
232
|
assert_nok(tc, 'File.read "hello.txt"')
|
233
|
+
assert_nok(tc, '::File.read "hello.txt"')
|
244
234
|
end
|
245
235
|
|
246
236
|
#def test_X
|
@@ -28,7 +28,7 @@ class OldTreeCheckerTest < Test::Unit::TestCase
|
|
28
28
|
exclude_alias
|
29
29
|
exclude_global_vars
|
30
30
|
exclude_call_on File, FileUtils
|
31
|
-
exclude_class_tinkering Testy::Tasty
|
31
|
+
exclude_class_tinkering :except => Testy::Tasty
|
32
32
|
exclude_module_tinkering
|
33
33
|
|
34
34
|
exclude_fvcall :public
|
data/test/ft_2_clone.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Testing rufus-treechecker
|
4
|
+
#
|
5
|
+
# jmettraux at gmail.org
|
6
|
+
#
|
7
|
+
# Tue Sep 2 14:28:01 JST 2008
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'testmixin'
|
11
|
+
|
12
|
+
class CloneTest < Test::Unit::TestCase
|
13
|
+
include TestMixin
|
14
|
+
|
15
|
+
|
16
|
+
def test_0
|
17
|
+
|
18
|
+
tc0 = Rufus::TreeChecker.new do
|
19
|
+
exclude_fvccall :abort
|
20
|
+
end
|
21
|
+
|
22
|
+
tc1 = tc0.clone
|
23
|
+
tc1.add_rules do
|
24
|
+
at_root do
|
25
|
+
exclude_head [ :block ]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
assert_not_equal tc0.object_id, tc1.object_id
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
data/test/test.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rufus-treechecker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Mettraux
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-09-
|
12
|
+
date: 2008-09-02 00:00:00 +09:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -33,8 +33,10 @@ extra_rdoc_files:
|
|
33
33
|
files:
|
34
34
|
- lib/rufus
|
35
35
|
- lib/rufus/treechecker.rb
|
36
|
+
- test/bm.rb
|
36
37
|
- test/ft_0_basic.rb
|
37
38
|
- test/ft_1_old_treechecker.rb
|
39
|
+
- test/ft_2_clone.rb
|
38
40
|
- test/test.rb
|
39
41
|
- test/testmixin.rb
|
40
42
|
- README.txt
|