On Jul 7, 2010, at 1:24 AM, Wincent Colaiuta wrote:

> El 07/07/2010, a las 01:16, Lalish-Menagh, Trevor escribió:
> 
>> Hi David,
>> 
>> You make a good point. I was talking with a coworker about this
>> problem, and he suggested a simpler format, that I think will coincide
>> some with Wincent's thoughts. Here is my next stab
>> (http://gist.github.com/466064):
>> describe "routing" do
>> it "recognizes and generates #index" do
>>   get("/days").should have_routing('days#index')
>> end
> 
> Very nice. I definitely like this better than the "map()" terminology that I 
> used.
> 
>> it "generates #index" do
>>   get("/days").should generate('days#index')
>> end
> 
> Reads well, _but_ I think you've got it back-to-front. assert_generates, and 
> therefore the corresponding matcher in RSpec, asserts that a _path_ can be 
> generated from a set of _params_ (controller, action, additional params), but 
> here you're asserting the opposite.
> 
> (One thing to note is that assert_generates really only does assert about the 
> _path_, not the method + path, but it's still nice to write it as "get(path)" 
> just for symmetry with the reverse version of the spec.)
> 
>> it "recognizes #index" do
>>   ('days#index').should recognize get("/days")
>> end
> 
> This one is back-to-front too; assert_recognizes is an assertion that a path 
> (this time method + path) is recognized as a particular route (action, 
> controller, additional params) but here you're asserting the opposite.
> 
> If we're really serious about using the same verbs as the Rails assertions, 
> and we want to forward and reverse versions of the spec to read in the same 
> way, we could use something like:
> 
>  specify { get('/days').should recognize_as('days#index') }
>  specify { get('/days').should generate_from('days#index') }
> 
> If we don't mind swapping the order around
> 
>  specify { get('/days').should recognize_as('days#index') }
>  specify { 'days#index'.should generate('/days') }
> 
> Note that in the "generate" spec here I drop the "get()" seeing as Rails 
> isn't actually looking at the method, and it is just verbiage IMO to start 
> nesting other method calls inside the generate() matcher.
> 
> Weighing up the two orders, I prefer the first pair of specs, I think, 
> because:
> 
> - the repetition of the pattern makes it easier to remember and apply.
> 
> - if you have to supply additional parameters (as you do in your later 
> example), using the first format you can write ('days#index', :student_id => 
> '1') whereas with the second format you are obliged to involve another method 
> like with() in order to express it as "('days#index').with(:student_id => 
> '1')".
> 
>> describe "nested in students" do
>>   it "recognizes #index" do
>>     ('days#index').with(:student_id => "1").should recognize
>> get("/students/1/days")
>>   end
>> end
>> end
> 
> This is another back-to-front one, I think. You're not recognizing here, but 
> generating.
> 
>> Notes:
>> - I am using have_routing, recognize, and generate because those are
>> the verbs used in Rails for the functions we are wrapping.
> 
> Seems like a good idea that we should definitely try to do, although with one 
> reservation; if we feel that the language is confusing or suboptimal then we 
> should feel free to change it.
> 
> I personally have lingering doubts about the Rails language because I think 
> it _is_ confusing in a way. Look at the way you used recognize and generate 
> back-to-front in this message. And I know that every time I want to make a 
> comment about "assert_recognizes" and "assert_generates" I end up 
> double-checking the API docs just to make sure that I'm about to use them in 
> the right way.
> 
>> - I like using the word "with" to represent "extras," in the Rails API
>> (see 
>> http://edgeapi.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html),
>> since I think it fits here, and we already use with in RSpec in other
>> places (like stubs, etc.).
> 
> I don't really like it; I think it adds unnecessary verbiage to the specs.
> 
>> - I like using get('path') since it is similar to the routing calls in
>> the Rails 3 route file, and I think it is easy to intuit.
>> - We can use the hash notation to conform to Rails 3, with an option
>> to provide a full hash as well (Rails 2 style).
> 
> Yes, the example I posted at http://gist.github.com/464081 does that. 
> 
>> - The format still reads like English, and using "have_routing"
>> instead of "routes_to" avoids the "_to" and "_from" problem that we
>> have been talking about, PLUS it makes it easier to draw a
>> relationship between the RSpec command and the Test::Unit command
>> (assert_routing).
> 
> Yeah, I think "have_routing" is a definite improvement over "map".
> 
> I am less convinced that "recognize_as" is an improvement over the highly 
> readable "map_to".
> 
> I am less attached to "map_from", though, and think "generate_from" might be 
> an improvement.
> 
> Like I said above, I think the Rails terminology does have the potential to 
> be confusing, so I don't necessarily feel "wedded" to it.
> 
>> - Using these verbs still allow "should_not" to make sense.
> 
> Yes, I think that's important.
> 
> One thing I wanted to add is that I discovered in my testing that the 
> existing "be_routable" matcher isn't very useful. This is because it relies 
> on "recognize_path", which I am not sure is public API or not, and 
> "recognize_path" sometimes recognizes the unrecognizable... For example:
> 
>  in config/routes.rb:
>    resource :issues, :except => :index
> 
>  visit issues#index (/issues) in your browser:
>    get a RoutingError (expected)
> 
>  in your spec:
>    recognize_path('/issues', :method => :get) # recognizes!
> 
> So this means you can't do stuff like get('issues#index').should_not 
> be_routable, because the Rails recognize_path() method will tell you that it 
> _is_ routable. Seems that it is only useful for a subset of unroutable routes 
> (like completely non-existent resources, for example).
> 
> If you look in the Gist you'll see that I work around this limitation by 
> adding a "be_recognized" matcher which doesn't use "recognize_path()" under 
> the hood. Instead it uses "assert_recognizes" and decides what to do based on 
> what kind of exception, if any, gets thrown by it. So you can write:
> 
>  specify { get('/issues').should_not be_recognized }
> 
> (Funnily enough, assert_recognizes() _does_ use recognize_path() under the 
> hood, but it's evidently doing some additional set-up and tear-down to make 
> it work. It seems like wrapping assert_recognizes rather than replicating its 
> logic, though, is the right thing to do.)

Seems as though this format has been abandoned in this conversation:

  it { should route(get "/issues/new").to("issues#new") }
  it { should generate("/issues/new").from("issues#new") }

I think that verbiage is concise and intention revealing, and keeps the path on 
the left and the details on the right. Supported variants would be:

  it { should route(:get => "/issues/new") ... # explicit hash for method/path
  it { should route("/issues/new")...  # defaults to get
  it { should ...to(:controller => "issues", :action => "new") } # explicit 
hash for params

The negative version would be:

  it { should_not route(get "/issues/new") }

We could alias route() with recognize() to get:

  it { should_not recognize(get "/issues/new") }

We still need to consider output. For example:

  it { should route("/issues/37").to("issues#show", :id => 37) }

I think in this case we _might_ be able to figure out that 37 is the value of 
:id and output

  should route "/issues/:id" to "issues#show"

Not sure if that'd be asking for trouble, but it seems feasible/reasonable.

In terms of the more verbose format for custom messages, we could add a 
router() method for sugar:

  it "routes /issues/new to issues#new" do
    router.should route("/issues/new").to("issues#new") }
  end

And we still need the bi-directional version. I'm really at a loss on this one.

Thoughts?

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

Reply via email to