---
title: Write Fewer Regular Expressions
teaser: How to avoid regex in Cucumber steps.
tags: testing
author: Mike Burns
published_on: 2010-03-05
---

Oh man Cucumber is awesome but why do I have to write regular expressions? It's
always like:

```ruby
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:

```ruby
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:

```ruby
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!

```ruby
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:

```ruby
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!
