If you’ve never worked with MooX::Role::Parameterized or MooseX::Role::Parameterized, you might wonder what is a parameterized role at all?
Roles are used when you need to share behaviour among several classes that don’t have to be related by inheritance. Normally, a role just adds a bunch of methods to the class that consumes it (there’s more, you can for example specify which other methods the role expects to already exist).
A parameterized role makes it possible to provide parameters for the consumed role. This way, you can adjust the behaviour for each consuming class.
The standard syntax to apply a role to a class before version 0.100 of the module was to use the apply class method:
# My/Role.pm package My::Role; use Moo::Role; use MooX::Role::Parameterized; role { my ($params, $mop) = @_; $mop->has($params->{name} => is => $params->{is}); }
# My/Obj.pm package My::Obj; use Moo; use My::Role; 'My::Role'->apply({ name => 'size', is => 'ro', });
If we now created an object $o using my $o = 'My::Obj'->new(size => 2), we could get the value of the attribute size using the $o->size getter: the role created a new read-only attribute size for us.
What I didn’t like about applying a role to a class the old standard way was it wasn’t declarative. You could easily overlook it as a block of code happening at runtime, while the meaning of the code was This is how a role is consumed. Therefore, I used the alternative experimental syntax:
package My::Obj; use Moo; use MooX::Role::Parameterized::With 'My::Role' => { name => 'size', is => 'ro', };
It's part of a use clause, so it’s clear that it’s happening at compile time.
I promoted one of my side-jobs to a full-time job recently. They gave me a new computer where I had to install all my code base to start working on it 8 hours a day instead of a couple a month.
Imagine my surprise when the code stopped with an error:
Can't locate object method "size" via package "My::Obj" at ./run.pl line 37.
Line 37 was where I called $o->size!
When installing the dependencies for my code, the most recent version of MooX::Role::Parameterized was installed from CPAN (0.501). The experimental syntax is no longer documented and as I found out, doesn’t work anymore.
The old non-experimental syntax still works, but there’s a new syntax, too. It uses the with keyword that looks like the one that can be used to consume a Moo::Role, but if we first use MooX::Role::Parameterized::With, it can also accept parameters for the role application.
package My::Obj; use Moo; use MooX::Role::Parameterized::With 0.501; with 'My::Role' => { name => 'size', is => 'ro', };
Moreover, we should change the definition of the role, too. Parameters should be predeclared using the parameter keyword (similarly to MooseX::Role::Parameterized), and they can be then accessed via getters instead of peeking inside a parameter hash reference.
package My::Role; use Moo::Role; use MooX::Role::Parameterized 0.501; parameter name => (is => 'ro'); parameter is => (is => 'ro'); role { my ($params, $mop) = @_; $mop->has($params->name => is => $params->is); }
Note: Published to my blog, too.
|
|---|