routing and reblessing

18 views
Skip to first unread message

mla

unread,
Mar 22, 2014, 2:53:43 PM3/22/14
to perl...@googlegroups.com
I have a Plack app that's currently using Router::Simple for the routing, but I'm thinking of switching over to Kelp::Routes for it for the bridge support.
One thing I do like about the existing logic I have, is that rather than dispatching to a subroutine, it actually reblesses the app instance into the target controller package.

For example, assume we have this structure:

  package MyApp;
  ...

  package MyApp::Controller;
  use parent qw/ MyApp /;
  ...

  package MyApp::Controller::Blog;
  use parent qw/ MyApp::Controller /;

  sub action_monthly {}
  ...

Then when we match a route like this:

  $router->connect('/blog/{year}/{month}', { controller => 'Blog', action => 'monthly' })

Rather than calling the action as a subroutine and passing in a MyApp reference, it reblesses the app instance into the MyApp::Controller::Blog class
and calls the action_monthly() method on it.

The advantage is now the controller method has the context of MyApp::Controller::Blog so it's simple to factor out code and share it among related actions.

Do you see any inherent problem/danger with the reblessing approach? 





mla

unread,
Mar 22, 2014, 7:07:10 PM3/22/14
to perl...@googlegroups.com
Somewhat related to this, please see this commit:

I'm experimenting with the routing so I wanted to use a custom Kelp::Routes subclass.
Kelp provides config_module() to override the configuration class, but I thought it might be better to share the same Module::Routes to encourage interfaces.

This allows me to substitute my class through the config. e.g., 

    modules_init => {
        Routes => {
          module => 'MyApp::Router',
        },
    },

But my doing that, I'm agreeing to provides the routes() and add_route() interfaces, etc.

Thoughts?

mla

unread,
Mar 23, 2014, 2:08:04 AM3/23/14
to perl...@googlegroups.com
I have an experiment for this here:

It's not trying to rebless currently. Instead, it simply calls the controller action as a method rather than as a subroutine.
The drawback vs. reblessing is now you need to keep track of the controller class vs. the app class.

I moved the dispatch logic into the Routes class. I know that might be a separation-of-concerns issue but I noted that Routes was already loading the controller classes, so it's already tightly coupled in that respect.
If you look at this version of Kelp, it simply finds the matching routes and iterates over them, calling dispatch() on each one.

I added a setting to Kelp::Routes, use_method_dispatch(). If false (default), it calls all actions as subroutines, like normal.
If true, it calls them as methods.

So basically, all that's different is that with use_method_dispatch disabled, the controller action signature is:

MyApp::MyController;

sub action {
  my $app = shift;
  ...
}

whereas with it enabled, that becomes:

MyApp::MyController;

sub action;
  my $class = shift;
  my $app = shift;
  ...
}


I'm a little ambivalent about it. I like the fact that controllers can now inherit logic, but it seems like a bit of a pain to differentiate between the controller class and the app class, and now there's another flag to manage.

Looking at Rails, it appears that they instantiate the specific controller directly.


Stefan Geneshky

unread,
Mar 24, 2014, 8:43:22 PM3/24/14
to perl...@googlegroups.com
I am going to try to add my input on all of the above in one email:

1. Router reblessing the app instance into the target controller:

This has been requested several times in the past. The reason I've been reluctant to implement it is, that reblessing each request may become a bottleneck. I aimed for quick route dispatching. 
However, since you have quite a lot of code added for this on your branch, I cloned it and ran some benchmarks to see the difference. My benchmarks show that there is hardly any difference. I would like to run the same benchmarks on code that actually reblesses the app instane.

2. Custom routing:

I am not against using custom routers. However, it's not only routes() and add_route() interfaces that need to be provided. There is also named attribute, which contains the named captures for the route.
If we were to go down this road, I think we should use a small roles module, such as Role::Tiny. 

3. Calling the controller action as method:

I agree with you, that this is pain in the neck and just not pretty. I am in favor of reblessing, if it's not a bottleneck.

Stefan

mla

unread,
Mar 30, 2014, 1:50:27 AM3/30/14
to perl...@googlegroups.com


On Monday, March 24, 2014 5:43:22 PM UTC-7, Stefan Geneshky wrote:
 I would like to run the same benchmarks on code that actually reblesses the app instane.

Hi Stefan. Sorry for the delay on this. Please see my blessed_routes branch here:

It's reblessing the app instance now. Make sure to set use_method_dispatch in the config. e.g.,

    modules_init => {
        Routes => {
          use_method_dispatch => 1,
        },
    },







Stefan Geneshky

unread,
Mar 31, 2014, 12:36:46 PM3/31/14
to perl...@googlegroups.com
This is looking great! I am working on integrating it to the master branch, with small changes. Stay tuned.

Stefan
Reply all
Reply to author
Forward
0 new messages