package MyApp::Item; use Moose::Role -traits => 'MooseX::MethodAttributes::Role::Meta::Role'; use namespace::autoclean; sub view : Chained('item') PathPart('') Args(0) {} sub edit : Chained('item') PathPart('edit') Args(0) {} package MyApp::Controller::Foo; use Moose; use namespace::autoclean; BEGIN { extends 'Catalyst::Controller' } with 'MyApp::Item'; sub item : Chained('/') PathPart('foo') CaptureArgs(1) {}
This simple example will produce the following URIs (corrected by an astute reader):
- /foo/item/*
- /foo/item/*/edit
The sweet thing about this is that you can apply the role anywhere you have a 'sub item', and as long as the item is stored in the same place in the stash, and can be manipulated in expected ways (e.g. is a dbic resultset)..
You've suddenly got generic, re-useable CRUD, without any nasty multiple inheritance going on, method modifiers should work like you expect, etc.
Nice, eh? I have lots of places where I like to re-use chunks of URL space like this in my apps, and currently I have to use steeenking multiple inheritence.
I just CPAN'd a dev release of MooseX::MethodAttributes which makes this work.
Caveat: I'm fairly sure that composing roles with actions in them onto other roles will not work correctly currently, it may work, but I haven't written tests yet so it probably doesn't.
I'll be fixing this and releasing 'for real' within the next week or so hopefully, but I'm fairly sure it's solid as long as you compose roles directly onto classes as shown above. Method modifiers (not shown above) are also tested and do work.
P.S. I'm fairly sure MooseX::MethodAttributes::Role::Meta::Ro
P.P.S.It was pointed out to me that what I'm doing above could previously have been trivially achieved using controller base classes. This is totally true, as it was a simple example. I'll demonstrate a much more complex example and how having to use base classes and multiple inheritance make this a lot more painful than it has to be for more complex cases in a future post :)