bbangert/routes — pull request #28 by mikepk (2014-03-07 22:51:30+00:00)
Title: Concat fix

Hi Ben,

I've been using Routes for a while with my semi-custom web framework (I know, I know, why on earth?! I'm a weirdo :) ). I often use submappers to DRY up my routes and am a fan of the modular routing it enables.

When I first started using them I ran into some behaviors I thought seemed non-intuitive. I opened an issue on the old bit-bucket hosted version of routes (a few years ago) but ended up creating my own github fork of your repo to make some changes. Now that routes is on github and accepting pull requests, I went ahead and re-forked 'officially' from your github repo and thought I'd offer these changes to you for routes (if you agree with my thinking and I'm not overlooking something).

The issue I ran into has to do with submappers not allowing overriding arguments at lower levels of the nesting in submappers and arguments concatenating in ways that I didn't expect.

Here's a contrived example to show the issue:
```
from webob import Request
from routes import Mapper
mapper = Mapper(explicit=False)

with mapper.submapper(controller="experiment", path_prefix="/exp") as exp:
exp.connect('test', r'/test')
with exp.submapper(controller="other", path_prefix="/other") as other:
other.connect('test2', r'/zing')
other.connect('test3', r'/parrot', controller="parrot")

print mapper

print
print "Results in the following Mappings:"
for url in ('/exp/test', '/exp/other/zing', '/exp/other/parrot'):
request = Request.blank(url)
match, route = mapper.routematch(environ=request.environ)
print "{url:20} - {match}".format(url=url, match=match)

```

This generates the routes you would expect but the matched vars seem surprising.
```
Route name Methods Path
test /exp/test
test2 /exp/other/zing
test3 /exp/other/parrot

Results in the following Mappings:
/exp/test - {'action': u'index', 'controller': u'experiment'}
/exp/other/zing - {'action': u'index', 'controller': u'experimentother'}
/exp/other/parrot - {'action': u'index', 'controller': u'experimentotherparrot'}
```

The controller url variable that's returned is the **concatenation** of all of the controller keyword arguments in the nested hierarchy.

The concatenting logic makes sense when dealing with generative prefix arguments (name_prefix and path_prefix) but that seems like the special case rather than the general case.

The fix seems simple enough, make the 'prefix' arguments generative and the special case. If the keyword argument value isn't a dict (and therefore merged) then just override the keyword argument with the new argument. This means the prefix arguments concatenate and nest, and any other arguments can be overridden at any lower level of the submapper nesting.

I also had to add a minor fix for collections to work with no name when being used in a submapper context with no collection_name specified.

Thoughts?

(the .gitignore cruft is from my original uploading of my bitbucket -> github fork a few years ago)