The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
Ruby: Recording Method Calls and Playback With Inject

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Jay Fields

Posts: 765
Nickname: jayfields
Registered: Sep, 2006

Jay Fields is a software developer for ThoughtWorks
Ruby: Recording Method Calls and Playback With Inject Posted: Sep 3, 2008 10:48 PM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Jay Fields.
Original Post: Ruby: Recording Method Calls and Playback With Inject
Feed Title: Jay Fields Thoughts
Feed URL: http://feeds.feedburner.com/jayfields/mjKQ
Feed Description: Blog about Ruby, Agile, Testing and other topics related to software development.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Jay Fields
Latest Posts From Jay Fields Thoughts

Advertisement
Sometimes you want to call methods on an object, but you want to delay the actual execution of those methods till a later time.

For example, in expectations you create a mock at parse time, but you actually want the mock to be available at execution time.

class SystemProcess
def start
puts "started"
new StartedProcess
end
end

Expectations do
expect SystemProcess.new.to.receive(:start) do |process|
process.start
end
end

In 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.

class Recorder
attr_reader :subject
def initialize(subject)
@subject = subject
end

def replay
method_stack.inject(subject) { |result, element| result.send element.first, *element.last }
end

def method_stack
@method_stack ||= []
end

def method_missing(sym, *args)
method_stack << [sym, args]
self
end
end

Here's an example usage of a recorder.

class SystemProcess
def start(in_seconds)
puts "starting in #{in_seconds}"
sleep in_seconds
StartedProcess.new
end
end

class StartedProcess
def pause(in_seconds)
puts "pausing in #{in_seconds}"
sleep in_seconds
PausedProcess.new
end
end

class PausedProcess
def stop(in_seconds)
puts "stopping in #{in_seconds}"
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.

Read: Ruby: Recording Method Calls and Playback With Inject

Topic: Grails Presentations Open Sourced on GitHub Previous Topic   Next Topic Topic: Passionate, Not Dogmatic

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use