introduction to moose

47
. OOP for Perl Moose

Upload: thashaa

Post on 15-May-2015

3.308 views

Category:

Technology


2 download

DESCRIPTION

Moose is a framework for Perl 5 build on top of Class::MOP, that brings all features of object-oriented programming.

TRANSCRIPT

Page 1: Introduction to Moose

.OOP for PerlMoose

Page 2: Introduction to Moose

● ( , , , ...)Classes methods types attributes open recursion

● Encapsulation

● Aggregation

● Message passing and dynamic dispatch

● Inheritance and polymorphism

● Abstraction

What we expect from OOPWhat we expect from OOP

Skip definitions

Page 3: Introduction to Moose

ClassesClasses

● Templates for defining objects state and

behavior

Page 4: Introduction to Moose

EncapsulationEncapsulation

● Specifying which classes may use the

. :members of an object e g

, , public protected or private determining

, whether they are available to all classes

- .sub classes or only the defining class

Page 5: Introduction to Moose

AggregationAggregation

● Object containing another object

Page 6: Introduction to Moose

Message passing and dynamic dispatchMessage passing and dynamic dispatch

● Message passing is the process by which an object sends data to

another object or asks the other object to invoke a method

● , when a method is invoked on an object the object itself determines

what code gets executed by looking up the method at run time in a

( table associated with the object needed when multiple classes

)contain different implementations of the same method

Page 7: Introduction to Moose

Inheritance and polymorphism Inheritance and polymorphism

● allows the programmer to treat derived class members just like

' (" " their parent class s members Subclasses are more specialized

, versions of a class which inherit attributes and behaviors from

, .)their parent classes and can introduce their own

● - a class has all the state and behavior of another class

polymorphism

Page 8: Introduction to Moose

What OOP features offers Perl?What OOP features offers Perl?

● 5:MOP in Perl

● Class - package

● Object - ( blessed reference a scalar type holding a reference to object

, , .)data – object may be a hash array or reference to subroutine

● Method - a subroutine within a package

● Constructor – a method that returns reference to blessed variable

Page 9: Introduction to Moose

What OOP features offers Perl?What OOP features offers Perl?

package Car; sub new { my $class = shift; my $brand = shift; my $self = {}; $self->{'brand'} = $brand; bless ($self, $class); return $self; }

Page 10: Introduction to Moose

What OOP features offers Perl?What OOP features offers Perl?

● .Encapsulation – in general only by convention

● : , , Some tricks private variable private method private function

package Mom;

sub new{ my $class = shift; my $self = { 'CARD_PIN' => '0000', };

my $closure = sub { my $arg = shift; if ($arg and $arg eq 'nice'){ return $self->{'CARD_PIN'}; } else { return 'forget!'; } }; bless($closure, $class); return $closure; };

package Kido;

use base qw(Mom);

sub ask_for_pin{ my $self = shift; my $how = shift; return &{$self}($how);}

package main;my $mom = Mom->new();my $kido = Kido->new();

print $kido->ask_for_pin('not nice');print $kido->ask_for_pin('nice');

●“ - ... ...Inside out” classes not handy “There is only one way to do it ”.

Page 11: Introduction to Moose

What OOP features offers Perl?What OOP features offers Perl?

{package Mom; (...)

my $_prepare_pastry = sub{ print "makin' pastry 2 \n"; };

sub make_cookies{ &{$_pastry}; print "cookies ready\n"; }}

package main;(...)package main;

my $mom = Mom->new();$mom->make_cookies();

{package Mom; (...)

sub _prepare_pastry{ if (caller ne __PACKAGE__){ die; } else { print "makin' pastry \n"; } }

sub make_cookies{ _prepare_pastry(); print "cookies ready\n"; }}

package main;(...)my $mom = Mom->new();$mom->_prepare_pastry(); #thiscompiles!$mom->make_cookies();

Page 12: Introduction to Moose

What OOP features offers Perl?What OOP features offers Perl?

● Aggregation

my $eva = Person->new();my $car1 = Car->new();$car1->brand( 'Fiat' );

$eva->cars->[0]->brand(); #returns 'Fiat'

package Person;

sub new { my $class = shift; my $self = {}; $self->{'cars'} = (); bless( $self, $class ); return $self; }

sub cars { my $self = shift; my $car = shift; if ( ref( $car ) eq 'Car' ) { push @{ $self->{'cars'} }, $car; } return $self->cars; }

Page 13: Introduction to Moose

What OOP features offers Perl?What OOP features offers Perl?

● ( - ) : ()Inheritance multi object and polymorphism use base

package Person;

sub new { my $class = shift; my $self = {}; bless( $self, $class ); return $self;}

sub name { my $self = shift; if ( @_ ) { $self->{'name'} = shift } return $self->{'name'};}

sub say_name { my $self = shift; printf( "My name is %s. \n", $self->{'name'} );}

package Employee;

use base qw(Person);

sub new { my $class = shift; my $job = shift; my $self = $class->SUPER::new(); $self->{'job'} = $job;

bless( $self, $class ); return $self;}

#overridingsub say_name { my $self = shift; $self->SUPER::say_name(); printf( "My job is %s.\n", $self->{'job'} ); }

#inheritance and polymorphismmy $adam = Employee->new( 'Developer' );$adam->name( 'Adam' );$adam->say_name

Page 14: Introduction to Moose

What OOP features offers Perl?What OOP features offers Perl?

● Abstraction – only objects

package File; use Carp; sub new { my $class = shift; my $self = {}; bless ($self, $class); return $self; }

sub load{ croak('not implemented'); }

package BMP; use base qw(File);

package JPG; use base qw(File); sub load{ my $self = shift; print "File loaded. \n"; }

my $bmp = BMP->new();$bmp->load(); my $jpg = JPG->new();$jpg->load();

Page 15: Introduction to Moose

What OOP features offers Perl?What OOP features offers Perl?

?What is missing

● - .The in language support for OO features is minimal

● , , ... No type checking no horizontal inheritance no encapsulation

!There is more than one way to do it

Page 16: Introduction to Moose

MooseMoose

, There is more than one way to do it but sometimes !consistency is not a bad thing either

Page 17: Introduction to Moose

Moose is Perl.Moose is Perl.

=Moose:: + Class MOP semantic

Page 18: Introduction to Moose

Moose is Perl.Moose is Perl.

● common system for building classes

● , new levels of code reuse allowing you to improve your

code with features that would otherwise be too complex or

expensive to implement

Page 19: Introduction to Moose

Moose is Perl. Moose is Perl.

+ Everything missing in OO Perl you can find in Moose some

!important bonuses

● Type matching

● Coercion - the ability to convert types of one type to another when

necessary

● Encapsulation

● Method Modifiers - , the ability to add code that runs before after or

around an existing method

● Horizontal inheritance - - roles the ability to add predefined

-functionality to classes without sub classing

… .and much more

Page 20: Introduction to Moose

Moose – first example.Moose – first example.

package Vehicle;use Moose;

has 'RegNum' => ( 'is' => 'rw', 'isa' => 'Str');

sub goto{ my $self = shift; my $place_name = shift; print "Going to $place_name \n"; }

__PACKAGE__->meta->make_immutable;

no Moose;1;

use Vehicle;my $avehicle = Vehicle->new();

$acar->RegNum('123456');print $acar->RegNum;

$acar->goto('Oriente');

MOO

S E C

LASS

Sets strict and warnings

.Class attributes

.Class methods

() We get new for free

We get also default .accessors for free

Page 21: Introduction to Moose

Moose – first example.Moose – first example.

package Vehicle;use strict;

sub new { my $class = shift; my %args = @_;

my $self = { '_RegNum' => undef };

if ( exists( $args{'RegNum'} ) && defined( $args{'RegNum'} ) ) { $self->{'_RegNum'} = $args{'RegNum'}; }

return bless($self, $class);}

sub RegNum { my $self = shift; my $regnum = shift; if ( $regnum ) { $self->{'_RegNum'} = $regnum; } return $self->{'_RegNum'};}

sub goto{ my $self = shift; my $place_name = shift; print "Going to $place_name \n";}

1;

package Vehicle;use Moose;

has 'RegNum' => ( 'is' => 'rw', 'isa' => 'Str');

sub goto{ my $self = shift; my $place_name = shift; print "Going to $place_name \n"; }

no Moose;1;

12 :lines of code from previous slide give us all this

Page 22: Introduction to Moose

Lets have a closer look...Lets have a closer look...

(...)

has 'RegNum' => ( 'is' => 'rw', 'isa' => 'Str');

(...)

' ' - -is – defines if argument is read write or read only

' ' ( )isa – defines type of the attribute and validate it during assignment

● Arguments

' ' ' ' rw or ro – tells which accessors will be created

:Moose types , , , , , ,Bool Str Num Int ArrayRef HashRef

and more

Page 23: Introduction to Moose

Lets have a closer look...Lets have a closer look...

has 'RegNum' => ( 'is' => 'ro', 'isa' => 'Str');

$avehicle->RegNum('123456');

my $avehicle = Vehicle->new(

'RegNum'=>'1234'

);

print $avehicle->RegNum."\n";

● - Read only arguments

...If we restrict access to the attribute ' .the default accessor won t be created

' This method doesn t exist – it results in compilation error

The only right moment to set up the .attribute is during initialization

.We can still read it wherever we want

Page 24: Introduction to Moose

What more we can do with attributes?What more we can do with attributes?

has 'RegNum' => ( 'is' => 'ro', 'isa' => 'Str', 'required' => 1, );

#$acar = Vehicule->new();

my $avehicle = Vehicle->new('RegNum'=>'123456');

my $avehicle = Vehicle->new('RegNum'=>'');

.Required attribute must be set ...It means that

… this will not compile

... ..but we still can have illegal vehicle .RegNum can be set to empty string

has 'RegNum' => ( 'is' => 'ro', 'required' => 1, );

my $avehicle = Vehicle->new('RegNum'=>undef);BUT

If attribute has no type it can beset to undefined

● Required arguments

Page 25: Introduction to Moose

What more we can do with attributes?What more we can do with attributes?

has 'RegNum' => ( 'is' => 'ro', 'isa' => 'Str', 'required'=> 1, 'clearer' => 'unregister', 'predicate'=>'is_registered', );

my $avehicle = Vehicule->new('RegNum'=>'1234');

print $avehicle->RegNum;

$avehicle->unregister();

if (!$avehicle->is_registered()){ print "Vehicle illegal!.\n"; }

' .You can t use accessors because it is “ro”

... , .Imagine the vehicle is a broken and is waiting to be scraped but first you must unregister it

... but you can set clearer to clean the value

and predicate to check if the value exists

.The method you get for free

● Clearer and predicate

Page 26: Introduction to Moose

What more we can do with attributes?What more we can do with attributes?

...Not every string can be the registration number

my $avehicle = Vehicle->new('RegNum'=>'11-xx-22');

#my $avehicle = Vehicle->new('RegNum'=>'111-xx-22');

package Vehicle;use Moose;use Moose::Util::TypeConstraints;

subtype 'RegistrationNo' => as 'Str', => where { /^(\d\d)(-)(\w\w)(-)(\d\d)$/ }, => message {"$_ is not valid registration number."};

has 'RegNum' => ( 'is' => 'ro', 'isa' => 'RegistrationNo', 'required'=> 1, 'clearer' => 'unregister', 'predicate'=>'is_registered', );

use TypeConstraints and create subtype

parent type

$_ compare to something

and use it

Subtypes can be more complex more examples here

● Subtypes

Page 27: Introduction to Moose

One Step Further - MooseX.One Step Further - MooseX.

.... 2 - : Lets define where is our vehicle a D coordinate two points x and y that

. must have positive value

. .This is very useful type We can pack it in separate package and reuse later

package MyTypes;

use Moose;use MooseX::Types -declare => [qw(Coordinate Point)];use MooseX::Types::Moose qw(Int HashRef);

subtype Point, as Int, where { $_>= 0}, message {'Must be positive number.'};

subtype Coordinate, as HashRef, where { Point->check( $_->{'X'} ) and Point->check( $_->{'Y'} )}, message {'Incorect coordinate.'.$_ };

what we want to create

what we use to create

a point

A coordinate that is a has of two valid points

● Custom types

Page 28: Introduction to Moose

.Lets use the coordinate to define where is the vehicle

use MyTypes qw( Coordinate );

(...)has 'place' => ( 'is' => 'rw', 'isa' => Coordinate,);(...)

my $place = {'X'=>1, 'Y'=>3 };

$avehicle->place( $place );

modify the vehicle class ( . )Vehicle pm

use it where ever you need

import custom type

● Custom types

One Step Further - MooseX.One Step Further - MooseX.

Page 29: Introduction to Moose

...?But maybe it would be easier to use it this way

$avehicle->place( [4,5] );

package MyTypes;use Moose;use MooseX::Types -declare => [qw(Coordinate Point)];use MooseX::Types::Moose qw(Int HashRef ArrayRef);

subtype Point, as Int, where { $_> 0}, message {'Must be positive number.'};

subtype Coordinate, as HashRef, where { Point->check( $_->{'X'} ) and Point->check( $_->{'Y'} )}, message {'Incorect coordinate.'.$_ };

coerce Coordinate, from ArrayRef, via { {'X'=>$_->[0], 'Y'=>$_->[1]} };

1;

(...)has 'place' => ( 'is' => 'rw', 'isa' => Coordinate, 'coerce' => 1,);

(...)

One Step Further - MooseX.One Step Further - MooseX.

● Custom types and coercion

We define how we can .transform one type to another

, ,In the end in class definition' Don t forget to turn on the

coercion on the argument

Page 30: Introduction to Moose

Private attributes – only Private attributes – only convention.convention.

?The vehicle may change its place only when it moves

(...)#an attribute to be publicly readable, but only privately settable.has '_place' => ( 'is' => 'ro', 'isa' => Coordinate, 'coerce' => 1, 'writer' => '_set_place', );

sub goto{ my $self = shift; my $coordinate = shift; $self->_set_place($coordinate);}

(...)

$avehicle->goto([7,8]);print Dumper($avehicle);print 'The vehicle is at'.$avehicle->_place->{'X'}.','.$avehicle->_place->{'Y'}.'.';

#my $place = {'X'=>1, 'Y'=>3 };#my $other_place = [4,5];#$avehicle->_set_place( $place );

This is what the manual says – .but this is only CONVENTION

.Now we can “move” the vehicle

.However this still would work MOOSE is PERL

reader and writer redefine the names of custom accessors

Page 31: Introduction to Moose

has '_mileage' => ( 'is' => 'ro', 'isa' => 'Num', 'required' => 1, 'default' => 0, 'writer' => '_set_mileage', );

around 'goto' => sub { my $orig = shift; my $self = shift;

my $coordinate1 = $self->_place; my $x1 = $coordinate1->{'X'}; my $y1 = $coordinate1->{'Y'};

#@_ stores new coordinate $self->$orig(@_);

my $coordinate2 = $self->_place; my $x2 = $coordinate2->{'X'}; my $y2 = $coordinate2->{'Y'};

my $distance = sqrt(($x1-$x2)**2+($y1-$y2)**2); $self->_set_mileage($self->_mileage + $distance);};

Method modifiersMethod modifiers

.Mileage – every time the vehicle moves its mileage increase

One more private .attribute

Method modifier

,Has access to attributes before they are modified by

method

Executing main method

Accessing modifiedattributes

other actions

Page 32: Introduction to Moose

.Mileage – every time the vehicle moves its mileage increase

has '_place' => ( 'is' => 'ro', 'isa' => Coordinate, 'coerce' => 1, 'writer' => '_set_place', 'default' => sub {[0,0]}, );

print $avehicle->_mileage;

$avehicle->goto([7,8]);$avehicle->goto([1,1]);$avehicle->goto([4,5]);

print $avehicle->_mileage

Define default value

Every time we move vehicle .the mileage increase

Method modifiersMethod modifiers

Page 33: Introduction to Moose

Lazy, lazy_build and trigger.Lazy, lazy_build and trigger.

. .Imagine we want to sell the vehicle The price depends on the mileage

has 'price' => ( 'is' => 'ro', 'isa' => 'Num', 'predicate'=>'has_price', 'lazy_build'=>1, 'builder'=>'calculate_price', 'init_arg'=>undef, );

sub calculate_price { my $self = shift; my $price = 100000; if ($self->_mileage != 0){ $price = $price / $self->_mileage; } return $price;}

$avehicle->goto([1,1]);

print $avehicle->price;

$avehicle->goto([4,5]);

print $avehicle->price;

has 'price' => ( 'is' => 'ro', 'isa' => 'Num', 'predicate'=>'has_price', 'lazy_build'=>1,

+ = _lazy clearer lazy build

- Lazy value is calculated only when it is accessed and is unset.

Lazy needs default value or builder

.Method building the value

... , ' .despite we move the price didn t change Lazy build calculates the value only if it is unset.

Therefore we need to clean it every time .we want to get updated value

Page 34: Introduction to Moose

Lazy, lazy_build and trigger.Lazy, lazy_build and trigger.

' .Let s run the clearer automatically

has '_mileage' => ( 'is' => 'ro', 'isa' => 'Num', 'required' => 1, 'default' => 0, 'writer' => '_set_mileage', 'trigger' => sub { my $self=shift; $self->clear_price; } );

sub sell_vehicle { my $self = shift; $self->clear_price; return $self->price; }

$avehicle->goto([1,1]);print $avehicle->price;

$avehicle->goto([4,5]);print $avehicle->price;

print "The final price: ".$avehicle->sell_vehicle. "\n";

Every time the mileage changes the .clearer for price attribute is triggered

Lazy build is very useful for attributes are expensive to calculate – .we calculate it only while reading

We can also use method instead .the trigger The price is updated every time we read it

.using the method .Useful for expensive calculation

After this change the previous example shows updated value every time we access it

Page 35: Introduction to Moose

Code reuse - inheritance in Moose.Code reuse - inheritance in Moose.

?Is the vehicle car or bike

package Car;use Moose;

extends 'Vehicle';

has 'fuel' =>( 'is' => 'rw', 'isa' => 'Int', 'default'=>0,);

sub refuel { my $self = shift; $self->fuel($self->fuel + 10); }

override goto => sub{ my $self = shift; if($self->fuel eq 0){ print 'No fuel'; return; } return super;};

no Moose

Parent class

New attribute

New method

Overwritten method

Calling super

Page 36: Introduction to Moose

Code reuse - inheritance in Moose.Code reuse - inheritance in Moose.

package Bike;use Moose;

extends 'Vehicle';

has '+RegNum' => ( 'required'=> 0, );

no Moose;1;

my $abike = Bike->new();

changing inherited attribute

registration number is not linger required

Page 37: Introduction to Moose

Better code reuse – inheritance and roles.Better code reuse – inheritance and roles.

:Short explanation

● .Role is a “state or behavior that can be shared between classes ”

● ' , ' … ' .Role is not a class – can t be subclassed can t be extended we can t create an object of a role

● , .But we can use a role in a class and methods of the role in an object

Page 38: Introduction to Moose

' ' .We can create a truck role and use it in our vehicle

package Truck;use Moose::Role;

has 'capacity' => ( 'is' => 'ro', 'isa' => 'Int', 'default'=>10, 'required'=>1,);

has 'load' => ( 'is' => 'rw', 'isa' => 'Bool', 'default'=>0,);

sub do_load { my $self = shift; my $load = shift;

if(($self->capacity >= $load) and !$self->load){ $self->load(1);

}else{ print 'Load unsuccessful,'; }}

sub do_unload { my $self = shift; my $load = shift;

if($self->load){ $self->load(0); }else{ print 'Nothing to unload,'; }}no Moose;1;

We create a piece of functionality exactly the same way as we were

.creating a moose class

The only difference

Better code reuse – inheritance and roles.Better code reuse – inheritance and roles.

Page 39: Introduction to Moose

package Lorry;use Moose;

extends 'Car';with 'Truck';

no Moose;1;

(…)

use Lorry;

(…)

my $alorry = Lorry->new('RegNum'=>'11-xx-23', 'capacity'=>50);#$alorry->do_load(100); - more than capacity

$alorry->do_load(40);#$alorry->do_load(40); #unsecessfull - is loaded

$alorry->do_unload();$alorry->do_load(30);

#$alorry->goto([2,4]); - still can't go without the fuel

- .We want to have a car with a “truck functionality” a lorry

= Lorry Car with Truck role

?How to use Lorry .Lorry is a vehicle – mast have registration number

.Lorry has a Truck role – mast have capacity

.We can use all truck functions

But Lorry is still a car ' .so won t go without fuel

Better code reuse – inheritance and roles.Better code reuse – inheritance and roles.

Page 40: Introduction to Moose

package Truck;use Moose::Role;requires 'fuel';

(…)

use Moose;

extends 'Bike';with 'Truck';

no Moose;

'Truck' requires the method 'fuel' to be implemented by 'Lorrybike' at/usr/local/lib/perl5/site_perl/5.10.0/i386-linux-thread-multi/Moose/Meta/Role/Application.pm line 51

Moose::Meta::Role::Application::apply('Moose::Meta::Role::Application::ToClass=HASH(0xa5faa2c)','Moose::Meta::Role=HASH(0xa5f6a6c)', 'Moose::Meta::Class=HASH(0xa5f8754)') called at/usr/local/lib/perl5/site_perl/5.10.0/i386-linux-thread-multi/Moose/Meta/Role/Application/ToClass.pmline 31 (...)

In the end we want to assure that the truck role will be only used with anything that uses fuel

( - ?)Have you ever seen a lorry bike

' ' We require that a method fuel is present in a class where we

.use the Truck role

' Since bike doesn t use fuel .this code will not compile

Better code reuse – inheritance and roles.Better code reuse – inheritance and roles.

Page 41: Introduction to Moose

BUILDARGS and BUILD BUILDARGS and BUILD

' . :Let s go back to Vehicle It would be awesome to create a vehicle this way

$acar = Vehicule->new('11-xx-11');

around BUILDARGS => sub { my $orig = shift; my $class = shift;

my %a = @_; my %args = (); if ( @_ == 1 ) { $args{ 'RegNum' } = $_[0]; return $class->$orig( %args ); } return $class->$orig( %a );};

BUILDARGS method is called as a class method . before an object is created It has direct access .to arguments passed in method call

Page 42: Introduction to Moose

BUILDARGS and BUILD BUILDARGS and BUILD

. ...There is a possibility to have a bike without registration But we want to be warn about it

sub BUILD { my $self = shift; if(!$self->RegNum){ if($self->isa('Bike')){ print "Vehicle without registration number.\n"; } } }

my $abike = Bike->new();my $abike2 = Bike->new('22-yy-66');

.BUILD method is called after an object is created

We will be warn about creating a .bike without a registration number

Page 43: Introduction to Moose

Aggregation and Native TraitsAggregation and Native Traits

' .Let s create a garage for our vehicles

package Garage;use Moose;use Moose::Util::TypeConstraints;

has 'vehicles' => ( 'isa'=> 'ArrayRef[ Vehicle ]', 'default' => sub {[]}, 'traits' => ['Array'], 'handles'=> { 'add_vehicle' => 'push', 'get_vehicle' => 'shift', },);

no Moose;1;

Trait .– a role added to attribute Here we make the vehicles attribute

.work as an array

.Defining accessors( ).these accessors use type checking

: Notice there is no' ' =>'is ro|rw'

:More native traits

: , , , , , , …Array push pop shift unshit map sort grep

: , , , , , , _ …Hash get set delete exists defined clear is empty

: , , ...String append substr length

: , , ...Bool set unset toggle

: , _ ...Code execute execute method

Page 44: Introduction to Moose

Aggregation and Native TraitsAggregation and Native Traits

' ...Let s park some vehicles

my $garage = Garage->new();

$garage->add_vehicle($avehicle);my $v = $garage->get_vehicle();

$garage->add_vehicle($acar);my $acar2 = $garage->get_vehicle();

$ 2acar and $acar is the same( )reference to the same object

Page 45: Introduction to Moose

What more you can do in Moose?What more you can do in Moose?

:For example

● - " " Delegation proxy methods call some other method on an

.attribute

● - Custom traits MooseX

● - Custom OO system – sub classing methaclasses

● ...And much more

Page 46: Introduction to Moose

Some tipsSome tips

● ' :If you don t know what is wrong try to load package from command line

perl -Ilib/ -e 'use Coordinate'

● $ -> object dump for debugging

Page 47: Introduction to Moose

More information:More information:

● :// . . / 2010/ / / /13673http www oscon com oscon public schedule detail : Moose is Perl A Guide to the New Revolution

● :// . . / / -527243http www slideshare net dtreder moose , .Awesome presentation with huge dose of humor but also very helpful

● :// . . /~ / -1.21/http search cpan org drolsky Moose :: ::Moose Manual and Moose Cookbook