This is the Moose talk I gave at YAPC::NA 2012.
It included a practical example of a Moose objects code, a simple app called Comican. The code is not available online. If you want it, just email me (sawyer ATT cpan DOTT org).
6. … but why Moose?
package Person; package User;
use strict; use Email::Valid;
use warnings; use Moose;
use Moose::Util::TypeConstraints;
use Carp qw( confess );
use DateTime; extends 'Person';
use DateTime::Format::Natural;
subtype 'Email'
=> as 'Str'
sub new { => where { Email::Valid>address($_) }
my $class = shift; => message { "$_ is not a valid email
my %p = ref $_[0] ? %{ $_[0] } : @_; address" };
exists $p{name} has email_address => (
or confess 'name is a required attribute'; is => 'rw',
$class>_validate_name( $p{name} ); isa => 'Email',
required => 1,
exists $p{birth_date} );
or confess 'birth_date is a required attribute';
$p{birth_date} = $class
>_coerce_birth_date( $p{birth_date} );
$class>_validate_birth_date( $p{birth_date} );
$p{shirt_size} = 'l'
unless exists $p{shirt_size}:
$class>_validate_shirt_size( $p{shirt_size} );
return bless %p, $class;
}
sub _validate_name {
shift;
my $name = shift;
local $Carp::CarpLevel = $Carp::CarpLevel + 1;
defined $name
or confess 'name must be a string';
}
8. Writing objects in basic Perl 5
Create a reference (usually to a hash)
Connect it to a package (using „bless“)
Provide subroutines that access the hash keys
Error check the hell out of it
9. Writing objects in basic Perl 5, e.g.
package Dog;
use strict; use warnings;
sub new {
my $class = shift;
my $self = bless {}, $class;
return $self;
}
1;
10. Issues
Defining the same new() concept every time
No parameters for new() yet
Will have to do all error-checking manually
12. You get
use strict;
use warnings;
new() method
To hell with ponies, you get a moose!
(roll picture of a moose beating a pony in soccer)
13. Full affordance accessors (attributes)
has name => ( is => 'rw' );
„ro“ is available for read-only attributes
You can manually change setter/getter via writer/reader
Attributes can have defaults
Attributes can have type constraints
Attributes can have traits
Attributes can be lazy, have builders, clearers, predicates...
14. Type constraints
has name => ( is => 'ro', isa => 'Str' );
Str, Int, Bool, ArrayRef, HashRef, CodeRef, Regex,
Classes
Combine: ArrayRef|HashRef, ArrayRef[Str]
Derivatives (Int is a Num)
Create your own using subtype, available at
Moose::Util::TypeConstraints
15. Methods
Same as before
sub run {
my $self = shift;
say qq{I make it a habit only to run when
being chased!};
}
16. Inheritance easy as...
package Punk
use Moose;
extends 'Person';
Multiple inheritance also possible (extends accepts array)
package Child;
use Moose;
extends qw/Father Mother/;
17. Roles are even better
package Punk;
use Moose;
with qw/Tattoos Piercings Squatter/;
Roles are things you do, instead of things you are.
18. More hooks than a coat rack!
package User::WinterAware;
use Moose;
extends 'User';
before leaving => sub {
my $self = shift;
$self->cold and $self->take_jacket;
};
19. More hooks than a coat rack!
package User::Secure;
use Moose;
extends 'User';
around login => sub {
my $orig = shift;
my $self = shift;
$self->security_check and $self->$orig(@_);
};
20. More hooks than a coat rack!
Before
After
Around
Inner
Augment
21. Back to attributes...
has set => (
is => 'rw',
isa => 'Set::Object',
default => sub { Set::Object->new },
required => 1,
lazy => 1,
predicate => 'has_set',
clearer => 'clear_set',
22. Attribute options: default
default => 'kitteh' # string
default => 3 # number
default => sub { {} } # HashRef
default => sub { [] } # ArrayRef
default => sub { Object->new } # an Object
(if you need a more elaborate sub, use builder)
24. Attribute options: lazy
lazy => 1 # make it lazy
Class will not create the slot for this attribute unless it
absolutely has to, defined by whether it is accessed at all.
No access? No penalty!
Lazy == good
25. Attribute options: builder
builder => 'build_it' # subroutine name
sub build_it {
my $self = shift; # not a problem!
return Some::Object->new( $self-
>more_opts );
}
26. Attribute options: clearer
clearer => 'clear_it' # subroutine name
# you don't need to create the subroutine
sub time_machine {
my $self = shift;
$self->clear_it; # 'it' never happened :)
}
27. Attribute options: predicate
predicate => 'has_it' # subroutine name
# you don't need to create the subroutine
sub try_to_do_it {
my $self = shift;
$self->has_it && $self->do_it();
}
29. Example: Comican
A hub for various comics strips
Allow you to fetch comic strips
Standard uniformed interface to add more comics
We'll be using:
Roles
Lazy attributes
Overriding attributes options
Attribute predicates
30. Comican
comic modules Comican::Comic::Dilber
t interface
role
Comican::Comic::PennyArcade
Comican::Comic::xkcd Comican::
Role::Comic
main module
user
Comican.pm
31. Comican: overall
Comican.pm is the user's interface
It's a hub for Comican::Comic::* modules
They are objects that fetch specific comic strips
They have a common interface
Defined by Comican::Role::Comic
33. /^M(?:o(?:o|[ou]se)?)?$/
Moose: standart
Mouse: subset, uses XS, faster
(Any::Moose: use Mouse unless Moose already loaded)
Moo: Pure-Perl, subset, blazing fast
Mo: As little as possible (incl. character count)
M: Really as little as possible
Hummus (HuMoose): Incompatible chickpeas paste