Recently, in my new project, I decided to take the DCI approach that Mike Pack outlined, which has been really cool. I’ve been able to keep my tests fast, and have very distinct buckets to put data (models), specific roles of that data (rather than cluttering up the models), and an easy way to take a use case and map it out programatically (contexts).
I noticed that I was generating roles and contexts regularly and copying from previously written code examples so I decided to make role and context generators. The process wasn’t bad, but it did take a couple of steps that took a little digging to understand.
My Role generator pretty much just generates this:
1 2 |
|
But it also hooks into RSpec and generates this
1 2 3 4 5 6 7 8 9 10 11 12 |
|
The generator itself is pretty easy to setup… Rails even has a generator for making a generator!
1 2 3 4 5 |
|
The important file there is roles_generator.rb
1 2 3 |
|
What’s going on here? Well, the digging came in for Rails::Generators::NamedBase, which provides a bunch of fun little helpers like file_name
, class_name
, singular_name
, plural_name
etc – and this is exactly what you want when you’re making a generator for something like Roles or Contexts.
So I expanded the roles_generator:
1 2 3 4 5 6 7 8 9 10 |
|
It doesn’t matter what you call the method… every public method gets called. I don’t even want to know the horrid magic that had to go on to make that happen just the way they wanted it to. There are a bunch of fun helpers you can call like copy_file
, exists_dir
, and template
which give you most of what you need. Lots of other help is available in the Thor::Actions
docs
It was pretty easy to set up the templates at that point.
1 2 |
|
You’ll also notice the little hook_for :test_framework
line at the bottom of the generator. That enables you to tie into whatever test framework you’ve configured, which means this could be easily packaged up as a gem with support for both Rspec
and Test::Unit
depending on what you wanted to use.
Adding the support for Rspec was pretty easy, but you’re tapping into rspecs generators if you want to do it right, not just copying files willy nilly within your own generator.
I added a directory called lib/generators/rspec
that included roles_generator.rb
and a templates directory
The generator looks like this:
1 2 3 4 5 6 7 8 9 10 11 |
|
Only thing to note here is the module Rspec
that wraps the whole class. Without this, Rspec won’t pick up the generator.
Then make your spec template
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Since it’s a module, we set up a test class that is automatically extended as subject
since any other use of subject
doesn’t make sense.
Easy cheesy!
Now I just need to extract these generators to a dci_generators
gem :)