Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Defining method_missing and respond_to? in one fell swoop
# Do you ever define #method_missing and forget #respond_to? I sure
# do. It would be nice if we could do them both at the same time.
module MatchMethodMacros
def match_method(matcher, &method_body)
mod = Module.new do
define_method(:method_missing) do |method_name, *args|
if matcher === method_name.to_s
instance_exec(method_name, *args, &method_body)
else
super(method_name, *args)
end
end
define_method(:respond_to_missing?) do |method_name, include_private|
# Even though this is in the #respond_to_missing? hook we
# still need to call 'super' in case there are other included
# modules which also define #respond_to_missing?
(matcher === method_name) || super(method_name, include_private)
end
end
include mod
end
end
class Foo
extend MatchMethodMacros
match_method(/\Amake_me_a_/) do |name, *args|
food = /\Amake_me_a_(.*)$/.match(name.to_s)[1]
"Make your own damn #{food}"
end
match_method(/\Asudo_make_me_a/) do |name, *args, &block|
food = /\Asudo_make_me_a_(.*)$/.match(name.to_s)[1]
"Coming right up, one #{food}"
end
def method_missing(name, *args)
# match_method uses modules, so we can use super to delegate to
# the generated #method_missing definitions.
super
rescue NoMethodError
"We don't do that kind of thing here"
end
end
foo = Foo.new
foo.respond_to?(:fix_me_a_sandwich) # => false
foo.respond_to?(:make_me_a_sandwich) # => true
foo.respond_to?(:sudo_make_me_a_sandwich) # => true
foo.fix_me_a_sandwich # => "We don't do that kind of thing here"
foo.make_me_a_sandwich # => "Make your own damn sandwich"
foo.sudo_make_me_a_sandwich # => "Coming right up, one sandwich"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment