I revisited my Event.observe proof of concept and tidied it up a bit with a little help from stackoverflow.com.
Here’s how it do
This here defines a method to determine which method is currently running. There’s a slicker way to do this in 1.9 and you can read about them both on stackoverflow.com.
module Kernel
private
def current_method_name
caller[0] =~ /`([^']*)'/ and $1
end
end
Here’s my actual observer class, named after it’s inspiration.
class Event
def initialize
@events = []
end
def observe object, method, callback
handle = Handle.new self, object, method, callback
@events << handle
handle
end
def delete handle
@events.delete handle
end
def call object, method
handle = Handle.new self, object, method
@events.each do |e|
e.call if e.shares_type_with
end
end
end
And finally there's a basic handle class:
class Handle
attr_reader :observer, :object, :method, :callback
def initialize observer, object, method, callback = nil
@observer = observer
@object = object
@method = method
@callback = callback
end
def shares_type_with? handle
object == handle.object && method == handle.method
end
def call
callback.call
end
def stop_observing
observer.delete self
end
end
And here's how you use it, In the following example we want our "second" Test_Object to run it's test_method whenever we run the same method for our "first" object.
The important thing here is the "notify" method, you'll need to drop this method into whatever you'd like to be able to observe. If you wanted to be able to observe everything you could always loop through the methods, alias and override.
class Test_Object
def initialize observer, label
@observer = observer
@label = label
end
def notify method
@observer.call self, method
end
def test_method
puts "Calling => #{@label}"
notify current_method_name
end
end
observer = Event.new
first = Test_Object.new observer, "First"
second = Test_Object.new observer, "Second"
h1 = observer.observe(
first,
"test_method",
second.method :test_method
)
first.test_method
# Calling First
# Calling Second
#=> nil
And we can drop the handle by simply calling it's stop_observing method
h1.stop_observing
first.test_method
# Calling First
#=> nil
That's it.
Download the Proof of Concept!