Cheap Advice
- Kurt Stephens
- Enova Financial — http://enovafinancial.com
- 2011/11/14
- Slides — http://kurtstephens.com/pub/cheap_advice.slides/index.html
- Code — http://github.com/kstephens/cheap_advice
class MyClass
def foo; 42; end
end
class MyOtherClass
def bar; 43; end
end
a = MyClass.new
b = MyOtherClass.new
a.foo
b.bar
class MyClass
def foo
$stderr.puts "#{self}#foo => 42"
42
end
end
class MyOtherClass
def bar
$stderr.puts "#{self}#bar => 43"
43
end
end
a = MyClass.new
b = MyOtherClass.new
a.foo
b.bar
class MyClass
def foo
raise "SecurityError" unless $roles.include?("MyClass#foo")
$stderr.puts "#{self}#foo => 42"
42
end
end
class MyOtherClass
def bar
raise "SecurityError" unless $roles.include?("MyClass#bar")
$stderr.puts "#{self}#bar => 43"
43
end
end
a = MyClass.new
b = MyOtherClass.new
$roles = [ "MyClass#foo" ]
a.foo
b.bar
class MyClass
def foo
# YUCK!: raise "SecurityError" unless $roles.include?("MyClass#foo")
# YUCK!: $stderr.puts "#{self}#foo => 42"
42
end
end
class MyOtherClass
def bar
# YUCK!: raise "SecurityError" unless $roles.include?("MyClass#bar")
# YUCK!: $stderr.puts "#{self}#bar => 43"
43
end
end
a = MyClass.new
b = MyOtherClass.new
$roles = [ "MyClass#foo" ] # ???
a.foo
b.bar
… are not problem-domain issues.
# Advice
trace_advice = CheapAdvice.new(:around) do | ar, body |
ar.advice[:log] <<
"#{Time.now.iso8601(6)} " <<
"#{ar.rcvr.class} #{ar.meth} #{ar.rcvr.object_id}\n"
body.call
ar.advice[:log] <<
"#{Time.now.iso8601(6)} " <<
"#{ar.rcvr.class} #{ar.meth} #{ar.rcvr.object_id} " <<
"=> #{ar.result.inspect}\n"
end
# State attached to trace_advice.
trace_advice[:log] = File.open("trace.log", "a+")
...
# Activate trace_advice:
trace_advice.advise!(MyClass, :foo)
trace_advice.advise!(MyOtherClass, :bar)
a.foo
b.bar
# Disable trace_advice:
trace_advice.disable!
a.foo
b.bar
:advice:
~:
:enabled: false
:options:
:trace:
:logger:
:name: :default
'MyClass':
:advice: trace
'MyClass#foo':
:enabled: false
'MyClass#bar':
:enabled: false
You get the idea.