Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

Ovid (2709)

Ovid
  (email not shown publicly)
http://publius-ovidius.livejournal.com/
AOL IM: ovidperl (Add Buddy, Send Message)

Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.

Journal of Ovid (2709)

Thursday March 26, 2009
05:13 AM

More on "Better Code Via Roles"

[ #38705 ]

In our Catalyst controllers, we have methods like this:

sub allowed_query_params : Private {
    my ($self, $c) = @_;
    return $c->forward(
        'parameters_for_type',
        [ qw(tag broadcast) ]);
}

That let's our code know that this controller only allows query parameters for "broadcast" and "tag" searches. Along with this, everything allows "pagination" parameters. Magically, this allows us to append /doc/ to the end of most URLs for our REST interface and developers automatically see real, programatically generated documentation for allowed query parameters. (Er, sort of. This is a new, unreleased feature.)

Except that doesn't quite work. It's on a per controller basis, not a per resource basis. A controller might handle multiple resources:

/api/v1/episode/
/api/v1/episode/changes/
/api/v1/episode/pid.b0034c98/childre n/

Each of those resources creates a different DBIx::Class resultset. Each resultset may have a slightly different interface and thus require different query parameters to be used. This is where our conversion to Moose roles has made life much easier. In our result set base class (we may eventually eliminate all inheritance), we have this:

use Moose;
use MooseX::ClassAttribute;
extends 'DBIx::Class::ResultSet';

class_has query_params => (
    is      => 'ro',
    default => sub {
        PIPs::QueryParams->new(
            params => {
                rows => { datatype => "xsd:positive-integer" },
                page => { datatype => "xsd:positive-integer" },
            },
        );
    });

(If I recall correct, class data is not built into Moose because Stevan objects to class data. Correct me if I'm wrong!)

That bit of code ensures that all resultset classes have pagination parameters. Now let's say that an individual resulset class only allows 'tag' searches. It might look like this:

package Some::ResultSet::Class;

use Moose;
extends 'Some::ResultSet::Base';
with qw(
    DoesTagSearch
);

And in the DoesTagSearch role we have this:

around query_params => sub {
    my ($query_params, $proto) = @_;
    my $params = $proto->$query_params;
    $params->combine_params(
        PIPs::QueryParams->new(
            params => {
                tag_pid              => {},
                tag_value            => {},
                tag_scheme_pid       => {},
                tag_scheme_namespace => {},
            },
        ),
    );
};

Now for every resource, we know the resultset class we're getting back and we can just call this:

my $params = Some::ResultSet::Class->query_params;

Merely by specifying what type of search a resultset allows, the controllers can automatically infer what type of query parameters they support. Do we want to add broadcast and title searches to a resource?

package Some::ResultSet::Class;

use Moose;
extends 'Some::ResultSet::Base';
with qw(
    DoesTagSearch
    DoesBroadcastSearch
    DoesTitleSearch
);

And everything magically "just works". All of that silly "allowed_query_params" mess is going away from our controllers because that's duplicating knowledge and we've already been bitten by having to maintain this duplication. Adding new features to resultset classes is becoming stupidly easy at times.

In other news, I'll be at the Perl-QA Hackathon tomorrow. Yay!

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.