Created
June 6, 2012 05:20
-
-
Save mrbrdo/2880057 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rspec' | |
# TODO: class vars? | |
# TODO: better just alias_method_chain method_missing for the duration of running the method | |
module Tdef | |
def self.check_args(args, rules) | |
rules.each_pair do |name, klass| | |
unless args[name.to_s].kind_of?(klass) | |
raise "Wrong type: #{name} should be #{klass.to_s}, but is #{args[name].class.to_s}" | |
end | |
end | |
end | |
def tdef name, args, &block | |
self.send(:define_method, name.to_sym) do |*arg_values| | |
raise "Wrong number of arguments" if args.count != arg_values.count | |
args_map = Hash.new | |
(0...arg_values.count).each do |i| | |
args_map[args.keys[i].to_s] = arg_values[i] | |
end | |
Tdef::check_args(args_map, args) | |
self.class.send(:alias_method, :method_missing_tmp, :method_missing) | |
self.class.send(:define_method, :method_missing) do |meth, *args, &block| | |
if args_map.keys.include?(meth.to_s) | |
args_map[meth.to_s] | |
else | |
if self.respond_to?(:method_missing_tmp) | |
method_missing_tmp meth, *args, &block | |
else | |
super(meth, *args, &block) | |
end | |
end | |
end | |
result = self.instance_eval &block | |
self.class.send(:remove_method, :method_missing) | |
self.class.send(:alias_method, :method_missing, :method_missing_tmp) | |
# No harm in leaving the method_missing_tmp there | |
# self.class.send(:remove_method, :method_missing_tmp) | |
result | |
end | |
end | |
end | |
# Test class | |
class TestClass | |
extend Tdef | |
tdef :hello, :a1 => Integer, :a2 => String do | |
a2 = "Goodbye" | |
@lala = 999 | |
[a1, a2, missing_arg] | |
end | |
def method_missing meth, *args, &block | |
if meth.to_s == "missing_arg" | |
"lolario" | |
else | |
super | |
end | |
end | |
end | |
# Tests | |
describe TestClass do | |
it "works" do | |
k = TestClass.new | |
expect { k.hello }.should_not raise_error(NoMethodError) | |
r1, r2, r3 = k.hello(10, "Hello") | |
r1.should eq(10) | |
r2.should eq("Goodbye") | |
r3.should eq("lolario") | |
k.instance_variable_get("@lala").should eq(999) | |
expect { k.a1 }.should raise_error(NoMethodError) | |
expect { k.a2 }.should raise_error(NoMethodError) | |
defined?(a1).should be_nil | |
defined?(a2).should be_nil | |
end | |
it "detects wrong arguments" do | |
k = TestClass.new | |
expect { k.hello(10, 20) }.should raise_error | |
expect { k.hello("Hello", "World") }.should raise_error | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment