On Feb 8, 2011, at 4:14 AM, Matt Wynne wrote:

> 
> On 4 Feb 2011, at 09:30, Alan B wrote:
> 
>> Hi all, I'm trying to create a custom matcher that will visit a given
>> path and check it's authenticated.
>> Here's what I have so far (using rspec-rails and capybara):
>> 
>> matcher :require_authentication do
>> match do |path|
>>   visit path
>>   #page.current_path.should == sign_in_path
>>   page.current_path.should == '/sign_in'
>> end
>> end
>> 
>> The above version works, but when using the commented out line I get:
>> 
>> NameError:
>>      undefined local variable or method `sign_in_path' for
>> #<RSpec::Matchers::Matcher:0xbbd68ec>
>> 
>> sign_in_path is one of the routes in my application and works fine
>> inside a describe/it block.
>> I don't understand why the matcher recognises visit() but not
>> sign_in_path.
> 
> I'm surprised either of them do.

Actually, I'm not, but that's because I know something that you don't know 
(because I wrote it and it's not well documented):

<background>
A matcher created using the Matcher DSL is provided access to the example it is 
running in. When it receives method_missing, it asks the example if _it_ will 
respond to the message and, if so, sends it to the example.
</background>

<educated_guess guarantees="none">
If visit() is defined in the scope of the example using "def visit", then 
example.respond_to?(:visit) would return true, so the matcher would send 
visit() to the example.

If, however, sign_in_path() is handled with method_missing(), but respond_to?() 
is not also overridden to return true for respond_to?(:sign_in_path), then the 
matcher would call super from method_missing, raising the NameError.

You can test this theory out by putting the following in the same example 
before the matcher:

self.should respond_to(:visit)
self.should respond_to(:sign_in_path)

If my guess is correct, the former will pass, but the latter will fail. If they 
both pass, then I'm not sure about the explanation.
</educated_guess>

HTH,
David

> This DSL is just a factory method for a matcher class. Unless that matcher 
> class includes Capybara and the Rails routing methods module (can't remember 
> the name off-hand) you won't have access to either of these methods in the 
> matcher. Look at the non-DSL way to create a matcher and this will make more 
> sense.
> 
> Also, you need to return true / false from #match, rather than using an 
> assertion.
> 
> cheers,
> Matt
> 
> m...@mattwynne.net
> 07974 430184
> 
> _______________________________________________
> rspec-users mailing list
> rspec-users@rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users

Cheers,
David



_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to