Reputation: 345
I came across this solution for a Proxy class in the Ruby koans:
class Proxy
attr_accessor :messages
def initialize(target_object)
@object = target_object
@messages = []
end
def method_missing(method_name, *args, &block)
@messages << method_name
@object.send(method_name, *args, &block)
end
end
I can create an object from this proxy class by passing another class as an argument. For instance, the following code will result in "Do something"
, without having to type thing.method_missing(:do_thing)
:
class Thing
def do_thing
puts "Doing something."
end
end
thing = Proxy.new(Thing.new)
thing.do_thing
Why is the code in method_missing
executed even without having to call said method?
Upvotes: 2
Views: 195
Reputation: 168111
There are methods that are called implicitly (i.e., called even when you don't write it in the code) when a certain event happens or a certain method is called. I call these methods hooks, borrowing the terminology of e-lisp. As far as I know, Ruby has the following hooks:
Ruby hooks
at_exit
set_trace_func
initialize
method_missing
singleton_method_added
singleton_method_removed
singleton_method_undefined
respond_to_missing?
extended
included
method_added
method_removed
method_undefined
const_missing
inherited
initialize_copy
initialize_clone
initialize_dup
prepend
append_features
extend_features
prepend_features
And method_missing
is one of them. For this particular one, it is automatically called when Ruby cannot find a defined method. Or in other words, method_missing
is the most default method that is called with the least priority, for any method call.
Upvotes: 4
Reputation: 1779
method_missing
is one of the amazing aspects of metaprogramming
in ruby. With proper use of this method, you can gracefully handle exceptions and whatnot. In your case it is called because the method you are calling on the object doesn't exist obviously.
But one should be careful of its use too. While you are at it do look at responds_to
method too.
An example regarding ActiveRecord
will make you understand better. When we write:
User.find_by_email_and_age('[email protected]', 20)
There isn't actually a method by that name. This call goes to the method_missing
and then this fancyfind
method is broken down into pieces and you are served what you asked for. I hope that helps.
Upvotes: 1