Ruby Programming

Announcing The Cucumber Book (Beta)

I love using Cucumber to help me write software. I almost find it hard to imagine doing it any other way.

I want more people to discover this for themselves, so for the last year or so Aslak and I have been writing a book all about using Cucumber for Behaviour-Driven Development:

The Cucumber Book cover

We hope we’ve captured some of the passion and sheer enjoyment we get from working with this amazing tool. Whether you’re a complete novice or an experienced Cucumber user, I think you’ll get a lot from the book.

What are you waiting for? Go and get yourself a copy!

Agile / Lean Software Development
Ruby Programming

Comments (4)

Permalink

Fixing my testing workflow

Okay I’m bored of this. I need to talk about it.

I love to use Ruby, RSpec, Cucumber and Rails to do test-driven development, but my tools for running tests are just infuriatingly dumb. Here’s what I want:

  • When a test fails, it should be kept on a list until it has been seen to pass
  • When more than one test fails:
    • Show me the list, let me choose one
    • Focus on that one until it passes, or I ask to go ‘back up’ to the list
    • When it passes, go back up to the list and let me choose again
    • When the list is empty, I get a free biscuit
  • When a test case is run, a mapping should be stored to the source files that were covered as it ran so that:
    • When a file changes, I can use that mapping to guess which test cases to run. Fuck all this naming convention stuff, it’s full of holes.
    • At any time, I can pipe the git diff though the tool to figure out which test cases to run to cover the entire commit I’m about to make.

When I say test case, I personally mean:

  • An RSpec example
  • A Cucumber scenario

…but it should work for any other testing framework too.

I feel like having a tool like this that I trusted would make a huge difference to me. There are all these various scrappy little pieces of the puzzle around: guard plugins, autotest, cucover, cucumber’s rerun formatter. None of them seem to quite do it, for me. Am I missing something?

Or shall we make one?

Agile / Lean Software Development
Ruby Programming

Comments (8)

Permalink

Targeting Multiple Platforms (JRuby etc) with a RubyGems .gemspec

Recently we had a user who runs the relish gem on JRuby, and needed jruby-openssl to be loaded. He kindly submitted this patch, which I merged in without really thinking about it too much. Then the problems started.

That’s not the right way to express dependencies for different platforms using RubyGems and Bundler. I’ve done some research and I think I understand the current good practice for this, so I’m going to document it here.

The .gemspec is read at the time you build and release your gem, so any conditional logic in that file will be evaluated once when the gem is built and released on your machine. So a line like this:

s.add_runtime_dependency('jruby-openssl') if RUBY_PLATFORM == 'java'

Will bake-in the dependency based on whatever platform you run gem build on.

What you need instead is to evaluate the platform at runtime. Bundler offers you a way to do this, in your Gemfile:

platforms :jruby do
  gem "jruby-openssl"
end

What a jruby user will now experience is that when your gem is loaded, they’ll see a warning:

→ relish help
JRuby limited openssl loaded. http://jruby.org/openssl
gem install jruby-openssl for full support.
...

It’s now up to the user to manually install the gem themselves. It seems a shame that there isn’t any way to specify this information in the gem’s manifest, so that it can be installed on a platform-specific basis when you gem is installed, but as far as I can tell there’s no way to do that right now.

Agile / Lean Software Development
Ruby Programming

Comments (2)

Permalink

A Puzzle for Polite Ruby Programmers

I really enjoyed Jim Weirich’s session on polite programming at the Scottish Ruby Conference. He covered a problem that’s been vexing me for some time, about avoiding the use of method aliasing, by using inheritance instead. Unfortunately, his suggested solution didn’t tell me anything I hadn’t already tried. I still think this must be possible, but that I just don’t know quite enough about Ruby to be able to achieve it. Maybe you do?

Here’s the puzzle:

https://gist.github.com/912504

Can you solve it?

Ruby Programming

Comments (2)

Permalink

Two Truths I’ve Learned About Writing Clean Rails Apps

In summary:

  • Implement every feature without javascript first, add javascript as a progressive enhancement
  • Stick to REST. Always.

Now I’m as suspicious of absolute rules as you probably are, but these two have served me extremely well in keeping my Rails code clean and easy to maintain. I’m happy to push the boat out and call them truths, my truths anyway.

Let me explain.

Progressive Enhancement

When I first started at Songkick, Cucumber was just emerging and webrat was the new kid on the testing block. Although using Selenium for full-stack javascript testing was possible with webrat, it wasn’t easy and we quickly made a decision: we would build the first iteration of every feature to work without javascript. This was mainly driven by pragmatism: we could easily use webrat to test the app through Rails integration testing stack, and these tests ran quickly rather than waiting for a browser to start up.

What happened surprised us. We would receive fancy designs from our designers which could only be implemented with fairly complex javascript. Because of our rule, we had to figure out how to deliver the same behaviour using basic HTTP posts and gets of forms and URLs. This required us to simplify the designs for our first iteration. We got a little push-back at first but we were a tight team and the designers quickly caught on. Especially when we started shipping these iteration one features quickly and reliably. And funnily enough, it turned out that often these simple HTTP-only versions of the features were actually fine, and the designers decided we should move onto other stuff, instead of building all that complex javascript that had been implied by their earlier designs.

So this rule had helped us to do the simple thing. We shipped features and moved on.

When we did have to add javascript, we added it on top of the existing working HTTP-only implementation, and we got another surprise: it was easy! Nearly every time, because we’d built the server-side infrastructure to a clean, standard pattern, the javascript we needed was clean and simple to write.

Which leads me to my next truth…

Stick to REST. Always.

I’ve always felt a little uncomfortable with Rails’ controllers. They violate the Single Responsibility Principle for me. I’d prefer a pattern where I had a separate Request class for each action, rather than a few largely unrelated methods on the same controller class. But Rails is there and there’s a lot else to like, so let’s not get into that.

We all know it’s a bad idea to let our controllers bloat and something I’ve been enjoying greatly lately is Jose Valim‘s Inherited Resources. By sticking to this pattern, you push all the logic into your domain model, and keep the controllers focussed on what they need to do: handling web requests.

You end up with more controllers, and more models too. You create model objects that — Gosh! — don’t represent database tables, but represent other domain concepts instead. Altogether though, you end up with smaller, more focussed classes that are easier to test and easier to read and understand.

Ruby Programming

Comments (3)

Permalink

Using Capybara with RSpec Outside Cucumber

If you want to try using Capybara for browser automation on it’s own, here’s a simple script to get you started:

require 'rubygems'
 
require 'capybara'
require 'capybara/dsl'
 
Capybara.default_driver = :selenium
Capybara.app_host = "http://www.google.com"
 
require "rspec/expectations"
class Google
  include Capybara
  include RSpec::Matchers
 
  def search_for(text)
    visit "/"
    fill_in "q", :with => text
    click_button "Search"
  end
 
  def ensure_results_contain(expected_text)
    page.should have_content(expected_text)
  end
end
 
google = Google.new
google.search_for("Matt Wynne")
google.ensure_results_contain("Tea")

To make this work you’ll need to install the capybara and rspec Ruby gems:

gem install capybara rspec

Agile / Lean Software Development
Ruby Programming

Comments (2)

Permalink

Installing Ruby Gems with Native Extensions on Windows

If you’re stuck trying to run Ruby on Windows, one barrier you might have encountered is in trying to install a gem like ruby-debug or rdiscount. You’ll have seen an error like this:

%gem install ruby-debug
Building native extensions.  This could take a while...
ERROR:  Error installing ruby-debug:
        ERROR: Failed to build gem native extension.
 
C:/Ruby187/bin/ruby.exe extconf.rb
creating Makefile
 
make
'make' is not recognized as an internal or external command, operable program or batch file.
 
 
Gem files will remain installed in C:/Ruby187/lib/ruby/gems/1.8/gems/linecache-0.43 for inspection.
Results logged to C:/Ruby187/lib/ruby/gems/1.8/gems/linecache-0.43/ext/gem_make.out

That’s no fun.

The good news is, the lovely guys at Ruby Installer have put together a fix, called the DevKit. This installs the low-level bits and pieces needed to build those pesky native extensions on your Windows machine. There are a couple of manual steps which I didn’t find especially clear, so I’m documenting them here.

  • Download the DevKit self-extracting archive here
  • Run the archive, and when prompted, choose to extract it to C:\DevKit
  • When the archive has finished unpacking, open a command prompt in C:\DevKit and run ruby dk.rb init ruby dk.rb install
  • That’s it. You can test it using: gem install ruby-debug

Hooray!

Ruby Programming

Comments (3)

Permalink

Fix RubyMine 2.02 Cucumber Integration

If you’re using the latest version of RubyMine (2.0.2) with the latest version of Cucumber (actually anything above 0.7), you’ll probably see this ugly warning when you try to run your cukes from within the IDE:

screen-shot-of-rubymine-error

The bug has been logged, and there’s a published workaround, but I wanted something a bit easier to use.

Try this instead. Close RubyMine, open a terminal, and run this command:

curl http://gist.github.com/raw/550046/240dd98b8b0ed1efa817f26ff2697940ddd0f53d/rubymine-2.02-cucumber.patch | patch -p0

or even

curl -L http://bit.ly/bPNmYV | patch -p0

It won’t work with Cucumbers older than 0.7, but why would you want to use them?

Update: If you like life on the bleeding edge, you can also try the EAP release (latest development build) of the forthcoming RubyMine 2.5, which contains this fix.

Ruby Programming

Comments (0)

Permalink

Installing mysql gem on Mac OSX Snow Leopard

This old chore doesn’t seem to have become any easier lately. Here’s how to do it: http://blog.simb.net/2009/10/24/gem-mysql-with-mysql-5-1-on-snow-leopard/

Ruby Programming

Comments (0)

Permalink

MegaMutex: A Distributed Mutex for Ruby

Sometimes I need to do this:

unless enough_widgets?
  make_more_widgets
end

Which is all well and good, until I start letting two or more of these codes run in parallel. If you’ve never thought about this before, what can happen is something nasty called a race condition, where two or more processes (or threads) simultaneously check #enough_widgets?, and simultaneously both decide that they need to go and #make_more_widgets. With multiple processes now making more widgets, we end up with too many.

The solution is to lock this critical section of code so that only one process could ever run it at once – everyone else has to queue up and wait their turn. That way each check for #enough_widgets? will return an answer that’s accurate. In a single process with threads, this is achieved using the Mutex class, but when you run multiple processes in parallel, across multiple machines, you need something more. You need MegaMutex.

How

Suppose you have a WidgetMaker:

class WidgetMaker
  include MegaMutex
 
  def ensure_just_enough_things  
    with_distributed_mutex("WidgetMaker Mutex ID") do
      unless enough_widgets?
        make_more_widgets
      end
    end
  end
end

Now, thanks to the magic of MegaMutex, you can be sure that all processes trying to run this code will wait their turn, so each one will have the chance to make exactly the right number of widgets without anyone else poking their nose in.

Configuration

MegaMutex uses memcache-client to store the mutex, so your infrastructure must be set up to use memcache servers.

By default, MegaMutex will attempt to connect to a memcache on the local machine, but you can configure any number of servers like so:

MegaMutex.configure do |config|
  config.memcache_servers = ['mc1', 'mc2']
end

Installation

sudo gem install mega_mutex

Hacking

http://github.com/songkick/mega_mutex

Ruby Programming

Comments (1)

Permalink