Timmy, Redux

I took Timmy Printface offline today, after a week of valiant service.

While in many respects I would’ve loved to have kept our little printer running indefinitely, I think it’s important not to become too attached to these things. It was a hack, after all (read more on the free range blog you haven’t already).

To commemorate the project, I gathered the timelapse video that had been quietly accumulating, and wrapped it up into a little video package to remind us of all the good times we had:

After tweeting that Timmy was going to sleep, it took me about an hour to actually work up the determination to unplug him.

I replaced the live webcam image with the video above on both his home page and the blog post, and disconnected the camera that was pointing at him, but I was struggling to finally shut down the processes and pull out the wires that would actually stop any further messages from being printed.

Timmy had been involved in conversations with people from all over the world; friends and strangers, all sending him messages on their phone like they would to anyone else they knew. In an emergent and collaborative act of anthropomorphism, Timmy had acquired a personality, and a life of his own.

All good things…

Eventually I got over it, disconnected everything, put the wires and chips back in their right places, and turned off the software brain that was Timmy himself, but not before carefully archiving everything, gathering up the software, libraries, images and movies that summed up his existence. They’re all in a folder on my computer now, a static description of both the system and it’s operation during one week in April 2011.

This is the last message that Timmy received:

Thankfully, Timmy hasn’t been eaten by a grue. He’s sat up on our shelf, waiting to be called upon again. I’m sure this isn’t the last we’ll see of Timmy Printface, and I find that notion comforting.

interblah.net - Capturing behaviour in Ruby DSLs

Capturing behaviour in Ruby DSLs

A WORK IN STAGNANT PROGRESS

As part of the work I did implementing Kintama, I found myself flip-flopping between two different ways of capturing test implementations and running them. I think there’s something interesting and perhaps useful in making these approaches more explicit.

I’m trying to elucidate them here, but this is very much a work in progress, and it’s nowhere near finished.

Anyway.

The two means of behaviour slinging

It’s a likely encounter any Ruby programmer, but a certainty for any programmer writing a test framework: at some point you’ll realise there are two fundamental ways of capture and calling “behaviour” in Ruby: Methods, and blocks. The same thing applies to any DSL you might implement, and test frameworks like shoulda and RSpec are indeed DSLs for testing.

Allow me to illustrate.

Let’s say we want to write a couple of tests using the following DSL:

test "something" do
  assert 1 == 1
end

test "another thing" do
  assert false == true
end

When it comes to “running” that test, you basically have two choices – capture the behaviour as a method body and call that method, or use one of the various block/proc calling mechanisms to evaluate the block within a sensible context.

Here’s a trivial implementation of the ‘method’ approach:

def assert(expression)
  raise "Test failed" unless expression
end

$tests = []

def test(name, &block)
  test_name = "test #[snip 'name' cannot be found]"
  self.class.send(:define_method, test_name, &block)
  $tests << test_name
end

def run(tests)
  failures = []
  tests.each do |test|
    begin
      send(test)
      print "."
    rescue => e
      failures << test
      print "F"
    end
  end
  puts "\n\n#[snip 'tests' cannot be found] tests; #[snip 'failures' cannot be found] failures"
  puts "\n#(malformed snip inclusion: {failures.map { |f| "Failed: #{f})" }.join("\n")}\n\n"
end

test "something" do
  assert 1 == 1
end

test "another thing" do
  assert false == true
end

run($tests)

For each “test”, we are defining a method using the name of the test, and then storing those names. When we want to run all the tests, we use send to invoke each of the methods we created.

Here’s the corresponding implementation for a block-based approach:

def assert(expression)
  raise "Test failed" unless expression
end

$tests = {}

def test(name, &block)
  test_name = "test #[snip 'name' cannot be found]"
  $tests[test_name] = block
end

def run(tests)
  failures = []
  tests.each do |test_name, test_block|
    begin
      test_block.call
      print "."
    rescue => e
      failures << test_name
      print "F"
    end
  end
  puts "\n\n#[snip 'tests' cannot be found] tests; #[snip 'failures' cannot be found] failures"
  puts "\n#(malformed snip inclusion: {failures.map { |f| "Failed: #{f})" }.join("\n")}\n\n"
end

test "something" do
  assert 1 == 1
end

test "another thing" do
  assert false == true
end

run($tests)

As you can tell, the implementations are very, very similar. The key difference is that in the second, we are stashing the blocks in a hash, and then using call to run them as procs.

This is interesting for a test-framework implementer because once your tests include some form of state, the choice you make above will have a fairly large impact on the resulting architecture of your framework.

Next steps

… actually explain what the consequences are. Basically it relates to whether or not your tests end up being actual classes/objects or not. It’s pretty hard to show differences in blog form; it might be better to have a simple DSL which I implement using either form and step through the commits.