rspec/rspec-expectations — pull request #337 by myronmarston (2013-10-09 07:25:03+00:00)
Title: Matcher DSL deprecations for 2.99

I can't tell if I'm proud of this code or embarrassed by it. It's simultaneously just about the worse hack I've ever used, but also the most meta metaprogramming I've ever done.

I wouldn't want code like this in master, but it serves a useful purpose to provide a deprecation warning in 2.99 and won't be a maintenance burden given that we won't continue 2.x development.

Deprecate calling helper methods from a custom matcher with the wrong scope.

- `def self.foo` / `extend Helper` can be used to add macro methods
(e.g. methods that call the custom matcher DSL methods), but should
not be used to define helper methods called from within the DSL
blocks.
- `def foo` / `include Helper` is the opposite: it's for helper methods
callable from within a DSL block, but not for defining macros.

In 2.x, there wasn't a clear separation here because `self` in `define`
was the same as `self` wtihin the DSL blocks -- the matcher instance.
In 3.0, the `self` in `define` will be a class and `self` in the DSL
blocks will be an instance of that class -- so thi separation is
necessary for helper methods to work properly on 3.0.

This code is VERY hacky but it's the only way I could find to make it
work. We have to evaluate the block using `class_eval` in order
to differentiate methods defined using `def foo` vs `def self.foo`;
`instance_eval` treats them the same.

The string eval stuff is also quite hacky, but is necessary because
we still semi-support 1.8.6 in RSpec 2.99, and 1.8.6 can't parse
blocks that accept blocks using `define_method` :(.