Oh man Cucumber is awesome but why do I have to write regular expressions? It’s always like:
Then /^show me the emails$/ do
puts ActionMailer::Base.deliveries.map do |email|
email.subject
end.join("\n")
end
Then /^I should see the "([^"]+)" link once$/ do |link_title|
assert_select '.deal_title', :text => link_title, :count => 1
end
Then /^I should see "([^"]+)" for "([^"]+)" (.*) field
in the response XML$/ do |value, xpath, field|
@parsed_response.xpath("#{xpath}[@#{field}='#{value}']").should_not be_empty
end
Ugh that’s so ugly and it feels like I’m writing awk or Perl, and while I love me a good awk script it really does not belong near my beautiful Ruby. (They’re so ugly that they broke the syntax highlighter!)
Well you probably know how to replace the first one with a string:
Then 'show me the emails' do
puts ActionMailer::Base.deliveries.map do |email|
email.subject
end.join("\n")
end
But what of our parameterized steps?
I had a vision, a vision of a string with printf
-like escapes inside a string.
I was pumped and ready to make a patch so I cloned the source off github and
started looking through the classes (this was about 11PM). That’s when I
discovered that this was done for me by the wonderful scientists at the Cucumber
Research Institute! We can re-write those steps like this:
Then 'I should see the "$link_title" link once' do |link_title|
assert_select '.deal_title', :text => link_title, :count => 1
end
Then 'I should see "$value" for "$xpath" $field field
in the response XML' do |value, xpath, field|
@parsed_response.xpath("#{xpath}[@#{field}='#{value}']").should_not be_empty
end
Here’s how it works: the Cucumber step parser for Ruby turns every string into a
regular expression, to reduce it to a previously-solved problem. On the way it
translates $foo
into (.*)
. That’s it!
if String === regexp
p = Regexp.escape(regexp)
p = p.gsub(/\\\$\w+/, '(.*)') # Replace $var with (.*)
regexp = Regexp.new("^#{p}$")
end
This, obviously, is not going to rid the world of regular expressions overnight. Take these two for examples:
Given /^(?:|I )am on (.+)$/ do |page_name|
visit path_to(page_name)
end
Given /^the user with email "([^\"]*)" is (not )?an admin$/ do |email, status|
user = User.find_by_email!(email)
user.admin = status.blank?
user.save!
end
But these steps are few and far between.
Only you can reduce your regexps. Replace them with strings, today!