Class: Trace::Filter
- Inherits:
-
Object
- Object
- Trace::Filter
- Defined in:
- lib/tracefilter.rb
Overview
A class that can be used to test whether certain methods should be excluded. We also convert the hook call to pass a threadframe and an event rather than event and those other 5 parameters.
Instance Attribute Summary collapse
-
#excluded ⇒ Object
readonly
Returns the value of attribute excluded.
-
#hook_proc ⇒ Object
readonly
Returns the value of attribute hook_proc.
Instance Method Summary collapse
-
#<<(meth) ⇒ Object
Add
meth
to list of trace filters. -
#add_trace_func(hook_proc, event_mask = nil) ⇒ Object
Replacement for Kernel.add_trace_func.
-
#clear ⇒ Object
Null out list of excluded methods.
-
#initialize(excluded_meths = []) ⇒ Filter
constructor
A new instance of Filter.
-
#member?(meth) ⇒ Boolean
Returns
true
ifmeth
is a member of the trace filter set. -
#remove(meth) ⇒ Object
Remove
meth
from the list of functions to include. -
#remove_trace_func ⇒ Object
FIXME: remove just this trace function.
-
#set_trace_func(hook_proc, event_mask = nil) ⇒ Object
Replacement for Kernel.set_trace_func.
-
#trace_hook(event, file, line, id, binding, klass) ⇒ Object
A shim to convert between older-style trace hook call to newer style trace hook using RubyVM::Frame.
-
#valid_meth?(fn) ⇒ Boolean
fn
should be a RubyVM::Frame object or a Proc which has an instruction sequence.
Constructor Details
#initialize(excluded_meths = []) ⇒ Filter
Returns a new instance of Filter.
17 18 19 20 21 |
# File 'lib/tracefilter.rb', line 17 def initialize(excluded_meths = []) excluded_meths = excluded_meths.select{|fn| valid_meth?(fn)} excluded_meths << self.method(:set_trace_func).to_s @excluded = Set.new(excluded_meths.map{|m| m.to_s}) end |
Instance Attribute Details
#excluded ⇒ Object (readonly)
Returns the value of attribute excluded.
14 15 16 |
# File 'lib/tracefilter.rb', line 14 def excluded @excluded end |
#hook_proc ⇒ Object (readonly)
Returns the value of attribute hook_proc.
15 16 17 |
# File 'lib/tracefilter.rb', line 15 def hook_proc @hook_proc end |
Instance Method Details
#<<(meth) ⇒ Object
Add meth
to list of trace filters.
30 31 32 33 34 35 36 37 |
# File 'lib/tracefilter.rb', line 30 def <<(meth) if valid_meth?(meth) @excluded << meth.to_s return true else return false end end |
#add_trace_func(hook_proc, event_mask = nil) ⇒ Object
Replacement for Kernel.add_trace_func. hook_proc should be a Proc that takes two arguments, a string event, and threadframe object.
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/tracefilter.rb', line 124 def add_trace_func(hook_proc, event_mask=nil) if hook_proc.nil? Kernel.set_trace_func(nil) return end raise TypeError, "trace_func needs to be Proc or nil (is #{hook_proc.class})" unless hook_proc.is_a?(Proc) raise TypeError, "arity of hook_proc should be 2 or -3 (is #{hook_proc.arity})" unless 2 == hook_proc.arity || -3 == hook_proc.arity @hook_proc = hook_proc if event_mask Trace::add_trace_func(method(:trace_hook).to_proc, event_mask) else Kernel.add_trace_func(method(:trace_hook).to_proc) end end |
#clear ⇒ Object
Null out list of excluded methods
40 41 42 |
# File 'lib/tracefilter.rb', line 40 def clear @excluded = Set.new end |
#member?(meth) ⇒ Boolean
Returns true
if meth
is a member of the trace filter set.
45 46 47 48 49 50 51 |
# File 'lib/tracefilter.rb', line 45 def member?(meth) if valid_meth?(meth) @excluded.member?(meth.to_s) else false end end |
#remove(meth) ⇒ Object
Remove meth
from the list of functions to include.
54 55 56 57 |
# File 'lib/tracefilter.rb', line 54 def remove(meth) return nil unless valid_meth?(meth) @excluded -= [meth.to_s] end |
#remove_trace_func ⇒ Object
FIXME: remove just this trace function
143 144 145 |
# File 'lib/tracefilter.rb', line 143 def remove_trace_func Kernel.clear_trace_func end |
#set_trace_func(hook_proc, event_mask = nil) ⇒ Object
Replacement for Kernel.set_trace_func. proc should be a Proc that takes two arguments, a string event, and threadframe object.
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/tracefilter.rb', line 150 def set_trace_func(hook_proc, event_mask=nil) if hook_proc.nil? Kernel.set_trace_func(nil) return end raise TypeError, "trace_func needs to be Proc or nil (is #{hook_proc.class})" unless hook_proc.is_a?(Proc) raise TypeError, "arity of hook_proc should be 2 or -3 (is #{hook_proc.arity})" unless 2 == hook_proc.arity || -3 == hook_proc.arity @hook_proc = hook_proc if event_mask Trace::set_trace_func(method(:trace_hook).to_proc, event_mask) else Kernel.set_trace_func(method(:trace_hook).to_proc) end end |
#trace_hook(event, file, line, id, binding, klass) ⇒ Object
A shim to convert between older-style trace hook call to newer style trace hook using RubyVM::Frame. Methods stored in @excluded
are ignored.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/tracefilter.rb', line 62 def trace_hook(event, file, line, id, binding, klass) tf = RubyVM::Frame::current.prev # FIXME: Clean this mess up. And while your at it, understand # what's going on better. tf_check = tf while %w(IFUNC CFUNC).member?(tf_check.type) do tf_check = tf_check.prev end return unless tf_check begin if tf_check.method && !tf_check.method.empty? meth_name = tf_check.method.gsub(/^.* in /, '') meth = eval("self.method(:#{meth_name})", tf_check.binding) if @excluded.member?(meth.to_s) # Turn off tracing for any calls from this frame. Note # that Ruby turns of tracing in the thread of a hook while # it is running, but I don't think this is as good as # turning it off in the frame and frames called from that. # Example: if a trace hook yields to or calls a block # outside not derived from the frame, then tracing should # start again. But either way, since RubyVM::Frame # allows control over tracing *any* decision is not # irrevocable, just possibly unhelpful. tf_check.trace_off = true return end end rescue NameError rescue SyntaxError rescue ArgumentError end while %w(IFUNC).member?(tf.type) do tf = tf.prev end # There is what looks like a a bug in Ruby where self.class for C # functions are not set correctly. Until this is fixed in what I # consider a more proper way, we'll hack around this by passing # the binding as the optional arg parameter. arg = if 'CFUNC' == tf.type && NilClass != klass klass elsif 'raise' == event # As a horrible hack to be able to get the raise message on a # 'raise' event before the event occurs, I changed RubyVM to store # the message in the class field. klass else nil end retval = @hook_proc.call(event, tf, arg) if retval.respond_to?(:ancestors) && retval.ancestors.include?(Exception) raise retval end end |
#valid_meth?(fn) ⇒ Boolean
fn
should be a RubyVM::Frame object or a Proc which has an instruction sequence
25 26 27 |
# File 'lib/tracefilter.rb', line 25 def valid_meth?(fn) fn.is_a?(Method) end |