class_eval evaluates a string or block in a class-definition context; module_eval is its alias. It provides an ad hoc way to enter an existing class or module rather than opening it with the class keyword. section 14.4 section 14.4.4
Use class_eval when ordinary class syntax is insufficient:
- Evaluate a string as code in a class-definition context. section 14.4
- Open an anonymous class such as Class.new and define instance methods on it. section 14.4.4
- Preserve access to surrounding local variables inside the class_eval block. section 14.4.4
Block scope versus method scope
var = "initialized variable" C.class_eval { puts var } # initialized variable C.class_eval { def talk; puts var; end } C.new.talk # NameError The class_eval block can see var, but def starts a new scope. To retain the variable, define the method with define_method: C.class_eval { define_method("talk") { puts var } } C.new.talk # initialized variable section 14.4.4
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
A compact MicroTest implementation uses class_eval inside inherited to install method_added on each subclass, then runs newly defined test methods with setup and assertions. section 15.5.2
