Meta-Moose

Portland, Oregon

April 8th, 2009

Plan

Plan

Attributes

sub foo {
  my $self = shift;
  $self->{foo} = shift if @_;
  return $self->{foo};
}
__PACKAGE__->mk_accessors(qw(foo));
has foo => (is => 'rw');

http://search.cpan.org/perldoc?Moose::Manual::Attributes

Method Modifiers

package Parent;
sub foo { print "I'm a foo!"; return 17 }

package Child;
sub foo {
  my $self = shift;
  die "argh!" unless $self->is_valid;
  my $rv = $self->SUPER::foo(@_);
  print "A little kid foo!";
  return $rv + 5;
}
package Child;
before foo => sub {
  die "argh!" unless shift->is_valid;
};

after foo => sub {
  print "A little kid foo!";
};

around foo => sub {
  my $next = shift;
  return shift->$next(@_) + 5;
};

http://search.cpan.org/perldoc?Moose::Manual::MethodModifiers

More

Type Constraints

use MooseX::Types::Moose qw(Int Str ArrayRef HashRef);
my $tc = find_type_constraint(HashRef);
if ($tc->check($input)) { ... }
has foo => (is => 'rw', isa => HashRef);
use MooseX::Params::Validate;
sub foo {
  my ($self, %arg) = validated_hash(
    \@_,
    bar => { isa => Int },
  )
}
has foo => (is => 'rw', isa => ArrayRef[Int]);

Subtyping

use MooseX::Types::Moose qw(Int ArrayRef);
use MooseX::Types -declare => [ qw(PosInt PosEvenInt PosIntTriplet) ];

subtype PosInt,
  as Int,
  where { $_ > 0 },
  message { "Int is not greater than 0" };

subtype PosEvenInt,
  as PosInt,
  where { $_ % 2 == 0 },
  message { "Int is not even" };

subtype PosIntTriplet,
  as ArrayRef[PosInt],
  where { @$_ == 3 },
  message { "Must have exactly 3 PosInts" };

Type Constraint Libraries

package MyApp::Types;
use MooseX::Types -declare => [ 'PosInt' ];
subtype PosInt, ...

package MyApp;
use MyApp::Types qw(PosInt);

has awesome => (isa => PosInt); # don't let awesomeness drop to 0

Type Constraints

continued...

Type Constraints

continued...

Type Constraints

Type Coercions

sub read_file {
  my ($self, $file) = @_;
  unless (blessed $file) {
    $file = IO::File->new('<', $file);
  }
  # ... do something with $file
}
continued...

Type Coercions

sub read_file {
  my ($self, $file) = @_;
  unless (blessed $file) {
    $file = IO::File->new('<', $file);
  }
  # ... do something with $file
}
use MooseX::Types -declare => ['File'];

subtype File, as 'IO::File';
coerce File,
  from Str,
  via { IO::File->new('<', $_) or die "Can't open $_: $!" };

package MyApp::FileReader;
use Moose; 
use MyApp::Types qw(File);
has input_file => (is => 'rw', isa => File, coerce => 1);

# elsewhere
$f = MyApp::FileReader->new(input_file => $fh);
$f = MyApp::FileReader->new(input_file => '/some/file');

Profit

http://search.cpan.org/perldoc?Moose::Manual::Types

http://search.cpan.org/perldoc?MooseX::Types

http://search.cpan.org/perldoc?Moose::Util::TypeConstraints

Roles

Role as interface

package Fey::Role::Named;
use Moose::Role;
requires 'name';

Role as label

package Fey::Role::Joinable;
use Moose::Role;
sub is_joinable { 1 }

Role as complex definition

Role as complex behavior

Roles on objects

my $mech = WWW::Mechanize->new;
WWW::Mechanize::TreeBuilder->meta->apply($mech);

# adds $mech->look_down, etc.

Roles > Inheritance

sub driver_name { croak "A subclass should override this!" }

http://search.cpan.org/perldoc?Moose::Manual::Roles

Meta Object Protocol (MOP)

MooseX-tension

http://search.cpan.org/perldoc?MooseX::StrictConstructor

http://search.cpan.org/perldoc?Moose::Cookbook::Extending::Recipe1

The End