Building Flexible Interfaces

Heads up: you might start to feel a bit of déjà vu in this section. What we’ll cover here is basically a recap of what was discussed in Chapter 2, Designing Beautiful APIs, mixed in with a little dynamic help here and there. Though each step may seem fairly inconsequential, the end result is quite powerful.

When implementing a flexible domain-specific interface, the idea is that we want to strip away as much boilerplate code as possible so that every line expresses something meaningful in the context of our domain. We also want to build up a vocabulary to work with, and express our intents in that vocabulary as much as possible. A domain-specific interface puts Ruby in the background: available when you need it, but not as in-your-face as ordinary programmatic interfaces tend to be. An easy comparison would be to look at the difference between some elementary Test::Unit code and its RSpec equivalent.[7]

First, we’ll look at the vanilla Test::Unit code:

class NewAccountTest < Test::Unit

  def setup
    @account = Account.new
  end

  def test_must_start_with_a_zero_balance
    assert_equal Money.new(0, :dollars), @account.balance
  end

end

To a Rubyist, this code might seem relatively clear, straightforward, and expressive. However, its defining characteristic is that it looks like any other Ruby code, with all the associated benefits and drawbacks. Others prefer a different approach, which you can clearly see in this RSpec code:

describe Account, " when first created" do ...

Get Ruby Best Practices now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.