Ruby’s method_added callback observes instance-method definitions. Define it as a class method, and Ruby calls it whenever an instance method is defined or redefined, passing the method’s name. section 15.1.6
Reporting a newly defined method
class C def self.method_added(m) puts "Method #{m} was just defined." end def a_new_method end end # Method a_new_method was just defined. section 15.1.6
The callback receives the method name, which can drive runtime behavior. MicroTest installs method_added on each subclass; when a newly defined name starts with test, it creates an instance, runs optional setup, and invokes that method with send. section 15.5.2
Listing 15.7 MicroTest, a testing class that emulates some MiniTest functionality
require_relative 'callertools'
class MicroTest
def self.inherited(c)
c.class_eval do
def self.method_added(m)
if m =~ /^test/ 1
obj = self.new 2
if obj.methods.include?(:setup) 3
obj.setup
end
obj.send(m)
end
end
end
end
def assert(assertion) 4
if assertion
puts "Assertion passed"
true
else
puts "Assertion failed:"
stack = CallerTools::Stack.new 5
failure = stack.find {|call| call.meth !~ /assert/ } 5
puts failure
false
end
end
def assert_equal(expected, actual) 6
result = assert(expected == actual)
puts "(#{actual} is not #{expected})" unless result 7
result
end
end
Browse the complete MicroTest implementation, including inherited, class_eval, method_added, setup, test-method filtering, and assertion handling. section 15.5.2
