This is something I've come up against twice. First, I have an interactive editor which calls vi, emacs, or TextMate (etc.) via Unix, and then loads the file handed to the editor back into IRB after it's edited and saved. I guess that makes it a special case of a more general question, which is how do you spec external processes, with a slightly more complicated version of the standard answer, mocks.
The second instance is more complicated. I'm writing a MIDI code generator and using it to drive Propellerhead Reason, which is third-party closed-source commercial software which will run on my OS X box but which is not actually transparent to Unix in any meaningful way that I'm aware of. (The code generator can very probably also drive any arbitrary MIDI consumer.) I'm using code from Topher Cyll's book "Practical Ruby Projects" to create Ruby wrappers to C methods in Apple's CoreMIDI library. The trap here is I'm calling those C methods to generate MIDI elsewhere in the OS in some unknown way. That makes speccing weird. I've been able to refactor this code in a kind-of spec-first way. I write scripts which use the API successfully and actually generate music I can hear. Then I change the internals of the API and run the scripts again to ensure they still generate the same music. In that sense I'm basically doing the right thing, even though it's not particularly systematic or automated. I'm comparing the output with my ears rather than in a way that code can grok, but it still has the feel of a spec-first workflow. For developing the API itself, especially the parts which generate MIDI, I set up a layer of abstraction. Instead of directly driving the code which sends MIDI to external software, the code which generates the music drives an output adapter, and the output adapter sends MIDI to external software - or, in the case of the TextOutputAdapter, just text-dumps the music. Since it all comes back as text, it's very easy to write specs against. But I've ended up with three artifacts that are *either* byproducts of bad design *or* bad products of a compromised spec process. I created three mock *classes* (as opposed to mock objects). For example, one is the ArrayGenerator. In this system Generators return notes. The ArrayGenerator "generates" an array of notes. It's a silly implementation, but it's useful if you want to spec that some code can take an arbitrary generator, which generates arbitrary notes, and then process those notes correctly. Sometimes I think my design has too many abstract parts. Sometimes I'm happy with it. I want to improve my speccing approach so I can operate with greater certainty. I think probably this approach is a good direction, and that I should change the specs by making them more specific. (For instance, there are places where I check that a Generator subclass can do stuff, even though Generator itself isn't fully specced.) I'm not quite sure though. -- Giles Bowkett Podcast: http://hollywoodgrit.blogspot.com Blog: http://gilesbowkett.blogspot.com Portfolio: http://www.gilesgoatboy.org Tumblelog: http://giles.tumblr.com _______________________________________________ rspec-users mailing list [email protected] http://rubyforge.org/mailman/listinfo/rspec-users
