rspec/rspec-expectations — pull request #388 by myronmarston (2013-12-14 05:29:02+00:00)
Title: WIP: spike composable matchers

This is a WIP spike at supporting composable matchers (for #280). I'd like to get some feedback before going further down this path. In a nutshell, here's how you make an existing matcher support receiving another matcher as an argument:

* `include RSpec::Matchers::Composable` in your matcher class.
* Use `values_match?(expected, actual)` in your `matches?` logic (rather than `expected == actual` or whatever).
* Use `description_of(object)` rather than `object.inspect` in your failure messages and descriptions.

The phrasing of the existing matchers reads well in an `expect(...).to matcher` expression, but reads poorly when they are passed as an argument to another matcher. For example, consider these two expressions:

``` ruby
expect { do_it }.to change { x }.from( be_within(0.1).of(3) )
# vs
expect { do_it }.to change { x }.from( a_value_within(0.1).of(3) )
```

The second reads much better, grammatically. I'd like to provide aliases of all the build-in matchers that "nounifies" them so they read well when passed as arguments to another matcher. In addition, the `description` method of these aliases needs to be changed a bit to read well. With this PR, the two expressions above read like so:

> change result from be within 0.1 of 3

vs

> change result from a value within 0.1 of 3

To implement this, I've had to implement a wrapper class that substitutes `"a value within"` for `"be within"` in the description. The implementation isn't too bad but it's not as simple as I was hoping for.

Feedback wanted before I proceed with more on this feature.

/cc @xaviershay @JonRowe @alindeman @soulcutter @samphippen