## call_counter.rb
module CallCounter
def count_calls_to(method_name)
original_method = instance_method(method_name)
unless class_variable_defined?(:@@call_counter):
class_variable_set(:@@call_counter, {})
end
call_counter = class_variable_get(:@@call_counter)
define_method(method_name) do |*args|
call_counter[method_name] ||= 0
call_counter[method_name] += 1
bound_original_method = original_method.bind(self)
bound_original_method.call(*args)
end
metaclass = class << self; self; end
metaclass.instance_eval do
define_method(:calls_to) do |m|
call_counter[m].nil? ? 0 : call_counter[m]
end
define_method(:reset_counters) do
call_counter.each_key do |k|
call_counter[k] = 0
end
end
end
end
end
## call_foo.rb
require "call_counter"
class CallFoo
extend CallCounter
def foo; "foo"; end
def bar; "bar"; end
count_calls_to :foo
count_calls_to :bar
end
## call_counter_spec.rb
require "call_foo"
require "spec"
describe CallFoo do
before(:each) do
@call_foo = CallFoo.new
CallFoo.reset_counters
end
it "should have a method calls_to" do
CallFoo.should respond_to(:calls_to)
end
it "method counter should be zero at start" do
CallFoo.calls_to(:foo).should == 0
end
it "should reset counters" do
4.times { @call_foo. foo }
CallFoo.reset_counters
CallFoo.calls_to(:foo).should == 0
end
it "should count the number of times a counted method has been called" do
4.times { @call_foo.foo }
CallFoo.calls_to(:foo).should == 4
end
it "should be able to count several methods' calls" do
4.times { @call_foo.foo }
CallFoo.calls_to(:foo).should == 4
7.times { @call_foo.bar }
CallFoo.calls_to(:bar).should == 7
end
it "shold count bar calls correctly, too" do
7.times { @call_foo.bar }
CallFoo.calls_to(:bar).should == 7
end
end