This is a rather standard metaprogramming technique that was popularized many years ago by the BlankSlate
and XmlBase
classes in Jim Weirich's builder
Gem.
The main idea is to create a "blank slate" object, i.e. an object that has no methods, and then record all method calls on this object.
Here is one possible implementation:
class Squirrel
class Recorder < BasicObject
(instance_methods + private_instance_methods).each(&method(:undef_method))
def method_missing(method) @actions << method.to_s end
end
attr_reader :actions, :recorder
private
attr_writer :actions, :recorder
def initialize
self.actions = []
self.recorder = Recorder.allocate
Object.public_instance_method(:instance_variable_set).bind(recorder).(:@actions, actions)
end
public def fight(&block)
BasicObject.public_instance_method(:instance_eval).bind(recorder).(&block)
end
end
require 'minitest/autorun'
describe Squirrel do
before do @squirrel = Squirrel.new end
describe '#fight' do
it 'should record its actions' do
@squirrel.fight do jump; kick; punch; jump end
@squirrel.actions.must_equal %w[jump kick punch jump]
end
end
end