Whenever you define method_missing to accomplish some metatrickery you need to remember to also redefine respond_to? so that it reflects the same new logic which you’ve added to method_missing. This is annoying to do and people don’t always do it. For example, Rails dynamic finders will not respond_to? properly (until after they’re called for the first time).
I thought up a little way to get both the method_missing logic and respond_to? logic working without any duplication needed. We define a new method, method_missing_proc, which instead of actually running code returns a lambda with the code that should be run. If no code should be run, nil is returned. With this, respond_to? can call method_missing_proc and if the return result is non-nil it knows to return true. method_missing can call method_missing_proc and then call the lambda if one is returned otherwise calling the original method_missing method to allow the method lookup chain to continue.
Update: I decided to include an implementation for the method method as well. I was talking to someone who had a legitimate-ish use case for having it. Now when someone calls object.method(:something), if method_missing_proc returns a lambda for that method name, an actual method will be created on the singleton class of the object and a Method object representing it returned.
Here’s the implementation:
class Object
alias_method :old_method_missing, :method_missing
def method_missing m, *a, &b
l = method_missing_proc m, *a, &b
return l.call if l
old_method_missing m, *a, &b
end
alias_method :old_respond_to?, :respond_to?
def respond_to? m
old_respond_to?(m) || !!method_missing_proc(m.to_sym)
end
alias_method :old_method, :method
def method m
old_method m
rescue NameError
l = method_missing_proc m
(class<<self;self;end).class_eval { define_method m, &l }
retry
end
def method_missing_proc *a; nil; end
end
And here’s an example of it in use:
class X
def method_missing_proc m, *a, &b
case m.to_s
when /^hello_(\w+)$/
lambda { puts "hello #{$1.gsub('_',' ')}" }
when /^say_(\w+)_to$/
lambda do
raise ArgumentError, "You must specify who to say #$1 to" if a.empty?
puts "#{a.first}: #$1"
end
else
super
end
end
end
x = X.new
p x.respond_to?(:hello_my_friend) # => true
p x.respond_to?(:hello_world) # => true
p x.respond_to?(:say_hi_to) # => true
p x.respond_to?(:goodbye_world) # => false
x.hello_world # => hello world
x.say_hi_to :sam # => sam: hi
x.say_hi_to rescue p $! # => #<ArgumentError: You must specify who to say hi to>
x.goodbye_world rescue p $! # => #<NoMethodError: undefined method `goodbye_world' for #<X:0xb7c576c0>>
# this time the method will actually be generated
p x.method(:hello_my_good_friend) # => #<Method: #<X:0xb7a93064>.hello_my_good_friend>
# this time the method will already exist
p x.method(:hello_my_good_friend) # => #<Method: #<X:0xb7a93064>.hello_my_good_friend>
Right after writing this I found that Mark Hubbart had already come up with the same solution over 3 years ago in the ruby-talk mailing list. His implementation is very similar, I swear I didn’t steal it! He actually went a step further and overrided the ‘method’ method to return the lambda from method_missing_proc. I’m not so sure if this is a good idea since you wouldn’t be getting back an actual Method object. Although you could modify the code to create a temporary method and return a Method object pointing to that. I’m not sure how important overriding ‘method’ is anyway.
So does anyone think this method_missing_proc technique is actually useful? Or just solving a problem which doesn’t exist?

Very useful. I have implemented method_missing on several occasions but rarely do it completely enough to cover respond_to? (or even method).
Your strategy would allow me to have a more complete implementation without any more work. Always a win. I would think this would be something nice to implement in a support library like ActiveSupport or Facets. This way I would have to think about it. Just implement method_missing_proc and done.
Comment by Eric Anderson — July 11, 2008 @ 2:30 pm
The ActiveRecord dynamic finder problem that you mention was fixed in my patch – http://dev.rubyonrails.org/ticket/11538.
Comment by Floehopper — July 13, 2008 @ 1:19 pm
hey thats pretty cool
Comment by hellobennguyen — July 14, 2008 @ 1:03 pm
[...] might want to be aware of. If a class implements methods through a method_missing method then try might not recognize a valid method call because respond_to? will return false, and therefor try will return nil instead of the value that [...]
Pingback by Try() as you might | Lambda @ Copa — January 11, 2009 @ 12:43 pm
Very nice and almost totally removes my objections against (the overuse of) method_missing. One should be able to ask the duck if it walks like one without having to make it actually walk.
Comment by Jonas Elfström — October 9, 2009 @ 6:32 pm
pasted from my skype discussion about this comment thread.
[22:03:24] Marcos Toledo: the fact is that you can’t really know if the duck walks like a duck unless it can walk without parameters
[22:04:09] Marcos Toledo: you can only know if it can or cannot walk. and to me, asking how it walks without making it walk is probably wrong
Comment by mtoledo — October 9, 2009 @ 8:07 pm