I'm looking for a way to set up some helper methods from within a parent Moose class, rather than a standalone utility class. If it is possible, it would be a more transparent way of adding Moose sugar to modules, as it does not require explicitly requiring any helper modules (as everything would come via the extends
declaration).
Based on the example provided in the documentation, this is roughly what I am going for:
package Parent;
use Moose;
Moose::Exporter->setup_import_methods(
with_meta => [ 'has_rw' ],
as_is => [ 'thing' ],
also => 'Moose',
);
sub has_rw {
my ( $meta, $name, %options ) = @_;
$meta->add_attribute(
$name,
is => 'rw',
%options,
);
}
# then later ...
package Child;
use Moose;
extends 'Parent';
has 'name';
has_rw 'size';
thing;
However this does not work:
perl -I. -MChild -wle'$obj = Child->new(size => 1); print $obj->size'
String found where operator expected at Child.pm line 10, near "has_rw 'size'" (Do you need to predeclare has_rw?) syntax error at Child.pm line 10, near "has_rw 'size'" Bareword "thing" not allowed while "strict subs" in use at Child.pm line 12. Compilation failed in require. BEGIN failed--compilation aborted.
PS. I've also tried moving the export magic into a role (with Role;
rather than extends Parent;
) but the same errors occur.
This isn't supported, and there is a good reason why. A Class or a Role are not the same as sugar methods, and at some level different things should be different. If your problem is having to "use" Moose + A Custom Sugar package then you can solve that by simply having your custom sugar package export Moose as well, stealing from your example:
package MySugar;
use strict;
use Moose::Exporter;
Moose::Exporter->setup_import_methods(
with_meta => [ 'has_rw' ],
as_is => [ 'thing' ],
also => 'Moose',
);
sub has_rw {
my ( $meta, $name, %options ) = @_;
$meta->add_attribute(
$name,
is => 'rw',
%options,
);
}
Then you simply say:
package MyApp;
use MySugar; # imports everything from Moose + has_rw and thing
extends(Parent);
has_rw 'name';
has 'size';
thing;
This is how MooseX::POE
works, as well as several other packages. I for one would argue against having extends
bring in the sugar like you're suggesting here because a Class is not a bundle of sugar functions, and the two really should never be confused.
UPDATE: To bring in both at once the cleanest approach is to rework Parent as a role that is applied to Moose::Object.
package Parent::Methods;
use 5.10.0;
use Moose::Role;
sub something_special { say 'sparkles' }
Then we simply change the call to Moose::Exporter in MySugar to look like
Moose::Exporter->setup_import_methods(
apply_base_class_roles => 'Parent::Methods',
with_meta => ['has_rw'],
as_is => ['thing'],
also => 'Moose',
);
Now you can simply say
package MyApp;
use MySugar;
has_rw 'name';
has 'size';
thing;
package main;
MyApp->new->something_special; # prints sparkles
Which is I believe the final detail you were wanting.