Yesterday at the excellent Devopsdays in Gent, Belgium, I proposed an open session to flesh out an idea I had a few weeks ago - to use Cucumber as a general scripting language.
Cucumber’s Given/When/Then steps are well suited to procedural tasks like shell script, and you would be writing your “scripts” in straightforward language that non-technical users such as managers and clients could understand. Also, as writing a scenario without a Then to close it feels unbalanced, you’d get in the mindset of testing the actions of your “scripts” fairly quickly.
With little more than the hypothesis above, a group of us found a room and started modeling some scenarios. Our focus was on file manipulation, as it was a low hanging fruit and something most scripts do.
We came up with this:
The first scenario is fairly self explanatory, but the second one is where the interesting stuff starts happening.
In the implementation of the “following table” step, we create an instance variable that persists the list of files between steps. This way, we can reference the “tasty fruit” throughout our other steps:
We use the (.+)
regex to capture the name of the table so we can poke at
it later on. This design lets you easily use multiple tables throughout your
steps that won’t conflict with one another:
Other steps can reference data in the table by accepting a name and looking it up in the hash of tables:
We also looked at handling permission problems:
Here the step will raise an Errno::EACCES
exception, and as Cucumber uses
a pretty formatter by default, the failed step will appear in red.
Finally we tried copying files with a glob. The initial implementation I
banged out was very Unix focused (it used *
, which is a very explicit
globbing syntax), so we scrapped that idea and wrote our intentions in
plain English:
The implementation is obvious, and is very understandable (and seemingly powerful) to someone with no knowledge of globbing.
People who have used Cucumber in web development will likely note that the above implementation is an example of tightly coupled steps, which is sometimes regarded as an anti-pattern. I’m of the opinion that this is a lot more painful in a web development context than in a procedural/scripting tool one.
From my recollection of Euruko earlier this year, when Aslak was asked whether he considers it an antipattern, he said it can be ok to use depending on the problem you’re trying to solve, so I take that as tacit permission that it is ok this context. :-)
I posted the results of the session to a Gist yesterday, and I have also published a repo with a bundler-ready install process, so people can hack on it more.
After the session I remembered that the feature file doesn’t actually have to start with Feature, so it’s possible to write standalone scenarios one after another.
When wrapping up, someone in the room pointed out that our implementation actually went one better than being readable by non-technical users - they could probably write the scripts themselves.
This is pretty powerful, and coupled with Cucumber’s very cool step generation when running scenarios with undefined steps, makes it very easy to start prototyping a standard library of human readable scripting commands.
There was chatter on the Cucumber mailing list a few weeks ago about providing alternate interfaces for writing and executing Cucumber features, and it could be cool to see a drag-and-drop interface with a library of common tasks that calls out to Cucumber to execute them. You could even build something quite beautiful with HotCocoa.
Anyhow, if you think anything mentioned above is a cool idea, check out the code and start hacking!