Download - Moose workshop
Agenda
•Moose Overview
• Classes
• Roles
• Attributes
•Meta Object System
• Type System
•Moose Extensions
•Design Patterns
Friday, July 6, 12
Assumptions
• You know how to write a Moose classes
• You know how to define methods and what $self means
Friday, July 6, 12
Moose Overview
•Developed by Stevan Little (on the right)
• Started 2006
• Goal: Change the world
Friday, July 6, 12
Moose Features
• From perl to OO
•No boilerplate code
•Optional type constraints
• Inheritance and Mixins
•Design Patterns
Friday, July 6, 12
Organizations Using Moose
• Cisco
• IMDb
• Infinity Interactive
•MusicBrainz
• Symantec
• And others: http://moose.iinteractive.com/about.html#organizations
Friday, July 6, 12
Moose Alternatives
•Mouse
•Moo
•Mo
• Class::Builder
Friday, July 6, 12
Moose HELP
• IRC: irc://irc.perl.org/#moose
•Mailing List: mailto:[email protected]
• Youtube: search for “perl moose”
Friday, July 6, 12
Moose Classes
Friday, July 6, 12
Moose Classes
• Import sugar functions: extends, has, with, ...
• Enable strict & warnings
• Subclass of Moose::Object for default ctor and dtor
• Create Moose::Meta::Class object
package Foo;use Moose;
Friday, July 6, 12
Moose::Object
• new ( %params )
• BUILDARGS ( %params )
•DESTROY
• does( $role_name )
•DOES( $class_or_role_name )
• dump( $maxdepth )
Friday, July 6, 12
Example: Getting Info
package Pet;use Moose;
has 'name', is => 'ro', isa => 'Str', default => 'Lassy';has 'past_owners', is => 'ro', isa => 'ArrayRef[Str]';
package main;
my $dog = Pet->new( past_owners => ['James', 'Mike'] );
# show dog's info. No need to import Data::Dumperwarn $dog->dump;
# DOES returns true for objects of the class, subclasses or# implementors of the roleprint "Good boy" if $dog->DOES('Pet');
Friday, July 6, 12
Class Construction
• new method is automatically generated.
• Takes parameters hash or hash ref
package main;# Pass a hash ref to prevent copyingmy $enterprise = Starship->new( { captain => 'James T Kirk', crew => ['Dr. McCoy', 'Scott', 'Lt. Uhura'], });
Friday, July 6, 12
Class Construction
• Construction hooks:
• BUILD
• BUILDARGS
• attribute builders
Friday, July 6, 12
Class Construction
• BUILD is called every time a new object is created
• If inheritance is in effect, parent’s BUILD is called before child BUILD is called automatically
• Used for :
•Object state validation (whole object)
• Tracking objects creation
Friday, July 6, 12
Object State Validation
package Starship;use Moose;
has 'captain', is => 'ro', isa => 'Str', required => 1;has 'crew', is => 'rw', isa => 'ArrayRef[Str]', required => 1;
sub BUILD { my $self = shift; if ( $self->captain ~~ $self->crew ) { my $captain = $self->captain; die "Validation Error: Cannot use $captain for both Captain and Crew"; }}
package main;
# Validation errormy $enterprise = Starship->new( { captain => 'James T Kirk', crew => ['Dr. McCoy', 'Scott', 'Lt. Uhura', 'James T Kirk'], });
Friday, July 6, 12
BUILDARGS
• Used to manipulate arguments before object creation
• Takes the arguments hash as input, returns hashref
•Wrap in ‘around’ modifier to change
• Used for :
• Single arguments ctor
Friday, July 6, 12
BUILDARGS Examplepackage Person;use Moose;
has 'name', is => 'ro', isa => 'Str', required => 1;
around BUILDARGS => sub { my $orig = shift; my $class = shift; my @params = @_;
# Sole parameter that is not a ref # is considered the name if ( ( @params == 1 ) && ( ! ref $params[0] ) ) { return $class->$orig( name => $params[0] ); } else { return $class->$orig ( @params ); }}; # Watch the semicolon
Friday, July 6, 12
Class Destruction
•Moose implemented DESTROY, which will call your DEMOLISH
• It handles inheritance correctly: demolish child before super
Friday, July 6, 12
Class Destruction
•When program ends, prints out:
Bar ::DemolishFoo::Demolish
package Foo;use Moose;
sub DEMOLISH { warn 'Foo::Demolish' }
package Bar;use Moose;extends 'Foo';
sub DEMOLISH { warn 'Bar::Demolish' }
package main;
my $b = Bar->new;
Friday, July 6, 12
Construction Destruction
Do’s and Don’ts
Friday, July 6, 12
Do
• Provide reasonable validations with BUILD
Friday, July 6, 12
Do
• Use warn( $obj->dump ) for debug
Friday, July 6, 12
Do
• Consider namespace::autoclean to remove Moose sugar methods from your classes (has, with, etc.)
Friday, July 6, 12
Do
• Consider using:
__PACKAGE__->meta->make_immutable;
• To improve performance of objects creation
• Consider MooseX::AutoImmute
Friday, July 6, 12
Don’t
•Never override new ( it’ll break stuff down the road )
Friday, July 6, 12
Don’t
•Don’t use BUILD when attribute builders are sufficient
Friday, July 6, 12
Don’t
•Never call $self->SUPER::BUILD
•Moose does that for you
Friday, July 6, 12
Don’t
•Don’t apply a method modifier (before, after, around) to BUILD
Friday, July 6, 12
Don’t
•Don’t write BUILD method for your roles ( Moose ignores them )
Friday, July 6, 12
after
• Add code after a method is executed
• Receives: method name and subroutine to add
package Secret;use Mouse;
has 'message', is => 'ro', required => 1, clearer => 'reset';
has 'counter', is => 'rw', default => 3;
after 'message' => sub { my $self = shift; $self->counter( $self->counter - 1 ); if ( $self->counter <= 0 ) { $self->reset; }};
package main;my $secret = Secret->new( message => 'This message will self destroy');print $secret->message, "\n" for (1..5);
Friday, July 6, 12
What Is Printed ?
package Foo;use Moose;
sub DEMOLISH { warn 'Foo::Demolish' }sub BUILD { warn 'Foo::Build' }
package Bar;use Moose;extends 'Foo';
sub DEMOLISH { warn 'Bar::Demolish' }sub BUILD { warn 'Bar::Build' }
package main;
my $b = Bar->new;
Friday, July 6, 12
Method Modifiers
• Alter code by injecting other code before or after the modified method
• Can use from roles, subclasses or class itself
Friday, July 6, 12
before
• Before lets us inject code before a method is called
• Spot the bug on the right
package Logger;use Mouse;
sub log { my $self = shift; my ($msg) = @_;
print $msg;}
before 'log' => sub { select *STDERR };after 'log' => sub { select *STDOUT };
package main;my $log = Logger->new;$log->log("hello\n");
Friday, July 6, 12
around
• around has two more advantages:
• Can use return value of original method
• Can skip calling original method altogether
• You have the power
Friday, July 6, 12
around
• First parameter: original method as CODE ref
• Second parameter is the object
• Can call $self->$orig to get requested functionality
package AroundExample;use Mouse;use feature ':5.10';
sub foo { print "In Foo\n" }
around 'foo' => sub { my $orig = shift; my $self = shift;
say "Around: before calling method"; $self->$orig(@_); say "Around: after calling method";};
Friday, July 6, 12
around
• Forbid login before noon
package User;use Mouse;use DateTime;sub login { warn 'Welcome' }
around 'login' => sub { my $now = DateTime->now; if ( $now->hour < 12 ) { my $orig = shift; my $self = shift; $self->$orig(@_); }};
Friday, July 6, 12
Friday, July 6, 12
Moose RolesAn alternative to deep hierarchies and base classes
Friday, July 6, 12
Role
• Encapsulates behavior. Something that classes do
• Cannot be instansiated
• Classes consume roles - which means everything in the role is copied into the class
Friday, July 6, 12
Classes & Roles
Alive
Think Think
Alive
Person Computer Chicken
Friday, July 6, 12
Roles Example
package Glass;use Moose;
with 'Breakable';
package main;my $g = Glass->new;
$g->break;$g->fix;
package Breakable;use Moose::Role;
has 'is_broken', is => 'rw', isa => 'Bool';
sub break { my $self = shift; print "Ouch\n" if ! $self->is_broken; $self->is_broken(1);}
sub fix { my $self = shift; print "Works now\n" if $self->is_broken; $self->is_broken(0);}
Friday, July 6, 12
Moose Roles
• Use Moose::Role to define a role
• Use ‘with’ to consume a role
• Inside a role, define methods, attributes and modifiers
• Use ‘does’ to find out if an object implements a role
Friday, July 6, 12
Partial Implementation
• Use ‘requires’ in a role to force your consumer to define a method
• Useful for :
• Partial implementations (template method)
• Abstract Base Class
Friday, July 6, 12
Partial Implementationpackage MultipleFileUploader;use Moose::Role;
requires 'upload_file';
sub upload_files { my $self = shift;
my @success;
foreach my $f ( @_ ) { die "Invalid file: $f" if ! $f->DOES('File'); $self->upload_file ( $f ) && push @success, $f; }
return @success;}
Friday, July 6, 12
Method Conflicts
• Consuming two roles with the same method names results in a conflict
• Class must then implement the conflicted method on its own
• Can call role implementation using their namespace
Friday, July 6, 12
Method Conflicts
package R1;use Moose::Role;
sub foo { warn 'R1::foo'}
package R2;use Moose::Role;
sub foo { warn 'R2::foo'}
package Test;use Moose;
with qw/R1 R2/;
Compilation Error
Friday, July 6, 12
Method Conflict
• Can use -alias to make a copy of a role’s method by another name
• Can use -excludes to avoid consuming a specific method
• Combine both to work around a conflict
Friday, July 6, 12
Method Conflict
with 'Breakable' => { -alias => { break => 'break_bone' }, -excludes => 'break', },
'Breakdancer' => { -alias => { break => 'break_dance' }, -excludes => 'break', };
Friday, July 6, 12
Dynamic Roles
• Roles can be added to instances after creation
• Usage: debug tracing on specific obejct, dynamically change objects by configuration
• Code:
use Moose::Util qw( apply_all_roles );
my $car = Car->new; apply_all_roles( $car, 'Breakable' );
Friday, July 6, 12
Lab
• Implement a Comparable role which requires a single method: compare($other) - returns -1 if $other is greater than $self; 0 if they are equal and +1 if $self is greater.
• Use compare to implement the following: greater_than, greater_or_equal, less_than, less_or_equal
• Implement a class that consumes the role
Friday, July 6, 12
Friday, July 6, 12
Attributes
Friday, July 6, 12
Moose Attributes
• An attribute is a property that every member of a class has
• Some attributes are optional (e.g. some people have a middle name)
Friday, July 6, 12
Attribute Options
• is, reader, writer
• isa
• required, default, builder
• lazy
Friday, July 6, 12
Readers & Writers
• Use ‘is’ to auto generate reader/writer
• Use ‘writer’ to specify writer’s name
• Use ‘reader’ to specify reader’s name
package Product;use Moose;
has 'name' => ( is => 'rw', reader => 'get_name', writer => '_set_name',);
has 'price' => ( is => 'rw', reader => 'get_price', writer => 'set_price',);
Friday, July 6, 12
Isa
• Use isa to force a type constraint
• Available Types include: Bool, Str, Num, Int, ScalarRef, ArrayRef, HashRef, CodeRef
• Can use another object as type constraint
•Many more type constraints with option to extend the list yourself
Friday, July 6, 12
Isa
package Store;use Moose;use Client;use Product;
has 'owner', is => 'ro', isa => 'Str';
has 'clients', is => 'rw', isa => 'ArrayRef[Client]';has 'products', is => 'rw', isa => 'ArrayRef[Product]';
has 'revenue', is => 'rw', isa => 'Num';
1;
Friday, July 6, 12
Subtypes
• Use subtypes to easily define new constraints:
use Moose::Util::TypeConstraints;
subtype 'Age', as 'Int', where { $_ >= 0 && $_ <= 120 }, message { "Invalid Age: $_ "};
Friday, July 6, 12
Enumerations
• Use enum function to declare an enum subtype
• An enum takes a single value from a predefined list
enum 'EyeColor', [qw/green blue brown gray/];
Friday, July 6, 12
Required / Default / Builder
• Use required for fields that take their value from “outside”
• Use default / builder for everything else
Friday, July 6, 12
Builder
• Use builder for more complex initialization logic
• builder works better than default for inheritance
package Person;use Moose;
has 'pet', is => 'ro', builder => '_build_pet';
has 'age', is => 'rw', required => 1;
sub _build_pet { my $self = shift; if ( $self->age < 13 ) { return "None"; } else { return "Dog"; }}
package main;my $p = Person->new(age => 10);print $p->pet;
Friday, July 6, 12
lazy
• Create your attributes only when they are needed
• Use lazy_build to type less
package Person;use Moose;
has 'pet', is => 'ro', lazy_build => 1;has 'age', is => 'rw', required => 1;
sub _build_pet { my $self = shift; if ( $self->age < 13 ) { return "None"; } else { return "Dog"; }}
package main;my $p = Person->new(age => 10);print $p->pet;
Friday, July 6, 12
Dependency Injection
• A technique used in testing to build more testable versions of your classes
• If an attribute has both a builder AND was passed externally, external value wins
Friday, July 6, 12
Lab
• Implement a Logger class with one method: log. In the ctor, logger can take a file name
• If no arguments passed, create a screen logger (write all output to screen)
• If a file name was provided, write to that file
• Use dependency injection to test your Logger
Solution: https://gist.github.com/3029901
Friday, July 6, 12
Delegation
• A relationship between classes. A class attribute is an object of a different class
• Can then redirect all calls on containing object to the attribute - thus delegating specific methods
Friday, July 6, 12
Delegation
Contact EmailSend Mail Send Mail
Phone
CallCall
Friday, July 6, 12
Delegation
•Moose handles delegation for you
• Attribute should declare “handles” option
package Contact;use Moose;
has 'email' => ( is => 'ro', handles => [ qw/send_mail/ ]);
Friday, July 6, 12
Delegate
• Another option is to delegate an entire role
•Moose will delegate all methods in the role automatically
has 'uri' => ( is => 'ro', isa => 'URI', handles => 'HasURI',);
Friday, July 6, 12
Native Delegation
• Give your object “native” feel by using standard data type methods
• Currently supported: Array, Hash, Number, String, Bool, Counter
• Useful for : Fields that should “work like” the native data type
Friday, July 6, 12
Native Delegation
•Native arrays have push, pop, shift, unshift and more
• Can now use:$q->add_itemto add an item to the queue
has 'q' => ( is => 'ro', isa => 'ArrayRef[Int]', default => sub { [] }, traits => [qw/Array/], handles => { add_item => 'push', next_item => 'shift', },);
package main;my $q = Queue->new;$q->add_item(10, 20);
Friday, July 6, 12
Native Delegation
• Array functions: Moose::Meta::Attribute::Native::Trait::Array
•Hash functions:Moose::Meta::Attribute::Native::Trait::Hash
Friday, July 6, 12
Friday, July 6, 12
Attributes: Advanced Topics
• Predicates & Clearers
• Constructor Parameters
•Weak References
• Triggers
Friday, July 6, 12
Predicates & Clearers
• User can upload photos, other users can “like”
• Every photo starts with 0 likes
• How many “likes” do you have before the image is online ?
Uploading ImageNo likes yet
Image Online0 Likes.
Go find more friends
Friday, July 6, 12
Predicates & Clearers
• Provide two new methods on $self: unpublish and is_published
• Setting value to undef does not affect predicate
package Photo;use Moose;
has 'likes' => ( is => 'rw', clearer => 'unpublish', predicate => 'is_published',);
sub publish { my $self = shift; $self->likes ( 0 );}
Friday, July 6, 12
Predicates & Clearers
sub like { my $self = shift;
die 'Cannot like an Unpublished photo' if ! $self->is_published;
$self->likes ( $self->likes + 1 );}
Friday, July 6, 12
Constructor Parameters
• Sometimes the name of the attribute is not the same as the name of the constructor param
• A possible workaround is BUILDARGS, but that’s too tedious
• A better way: Use init_arg
• Usage: modify constructor param name, prevent dependency injection
Friday, July 6, 12
Example: init_arg
• Use to modify constructor parameter name
• Attribute name is size, while object creation is performed with:Cls->new( bigness => 7 )
has 'bigness' => ( is => 'ro', init_arg => 'size', );
Friday, July 6, 12
Example: init_arg
• Use init_arg => undef to prevent dependency injection
• Use with caution
has '_genetic_code' => ( is => 'ro', lazy_build => 1, init_arg => undef, );
Friday, July 6, 12
Weak References
Course
Student Student Student
Learns At
Friday, July 6, 12
Weak References
•When an object leaves scope, it’s ref-count decreases
• Circular references cause objects to remain in memory
•Weak references to the rescue
Friday, July 6, 12
Weak Ref
•When a Course object leaves the last scope - it will now be deleted
•When Course object leaves scope, Moose will automatically clear all “learns_at” attributes of students
package Student;use Moose;has 'name', is => 'ro', required => 1;
has 'learns_at', is => 'rw', weak_ref => 1;
Full Example: https://gist.github.com/3031636Friday, July 6, 12
Triggers
• Called when attribute value is set
• Called when set from new or explicitly
• Is not called when set from default or builder
has 'size' => ( is => 'rw', trigger => \&_size_set,);
sub _size_set { my ( $self, $size, $old_size ) = @_;}
Friday, July 6, 12
Friday, July 6, 12
Lab
• Improve Students/Course example to use native delegation
• Use method modifiers to add custom logic
Friday, July 6, 12
Meta Moose
Friday, July 6, 12
What is MOP
• An abstraction to build abstractions - or simply put - an API to build an object system
•Moose is one object system built upon Class::MOP
• Understanding Class::MOP and Moose’s use of it reveals new features in Moose
Friday, July 6, 12
MOP Parts
• The Class protocol
• The Attribute protocol
• The Method protocol
• The Instance protocol
Friday, July 6, 12
Moose and Class::MOP
•Moose is built on top of Class::MOP
• Prefixed Moose::Meta (for example Moose::Meta::Class)
• Get with $self->meta
Friday, July 6, 12
What Meta Can Do For You
• Class and Object Introspection
•Modify objects and classes dynamically (add/remove methods, attributes, roles)
• Add more information to attributes (label, persistent)
Friday, July 6, 12
Object Introspection
package main;
my $z = Zombie->new;
for my $attr ( $z->meta->get_all_attributes ) { say $attr->name;}
for my $method ( $z->meta->get_all_methods ) { say $method->fully_qualified_name;}
if ( $z->meta->has_method( 'eat_brain' ) ) { $z->eat_brain;}
Full Source: https://gist.github.com/3032056Friday, July 6, 12
Object Introspection
• All meta methods listed under:
Class::MOP::Class and Moose::META::Class
• In most cases, using roles is a better idea than dynamic checking
Friday, July 6, 12
Validate Type Constraints
• Use $self->meta->get_attribtue(attr)->type_constraint to get meta object of type constraints
• $constraint->check( $value )
• $constraint->validate( $value ) or die $constraint->get_message( $value );
• $constraint->assert_valid( $value )
Friday, July 6, 12
Class Modification
• $meta->add_attribute
• $meta->remove_attribute
• $meta->add_method
• $meta->remove_method
• $meta->make_immutable
Friday, July 6, 12
Moose::Util
• A bundle of useful functions that take away some of the pain of working with meta
• Start here before implementing your own.
Friday, July 6, 12
Moose::Util
• find_meta( $class_or_obj )
• does_role( $class_or_obj, $role )
• apply_all_roles( $applicant, @roles )
• english_list( @items )
Friday, July 6, 12
Friday, July 6, 12
Moose TypesCustomizable Type System
Friday, July 6, 12
Moose Type System
• Verify attribute values are “valid” - of a certain type
• Types have names, so they can be reused
• Type checking is just sugar for method arguments validation. Perl does not associate types with variables
• Earlier error detection
Friday, July 6, 12
Stock Types
• Bool, Maybe[‘a], Str, Num, Int, ClassName, RoleName
• Ref, ScalarRef[‘a], ArrayRef[‘a], HashRef[‘a], CodeRef
• RegexpRef, GlobRef, FileHandle
•Object
Friday, July 6, 12
Type Registry
• A type is an instance of Moose::Meta::TypeConstraint
• All types are stored in the type registry. Use get_type_constraint_registry from Moose::Util::TypeConstraints to get it
Friday, July 6, 12
Example: Print All Constraints
use v5.14;use Data::Dumper;use Moose::Util::TypeConstraints;
my $registry = Moose::Util::TypeConstraints::get_type_constraint_registry();
print Dumper($registry->type_constraints);
Friday, July 6, 12
Extending The Type System
• Every Moose object is a new type
• There are also helper methods to create new types
• A new type can be named or anonymous
Friday, July 6, 12
Named Subtypes: enum
use v5.14;
package Person::Types;use Moose::Util::TypeConstraints;
enum 'Person::Types::EyeColor', [qw/gray brown green blue/];
package Person;use Moose;use Moose::Util::TypeConstraints;
has 'eyecolor' => ( is => 'ro', isa => 'Person::Types::EyeColor',);
Friday, July 6, 12
Anonymous Subtypes: enum
use v5.14;
package Person;use Moose;use Moose::Util::TypeConstraints;
has 'eyecolor' => ( is => 'ro', isa => enum [qw/gray blue brown green/],);
Friday, July 6, 12
More Subtypes
• subtype( %opts ) - Create a new subtype
• role_type ‘barks’, { role => ‘Some::Library::Role::Barks’ }
• union ‘UnionName’, [qw/Str ArrayRef/]; - Create a new subtype that can hold either string or an array
Friday, July 6, 12
Subtypes
• Provide ‘as’ to specify base type
• Provide ‘where’ to add constraint on the base type
• Provide your own error message with ‘message’
subtype 'NaturalLessThanTen', as 'Natural', where { $_ < 10 }, message { "This number ($_) is not less than ten!" };
Friday, July 6, 12
Subtypes Do’s
•Define all your subtype in a single module for code reuse. Use that module from every Moose class
Friday, July 6, 12
Subtypes Do’s
• Prefer namespaced subtypes: ZombieApocalipse::Human::EyeColor is better thanEyeColor
• Zombies may have different eye color ...
Friday, July 6, 12
Type CoercionProceed With Caution
Friday, July 6, 12
Type Coercion
• Automatically convert invalid data to valid
• Int ------> ArrayRef[Int]
• Str ------> Person
• High risk - an invalid value could coerce thus skipping type validation
Friday, July 6, 12
Type Coercion
use v5.14;
package Student;use Moose;use Moose::Util::TypeConstraints;
subtype 'GradesArray', as 'ArrayRef[Int]';coerce 'GradesArray', from 'Int', via { [ $_ ] };
has 'grades', is => 'ro', isa => 'GradesArray', coerce => 1;
package main;my $s = Student->new( grades => 77 );
print $s->dump;
Friday, July 6, 12
Coercion Don’ts
•Don’t add coercion on Moose’s subtypes (unfortunately it’ll work)
• Generally, try to avoid coercions
Friday, July 6, 12
Friday, July 6, 12
Subtypes Lab
•Define a new subtype for hex numbers (numbers of the format 0x22)
• Add a coercion from HexNum to Int
Friday, July 6, 12
MooseXMore Than Moose
Friday, July 6, 12
eXtending Moose
•Moose is (relatively) easy to change and extend
•Writing extensions can take some time and effort BUT
• There are tons of Moose Extensions on CPAN
• Prefixed MooseX, they provide extra or modified functionality
Friday, July 6, 12
Useful MooseX
•MooseX::StrictConstructor
•MooseX::Singleton
•MooseX::Declare
•MooseX::FollowPBP
•MooseX::Privacy
•MooseX::SingleArg
•MooseX::MultiMethods
•MooseX::HasDefaults
•MooseX::APIRole
Friday, July 6, 12
Simple eXtensions
•MooseX::StrictConstructor
•MooseX::Singleton
•MooseX::FollowPBP
•MooseX::SingleArg
•MooseX::HasDefaults
•MooseX::Privacy
Friday, July 6, 12
MooseX::StrictConstructor
• Throw exception if constructor was passed an unexpected argument
package Contact;use Moose;use MooseX::StrictConstructor;
has 'email', is => 'ro';has 'name', is => 'ro';
package main;
# Throw an exceptionContact->new( name => 'Bob', emial => '[email protected]');
Friday, July 6, 12
MooseX::Singleton
• Create only one instance of a class
• Has initialization method to pass arguments if needed
package App;use MooseX::Singleton;
package main;
{ my $app = App->instance;}
{ # same one my $app = App->instance;}
Friday, July 6, 12
MooseX::FollowPBP
• Use set_x and get_x as default reader and writer
• SEE ALSO: Perl::Critic
Friday, July 6, 12
MooseX::SingleArg
• Easily create single arg constructor (without wrapping BUILDARGS)
use v5.14;
package Contact;use Moose;use MooseX::SingleArg;
single_arg 'name';has 'name', is => 'ro';
package main;my $c = Contact->new('Mike');
say $c->name;
Friday, July 6, 12
MooseX::HasDefaults
• Automatically use:
is => ‘ro’
or :
is => ‘rw’
use v5.14;
package Point;use Moose;use MooseX::HasDefaults::RO;
has ['x', 'y', 'z'];
Friday, July 6, 12
MooseX::Privacy
• Restrict visibility of methods
• private can only be called from within the class
• protected can only be called from within the class or any of its subclasses
•Doesn’t work for roles
use MooseX::Privacy; has config => ( is => 'rw', isa => 'Some::Config', traits => [qw/Private/],); private_method foo => sub { return 23;}; protected_method bar => sub { return 42;};
Friday, July 6, 12
Heavy Lifting
• Logging: Log4perl
•MooseX::APIRole
•MooseX::Declare
•MooseX::MultiMethods
Friday, July 6, 12
Log4perl
• Logging is all about keeping a record of your info at runtime
• Log4perl lets you control how your application logs its data
• Perl’s implementation of log4j
Friday, July 6, 12
Log4perl alternatives
• print/warn debug messages: Too simple for real apps
• roll-your-own: Too much work...
• Log4perl is currently the best logging solution for medium-large perl applications
Friday, July 6, 12
Log4perl and Moose
• Use MooseX::Log::Log4perl role in your class
•New attributes: log and logger
package MyApp;use Moose;
with 'MooseX::Log::Log4perl';
sub go { my $self = shift;
$self->log->debug('Starting method go'); $self->log->info('Go go go');
$self->log('IO')->info('reading data');}
Friday, July 6, 12
Log4perl Output
• Completely customizable
•Output log to: Screen, File, Socket, DBI, and more
• Example:
[2012/07/06 14:54:34] 130.pl MyApp::go 130.pl (9) MyApp - Starting method go[2012/07/06 14:54:34] 130.pl MyApp::go 130.pl (10) MyApp - Go go go[2012/07/06 14:54:34] 130.pl MyApp::go 130.pl (12) IO - reading data
Friday, July 6, 12
Log4perl Configuration
log4perl.logger = DEBUG, Screen, Logfile
log4perl.appender.Screen = Log::Log4perl::Appender::Screenlog4perl.appender.Screen.layout = PatternLayoutlog4perl.appender.Screen.layout.ConversionPattern= \ [%r] %F %l %c - %m%n
log4perl.appender.Logfile = Log::Log4perl::Appender::Filelog4perl.appender.Logfile.filename = my.loglog4perl.appender.Logfile.layout = PatternLayoutlog4perl.appender.Logfile.layout.ConversionPattern = \ [%d] %F %l %c - %m%n
Friday, July 6, 12
Log4perl Initialization
• Load configuration file on startup with: Log::Log4perl::init(filename)
package main;use Log::Log4perl;
Log::Log4perl::init('log.conf');
Friday, July 6, 12
Log4perl Docs
• Usage: perldoc Log::Log4perl
• Conversion Patterns Layout:http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html
Friday, July 6, 12
MooseX::APIRole
• Automatically create a role out of a class
• all subroutines become ‘requires’
• Easy to use and very powerful
package Logger;use Moose;use MooseX::APIRole;
sub info { }sub error { }
make_api_role 'Logger::API';
package Test;use Moose;# Fails - Test does not implement# required methodswith 'Logger::API';
Friday, July 6, 12
MooseX::Declare
• Use modern OO syntax for your moose objects
• ‘class’ keywords declares a class. Inside, MooseX::Method::Signatures is in effect.
• ‘role’ keyword declares a role
Friday, July 6, 12
MooseX::Declare
use MooseX::Declare;
class BankAccount { has 'balance' => ( isa => 'Num', is => 'rw', default => 0 );
method deposit (Num $amount) { $self−>balance( $self−>balance + $amount ); }
method withdraw (Num $amount) { my $current_balance = $self−>balance(); ( $current_balance >= $amount ) || confess "Account overdrawn"; $self−>balance( $current_balance − $amount ); }}
Friday, July 6, 12
MooseX::Declare
• Still experimental, API could change
• Inside a method $self is already defined for you, as well as other input parameters
• Awesome. perldoc MooseX::Declare for more
Friday, July 6, 12
MooseX::MultiMethods
• Allow multi methods dispatcher based on input arguments
•Define multiple handlers instead of long if-else blocks
Friday, July 6, 12
MooseX::MultiMethods
package Paper; use Moose;package Scissors; use Moose;package Rock; use Moose;
package Game;use Moose;use MooseX::MultiMethods;
multi method play (Paper $x, Rock $y) { 1 }multi method play (Scissors $x, Paper $y) { 1 }multi method play (Rock $x, Scissors $y) { 1 }multi method play (Any $x, Any $y) { 0 }
my $game = Game->new;
# 1, Paper covers Rockprint $game->play(Paper->new, Rock->new);
Friday, July 6, 12
Friday, July 6, 12
Thanks For Listening
• Ynon Perek
• ynonperek.com
Friday, July 6, 12