For example, in expectations you create a mock at parse time, but you actually want the mock to be available at execution time.
puts "started"
new StartedProcess
end
end
Expectations do
expect SystemProcess.new.to.receive(:start) do |process|
process.start
end
endIn the above code you define what you expect when the file is parsed, but you actually want the process expectation to be set when the do block is executed. This can be (and is) achieved by using a recorder to record all the method calls on the process object. At execution time the method calls are played back and the initialized process object is yielded to the block.
The code for a recorder is actually quite trivial in Ruby.
attr_reader :subject
@subject = subject
end
method_stack.inject(subject) {|result, element| result.send element.first, *element.last }
end
@method_stack ||= []
end
method_stack << [sym, args]
self
end
endHere's an example usage of a recorder.
puts "starting in "
sleep in_seconds
StartedProcess.new
end
end
puts "pausing in "
sleep in_seconds
PausedProcess.new
end
end
puts "stopping in "
sleep in_seconds
self
end
end
Recorder.new(SystemProcess.new).start(1).pause(2).stop(3).replay
# >> starting in 1
# >> pausing in 2
# >> stopping in 3
The only thing worth noting is that by using inject you can use a method chain that returns different objects. Traditional versions of a recorder that I've seen often assume that all the methods should be called on the subject. I prefer the version that allows for object creation within the fluent interface. In practice, that's exactly what was needed for recording and playing back Mocha's expectation setting methods.