natritmeyer/site_prism — pull request #84 by jmileham (2014-07-11 00:25:29+00:00)
Title: Addressable URL matchers

Hi Nat,

We're using SitePrism at Betterment, and it's great. I was wondering if you might consider this pull request.

The idea is to elevate the URL semantic awareness of a `url_matcher` beyond a regexp, which are hard to write flexibly and correctly. For example, a URL might get arbitrary query params baked into it in some contexts which can effectively be ignored by your app for the purposes of knowing which page you're on, but you still care about the presence of other parameters.

Addressable templates have some incredible facilities for matching URLs against patterns, but out of the box, as I'm sure you found when writing SitePrism, they're not quite powerful enough to allow matching a fully qualified URL against a partial template. I added a matcher class to provide this fuzzy matching facility on top of Addressable templates that works as follows:

* Substitutes all of the `{}`s in your pattern with nonsense strings so that it can be parsed as a valid Addressable::URI
* Splits it into its component parts (scheme, host, port, path, etc)
* Rehydrates the `{}` blocks and converts each component back into an Addressable::Template
* Matches each component template against the equivalent component of the `current_url`, returning true only if all non-null template components match the actual URL.

That way anything that's a valid URL template can be used as a minimally restrictive matcher pattern as well.

This change is backward compatible with the existing behavior of SitePrism (Regexp `url_matcher`s still behave as they used to), but allows you to automatically receive correct `url_matcher`s for most use cases without specifying them explicitly, and a flexible way of specifying even relatively complicated matchers without resorting to Regexp.

The change also includes documentation in the README, recommending that people use implicit URL matchers, but also saying that Regexps are there if you need them.

When coding this up, I also touched on a few other issues:

* The latest version of RSpec causes a few test regressions, which I fixed. RSpec collection matchers have been extracted to their own gem, and `be_true`, `be_false` are no longer a thing (in favor of `be_truthy` and `be_falsey` and `eq true`, `eq false`).
* The latest version of RSpec has deprecated the `bla.should` style in favor of `expect(bla).to`, so I upgraded all the tests and docs so that there are no deprecation warnings in the test suite and SitePrism docs reflect the modern style.
* I stubbed the default wait time to speed up the RSpec runs since their outcomes were deterministic and immune to race conditions, unlike the cucumber features.

I hope these changes are in line with your design direction. Let me know if you have any feedback or changes that would be needed before you'd be comfortable merging. We've ported a pretty robust test suite to use this fork with only implicit url matchers, and it's working great.