Skip to content

Instantly share code, notes, and snippets.

@dbenhur
Forked from avdi/match_method.rb
Created December 8, 2011 01:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dbenhur/1445597 to your computer and use it in GitHub Desktop.
Save dbenhur/1445597 to your computer and use it in GitHub Desktop.
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, &blk|
if matcher === method_name.to_s
instance_exec(method_name, *args, blk, &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 = args.pop if args.last.is_a? Proc
suffix = " with #{block.call}" if block
food = /\Asudo_make_me_a_(.*)$/.match(name.to_s)[1]
"Coming right up, one #{food}#{suffix}"
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
puts foo.respond_to?(:fix_me_a_sandwich) # => false
puts foo.respond_to?(:make_me_a_sandwich) # => true
puts foo.respond_to?(:sudo_make_me_a_sandwich) # => true
puts foo.fix_me_a_sandwich # => "We don't do that kind of thing here"
puts foo.make_me_a_sandwich # => "Make your own damn sandwich"
puts foo.sudo_make_me_a_sandwich # => "Coming right up, one sandwich"
puts foo.sudo_make_me_a_sandwich { 'love' } # => "Coming right up, one sandwich with love"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment