Writing your own extensions does require a good understanding of the meta-model. You can start learning about this with the Moose::Manual::MOP docs. There are also several extension recipes in the Moose::Cookbook.
Explaining how to write extensions is beyond the scope of this manual. Fortunately, lots of people have already written extensions and put them on CPAN for you.
This document covers a few of the ones we like best.
use Moose::Autobox; $somebody_elses_object->orders->push($order);
Lexically scoped and not to everybody's taste, but very handy for sugaring up other people's APIs and your own code.
package User; use Moose; use MooseX::StrictConstructor; has 'name'; has 'email'; User->new( name => 'Bob', emali => 'bob@example.com' );
With MooseX::StrictConstructor, that typo (``emali'') will cause a runtime error. With plain old Moose, the ``emali'' attribute would be silently ignored.
If you don't want to risk that, for now we recommend the decidedly more clunky (but also faster and simpler) MooseX::Params::Validate. This module lets you apply Moose types and coercions to any method arguments.
package User;
use Moose;
use MooseX::Params::Validate;
sub login {
my $self = shift;
my ($password)
= validated_list( \@_, password => { isa => 'Str', required => 1 } );
...
}
This makes writing a command-line application as a module trivially simple:
package App::Foo;
use Moose;
with 'MooseX::Getopt';
has 'input' => (
is => 'ro',
isa => 'Str',
required => 1
);
has 'output' => (
is => 'ro',
isa => 'Str',
required => 1
);
sub run { ... }
Then in the script that gets run we have:
use App::Foo; App::Foo->new_with_options->run;
From the command line, someone can execute the script:
foo@example> foo --input /path/to/input --output /path/to/output
In perl, you can just as easily use a global. However, if your colleagues are Java-infected, they might prefer a singleton. Also, if you have an existing class that isn't a singleton but should be, using MooseX::Singleton is the easiest way to convert it.
package Config; use MooseX::Singleton; # instead of Moose has 'cache_dir' => ( ... );
As of perl5 version 14, this goal has been achieved, and modules such as Devel::CallParser, Function::Parameters, and Keyword::Simple provide mechanisms to mangle perl syntax that don't require hallucinogenic drugs to interpret the error messages they produce.
If you want to use declarative syntax in new code, please for the love of kittens get yourself a recent perl and look at Moops instead.
use MooseX::Types -declare => ['PositiveInt'];
use MooseX::Types::Moose 'Int';
subtype PositiveInt,
as Int,
where { $_ > 0 },
message { "Int is not larger than 0" };
One nice feature is that those bareword names are actually namespaced in Moose's type registry, so multiple applications can use the same bareword names, even if the type definitions differ.
use MooseX::Types -declare => [ qw( Name Color ) ];
use MooseX::Types::Moose qw(Str Int);
use MooseX::Types::Structured qw(Dict Tuple Optional);
subtype Name
=> as Dict[ first => Str, middle => Optional[Str], last => Str ];
subtype Color
=> as Tuple[ Int, Int, Int, Optional[Int] ];
Of course, you could always use objects to represent these sorts of things too.
package User; use Moose; use MooseX::ClassAttribute; has 'name' => ( ... ); class_has 'Cache' => ( ... );
Note however that this class attribute does not inherit like a Class::Data::Inheritable or similar attribute - calling
$subclass->Cache($cache);
will set it for the superclass as well. Additionally, class data is usually The Wrong Thing To Do in a strongly OO program since it makes testing a lot harder - consider carefully whether you'd be better off with an object that's passed around instead.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.