Two Moose at Play

So today in the Moose pen I am going to have a closer look at my Role from my last post. So here it is


package Database::Accessor::Roles::Base;
BEGIN {
$Database::Accessor::Roles::DAD::VERSION = "0.01";
}
use Moose::Role;
has 'name' => (
required => 1,
is => 'rw',
isa => 'Str'
);
has 'alias' => (
is => 'rw',
isa => 'Str'
);

Now the above is fine for my View and Element Database::Accessor classes but the above sort of breaks down when I have a look a the 'Database::Accessor::Predicate' class.

Now it is always good to have a class to have a 'name', makes debugging a little easier, but is the name required in this Class. Thinking a few jumps ahead when when I go to write my say my SQL DAD I can not see much use for requiring a name in a predicateand I cannot think of any case where I will need an 'alias' so to do this;


package
Database::Accessor::Predicate;
use Moose;
with qw(Database::Accessor::Roles::Base);

is not what I really want.

Now I could do this in Predicate to mitigate things


has '+name' => ( required => 0 );

Now in this case I am telling Moose to override the consumed aspect of 'required => 1' with 'required => 0' thus changing it to not required. I can test this by changing my 14_predicate.t case like so;

--my $predicate = Database::Accessor::Predicate->new({name => 'name',left=> {name=>'left'},right=>{name=>'right'}});
++my $predicate = Database::Accessor::Predicate->new({left=> {name=>'left'},right=>{name=>'right'}});

and all my test still pass

ok 1 - use Database::Accessor;
ok 2 - use Database::Accessor::Predicate;
ok 3 - predicate is a Predicate
ok 4 - View does role Database::Accessor::Roles::Base


Now that leaves the little matter of the alias. Unfortunately Moose has no easy way to fix this. I could go into a very long post about how I can use the BEGIN sub along with the MOP remove_attribute function to remove it but that is very very far from an elegant or even a good solution. So I am left with one of three choices.

  1. Drop 'alias' from the role
  2. Make two roles one for Base one for Alias
  3. Make two roles and try to exclude 'alias' from one?
Well for #1 the coding is easy enough but then I still have a doubling up of the alias attributes again. For #2 I then have to have an extra line in the with clause for View and Element and an extra role. Unfortunately for #3 I was thinking of using the 'excludes' command for roles but that is just for methods not for 'attributes' . If I was to make 'alias' into I sub I could do this but like the remove_attribute solution it is just not pretty. So #2 it is.

I first start with my Base role and remove alias form it.


package
Database::Accessor::Roles::Base;
BEGIN {
$Database::Accessor::Roles::DAD::VERSION = "0.01";
}
use Moose::Role;
has 'name' => (
required => 1,
is => 'rw',
isa => 'Str'
);

next I create the second role called Alias

package
Database::Accessor::Roles::Alias;
BEGIN {
$Database::Accessor::Roles::Alias = "0.01";
}
use Moose::Role;
with 'Database::Accessor::Roles::Base';
has 'alias' => (
is => 'rw',
isa => 'Str',
);
}

and in this one I consume the 'Base' role then I change the View and Element classes to consume the 'Alias' role.

{
package
Database::Accessor::View;
use Moose;
with qw(Database::Accessor::Roles::Alias);

}
{
package
Database::Accessor::Element;
use Moose;
with qw(Database::Accessor::Roles::Alias);
}


Now when you think about it this is a much more logical way to apply and name my roles because if you have an 'alias' you must also have a 'name'.

Now to finish this off I just have the Predicate class consume the 'Base' role


package
Database::Accessor::Predicate;
use Moose;
with qw(Database::Accessor::Roles::Base);

add as always a little test for this

eval{
warn("rtest=".$predicate->alias());
};
if ($@){
pass("Predicate cannot alias");
}
else {
fail("Predicate cannot alias");
}

and a quick run

ok 1 - use Database::Accessor;
ok 2 - use Database::Accessor::Predicate;
ok 3 - predicate is a Predicate
ok 4 - View does role Database::Accessor::Roles::Base
ok 5 - Predicate cannot alias

So there you have it. With just a little jiggling about I have saved some code duplication and have a good first working role.
moose-at-play.jpg

Leave a comment

About byterock

user-pic Long time Perl guy, a few CPAN mods allot of work on DBD::Oracle and a few YAPC presentations