rufus-treechecker 1.0.1 → 1.0.2
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.
- 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
|