Tag Archive for 'ruby'

Specify a relative time in Cucumber

Prepping for working on a feature at $work that involves limiting documents by relative time, I hashed out the following steps. Posting here in case they prove useful for anyone.

I want to be able to specify an arbitrary time, in english, relative to the current time, in my Cucumber steps. For example,

Scenario: Only posts from the last two months are shown
  Given the following posts:
    | title           | posted_at           |
    | recent post     | 2 days ago          |
    | recent post 2   | yesterday           |
    | older post      | 2 months ago        |
    | really old post | 2 months, 1 day ago |
    | tomorrow's post | 1 day from now      |
  When I go to the posts page
  Then I should see 3 posts

The desire, there, is to be able to specify a date relative to the current time, in plain english. The tricky bit is being able to chain them together, as in 1 year, 3 months, 2 days ago

I got this worked out by stringing a few regular expressions together in my step definition helper. It depends on the 2.days.ago type dsl in ActiveSupport.

Given /^the following posts?:?/ do |table|
  table.map_column!('posted_at'){|date| interpret_time(date) }
  table.hashes.each{|hash| Factory :post, hash}
end
def interpret_time(time)
  return nil if time.blank?
  return time if time.kind_of?(Time) or time.kind_of?(Date)
  named_time(time) || time_by_regex(time) || Time.parse(time)
end
 
def named_time(time)
  case time.downcase
  when "today" : Date.today
  when "now" : Time.now
  # etc ...
  else nil
  end
end
 
def time_by_regex(time)
  directional_regex = /(ago|from now)/i
  time_regex = /(\d+) (minute|hour|day|week|month|year)s?/i
 
  direction = time.scan(directional_regex).flatten
  shifts = time.scan(time_regex)
 
  return nil if direction.empty? or shifts.empty?
  forward = direction.first == "from now"
 
  result = Time.now
  shifts.each do |count, unit|
    #depends on the 1.week type DSL for time measurements
    adjust = count.to_i.send(unit)
    # move time in correct direction
    result = forward ? (result + adjust) : (result - adjust)
  end
 
  result
end

Spec a FormBuilder in RSpec

yesterday, I started trying to work on a helper for generating a frequently-repeated calendar widget for the rails app at $WORK. Being the good BDDer that I am, I launched off a new spec to test the form builder — and to attempt to backfill specs and cover up the evidence of my naughty non-testing past.

This is a form builder we use in a couple of heavily used forms on the site, so we “know” this works, aside from the new code I want to add. But in moving in to backfill some specs, I discovered that, like many things relating to form builders in rails, it’s not the easiest thing to do, nor is it exactly well documented …

After a bit of digging, I finally managed to work out the right setup to get this going. Documented below for posterity

# spec/helper/random_form_builder_spec.rb
  describe RandomFormBuilder do
    attr_reader :builder, :helper
    before do
      @helper = Object.extend(ActionView::Helpers::FormHelper)
      @object = stub_model(Random)
      @builder = RandomFormBuilder.new(:random, @object, @helper, {}, nil)
    end
  end

You can then spec as normal, calling methods on builder and verifying the result.

The tricky part is the constructor.

:random
This is the name of the object, by analog, the first argument of a #form_for
@object
The object you run with; where the form pulls field values from
@helper
this is the tricky one. A form builder is really just a pass-through, decorating calls down to methods that live in FormHelper. If you don’t have a template that defines the FormHelper methods, failures abound.

{}
Options for the FormBuilder. Here, unused
nil
A proc

Railsconf 2007

I’m signed up for railsconf 2007, which runs in late May of 2007, up in Portland, Oregon. Looks like I’m one of about 10 NoVaRUG members going.