Moose - YAPC::NA 2012

  • Upload
    xsawyer

  • View
    2.106

  • Download
    4

Embed Size (px)

Citation preview

Moose

Sawyer X

Sawyer X

blogs.perl.org/users/sawyer_x

search.cpan.org/~xsawyerx

metacpan.org/author/XSAWYERX

github.com/xsawyerx/

The Dancer guy!

Projects: Dancer, Module::Starter, MetaCPAN::API, MooseX::Role::Loggable, etc.

Moose

Object system

Metaclass-based

Advanced

Sophisticated

Extensible

Production-ready

but why Moose?

package Person;

use strict;use warnings;

use Carp qw( confess );use DateTime;use DateTime::Format::Natural;

sub new { my $class = shift; my %p = ref $_[0] ? %{ $_[0] } : @_;

exists $p{name} or confess 'name is a required attribute'; $class->_validate_name( $p{name} );

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';}

package User;

use Email::Valid;use Moose;use Moose::Util::TypeConstraints;

extends 'Person';

subtype 'Email' => as 'Str' => where { Email::Valid->address($_) } => message { "$_ is not a valid email address" };

has email_address => ( is => 'rw', isa => 'Email', required => 1,);

Get it?

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

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;

Issues

Defining the same new() concept every time

No parameters for new() yet

Will have to do all error-checking manually

Moose

package Dog;

use Moose;

1;

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)

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...

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

Methods

Same as beforesub run { my $self = shift; say qq{I make it a habit only to run when being chased!};}

Inheritance easy as...

package Punkuse Moose;extends 'Person';Multiple inheritance also possible (extends accepts array)package Child;use Moose;extends qw/Father Mother/;

Roles are even better

package Punk;use Moose;with qw/Tattoos Piercings Squatter/;

Roles are things you do, instead of things you are.

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;};

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(@_);};

More hooks than a coat rack!

Before

After

Around

Inner

Augment

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', builder => 'build_set',);

Attribute options: default

default => 'kitteh' # stringdefault => 3 # numberdefault => sub { {} } # HashRefdefault => sub { [] } # ArrayRefdefault => sub { Object->new } # an Object

(if you need a more elaborate sub, use builder)

Attribute options: required

required => 1 # requiredrequired => 0 # not required

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

Attribute options: builder

builder => 'build_it' # subroutine name

sub build_it { my $self = shift; # not a problem! return Some::Object->new( $self->more_opts );}

# and, obviously...after build_it => sub { they will come };

Attribute options: clearer

clearer => 'clear_it' # subroutine name

# you don't need to create the subroutinesub time_machine { my $self = shift; $self->clear_it; # 'it' never happened :)}

- Clear the value (not back to default)

Attribute options: predicate

predicate => 'has_it' # subroutine name

# you don't need to create the subroutinesub try_to_do_it { my $self = shift; $self->has_it && $self->do_it();}

Checks an attribute value existsEven false valuesWhich is good

Attribute options: lazy_build

lazy_build => 1 # 1,builder => '_build_it', # privateclearer => 'clear_it',predicate => 'has_it',

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

Comican

Comican.pmComican::Comic::xkcdComican::Comic::PennyArcadeComican::Comic::DilbertComican::Role::Comicuser

main module

comic modules

interface role

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

SHOW ME THE CODE!

/^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

Thank you.