Skip to content

Instantly share code, notes, and snippets.

@stackdump
Created August 16, 2012 21:47
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 stackdump/3373898 to your computer and use it in GitHub Desktop.
Save stackdump/3373898 to your computer and use it in GitHub Desktop.
sample illustration of meta-programming with method_missing & respond_to
class Foo
TEST=[:foo, :bar]
def self.count_foo
TEST.find_index(:foo)
end
#TODO try to reuse method missing code between class & instance methods
def self.method_missing(sym, *args, &block)
if respond_to?(sym)
send(sym, args){ yield block } #TODO should branch based on block_given?
else
super(sym, args, block)
end
end
def self.respond_to?(sym)
super(sym) || add_count_method(sym)
end
private
def self.add_count_method(sym)
return false unless /^count_(?<key>[a-zA-Z]\w*)$/ =~ sym
instance_eval <<METHOD
def self.#{sym}(args=[], &block)
TEST.find_index(:"#{key}")
end
METHOD
return true
end
end
describe Foo do
context 'using class method' do
it 'should allow seemless :respond_to calls' do
Foo.should respond_to :count_foo #pre-defined method
Foo.should respond_to :count_bar
Foo.should respond_to :count_baz
Foo.should respond_to :count_a1
Foo.should_not respond_to :count_1
Foo.should_not respond_to :count_
Foo.should_not respond_to :baz
end
it 'should allow dynamic method creation' do
Foo.count_foo.should == 0
Foo.count_bar.should == 1
Foo.count_baz.should be_nil
Foo.count_a1.should be_nil
end
it 'should still raise normal method_missing error' do
lambda { Foo.baz }.should raise_error(NoMethodError)
end
it 'should still allow passing of blocks' do
pending 'rewrite test to use blocks'
end
end
context 'using instance methods' do
it 'should not create instance methods' do
f = Foo.new
f.should_not respond_to :count_bar
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment