Not sure if this falls into the useful or into the weird category, but I’m beginning to do code generation in my behavior specifications…

Take a look at the behavior specification:

text/unit/transaction_state_test.rb
 1 require File.dirname(__FILE__) + '/../test_helper'
 2 
 3 class TransactionStateOrderingTest < Test::Unit::TestCase
 4   TransactionState::StatusNames.each do |status|
 5     define_method("test_#{status}_query_method") do
 6       assert TransactionState.send(status).send("#{status}?"), status
 7       (TransactionState::StatusNames - [status]).each do |inner_status|
 8         assert !TransactionState.send(status).send("#{inner_status}?"), inner_status
 9       end
10     end
11   end
12 end

And the corresponding implementation:

app/models/transaction_state.rb
 1 class TransactionState
 2   StatusNames = %w(started approved processed completed cancelled).freeze
 3 
 4   attr_reader :name, :index
 5   alias_method :to_s, :name
 6 
 7   def initialize(name)
 8     @name, @index = name.to_s, StatusNames.index(name.to_s)
 9     raise "Unknown status name: #{name.inspect}" unless @index
10   end
11 
12   # Generate instance methods to query the state of this instance.
13   # Generates #started? and #completed?, among others.
14   StatusNames.each do |status|
15     define_method("#{status}?") do
16       self.name == TransactionState.send(status).name
17     end
18   end
19 
20   # Generate class methods to return pre-instantiated
21   # TransactionState objects, one per status name.
22   class << self
23     @@states_cache = Hash.new
24     StatusNames.each do |status|
25       @@states_cache[status.to_sym] = TransactionState.new(status)
26       define_method(status) do
27         @@states_cache[status.to_sym]
28       end
29     end
30   end
31 
32   Statuses = StatusNames.map {|status| TransactionState.send(status)}
33 end

Nothing too earth shattering, except for the specs. How do I ensure the specs were properly generated ? I didn’t, except for confirming that the number of tests and assertions went up as expected.

Search

Your Host

A picture of me

I am François Beausoleil, a Ruby on Rails and Scala developer. During the day, I work on Seevibes, a platform to measure social interactions related to TV shows. At night, I am interested many things. Read my biography.

Top Tags

Books I read and recommend

Links

Projects I work on

Projects I worked on