Introduction To Moose
Upcoming SlideShare
Loading in...5
×
 

Introduction To Moose

on

  • 9,083 views

Introduction to Moose talk given at Italian Perl Workshop 2009.

Introduction to Moose talk given at Italian Perl Workshop 2009.

Video at http://www.shadowcat.co.uk/archive/conference-video/ipw-2009/moose/

Statistics

Views

Total Views
9,083
Views on SlideShare
9,007
Embed Views
76

Actions

Likes
12
Downloads
256
Comments
1

2 Embeds 76

http://www.slideshare.net 59
http://docs.intra.mixi.co.jp 17

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

11 of 1

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • This looks good. The only problem is the downloading. The downloaded file is in .key format, which I have no way to view it in Windows. Any other formats?
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Introduction To Moose Introduction To Moose Presentation Transcript

  • Introduction to Moose Italian Perl Workshop 2009 Mike Whitaker - BBC / EnlightenedPerl.org
  • About me
  • About me • BBC iPlayer team
  • About me • BBC iPlayer team • ex-Yahoo Europe (News team)
  • About me • BBC iPlayer team • ex-Yahoo Europe (News team) • ex-CricInfo.com
  • About me • BBC iPlayer team • ex-Yahoo Europe (News team) • ex-CricInfo.com • Board member of EnlightenedPerl.org
  • Why Moose?
  • Why Moose? • For that, we need a bit of history:
  • In the Beginning...
  • In the Beginning... • ...there was Perl 5
  • In the Beginning... • ...there was Perl 5 • DIY OO
  • In the Beginning... • ...there was Perl 5 • DIY OO • perldoc perltoot
  • In the Beginning... • ...there was Perl 5 • DIY OO • perldoc perltoot package Foo; sub new { my $self = {}; return bless $self; }
  • In the Beginning... package Foo; • ...there was Perl 5 sub new { my $self = {}; • DIY OO } return bless $self; • perldoc perltoot sub bar { my $self = shift; my $val = shift; package Foo; if (defined $val) { $self->{bar} = $val; sub new { } my $self = {}; else { return bless $self; return $self->{bar}; } } }
  • Perl 5 Native OO
  • Perl 5 Native OO • A bit of a hack
  • Perl 5 Native OO • A bit of a hack • Not really a first-class part of the language
  • Perl 5 Native OO • A bit of a hack • Not really a first-class part of the language • Have to roll your own
  • So... People started writing classes to make it easier....
  • Class::Accessor::Classy Class::Accessor Object::InsideOut fields Hash::FieldHash Badger::Class Rubyish OP Object::Declare Class::Maker UR Class::Gomor Object::Tiny::XS Class::XSAccessor Class::Framework Class::Accessor::Fast Class::Simple Rose::Object MOP::MOP Coat Object::InsideOut Class::STD Class::Object Class::Base Class::ArrayObjects Spiffy Class::Accessor::Grouped Class::Frame Object::Accessor Object::Tiny Object::Simple Class::Generate Class::Builder accessors Fukurama::Class Class::Define Abstract::Meta::Class
  • Moose
  • What is Moose?
  • What is Moose? • (Post)modern Perl OO framework
  • What is Moose? • (Post)modern Perl OO framework • Deals with the overhead of implementing OO, allows you to get on with coding
  • What is Moose? • (Post)modern Perl OO framework • Deals with the overhead of implementing OO, allows you to get on with coding • Meta-object implementation - allows you to introspect your classes and objects
  • What is Moose? • (Post)modern Perl OO framework • Deals with the overhead of implementing OO, allows you to get on with coding • Meta-object implementation - allows you to introspect your classes and objects • Already used in production software
  • My First Class package Person; use Moose; has name => ( is => 'rw', ); no Moose;
  • Using the class use Person; my $person = Person->new(); $person->name('Mike'); print $person->name(); > Mike
  • Adding a method package Person; use Moose; has name => ( is => 'rw' ); sub introduce { print "I'm " . $self->name; }
  • Using it use Person; my $person = Person->new(); $person->name('Mike'); $person->introduce(); > I'm Mike
  • Read-only attributes package Person; use Moose; has name => ( is => 'ro' ); sub introduce { print "I'm " . $self->name; }
  • Read-only attributes (2) use Person; my $person = Person->new(); $person->name('Mike'); # boom!
  • Read-only attributes (3) use Person; my $person = Person->new( { name => 'Mike' }, ); # no boom today!
  • Changing defaults has 'name' => ( isa => 'Str', reader => 'get_name', writer => 'set_name', init_arg => 'name', required => 1, );
  • Types package Person; use Moose; has name => ( is => 'rw', isa => 'Str', );
  • Types (2) use Person; my $person = Person->new(); $person->name('Mike'); # shiny! $person->name( [] ); # boom! # Not a Str
  • Types (3) package Person; use Moose; has name => ( is => 'rw', isa => 'Str' ); has dob => ( is => 'rw', isa => 'DateTime', );
  • Types (4) use Person; my $person = Person->new( { name => 'Mike' } ); my $dob = DateTime->new ( year => 1963, month => 8, day => 5, ); $person->dob($dob); print $person->dob->year; > 1963
  • Subclassing package Student; use Moose; extends qw/Person/; has overdraft => ( isa => 'Bool', is => 'rw', );
  • Compound Types package Student; use Moose; extends qw/Person/; has classes => ( isa => 'HashRef[Str]', is => 'rw', );
  • Required attributes package Student; use Moose; extends qw/Person/; # ... has course => ( isa => 'Str', is => 'ro', required => 1, );
  • Setting defaults package Student; use Moose; has 'overdraft' => ( isa => 'Bool', default => 1, );
  • But, what if... package BankAccount; sub balance { # yadda yadda }
  • And then... package Student; use Moose; extends qw/Person/; has 'account' => ( isa => 'BankAccount', is => 'rw', required => 1, );
  • Lazy default has 'overdraft' => ( isa => 'Bool', is => 'ro', lazy => 1, default => sub { shift->account->balance < 0; } );
  • Lazy builder has 'overdraft' => ( isa => 'Bool', is => 'ro', lazy_build => 1, init_arg => undef, ); sub _build_overdraft { return shift->account->balance < 0; }
  • Method modifiers package Student; # yadda yadda after 'introduce' => sub { my $self = shift; print ', studying ' . $self->course; }
  • Using it use Student; my $person = Student->new( name => 'Mike', course => 'Computer Science', ); $person->introduce(); > I'm Mike, studying Computer Science
  • Method modifiers (2) package Student; # yadda yadda around 'introduce' => sub { my ($next, $self, @args) = @_; print "Hi, "; $self->$next(@args); print ', studying ' . $self->course; }
  • Using around use Student; my $person = Student->new( name => 'Mike', course => 'Computer Science', ); $person->introduce(); > Hi, I'm Mike, studying Computer Science
  • Roles
  • Roles • Code fragments that define and provide a small, reusable behaviour
  • Roles • Code fragments that define and provide a small, reusable behaviour • Not inherited - methods become part of consuming class
  • Roles • Code fragments that define and provide a small, reusable behaviour • Not inherited - methods become part of consuming class • can be overriden by comsuming class
  • Roles • Code fragments that define and provide a small, reusable behaviour • Not inherited - methods become part of consuming class • can be overriden by comsuming class • like MI but better!
  • Example role package Age; use Moose::Role; has dob => ( isa => 'DateTime', is =>'ro' ); sub age { return DateTime->now ->subtract( shift->dob() ) ->years; }
  • Using a role package Person; use Moose; with qw/Age/; has name => ( isa => 'Str', is => 'ro'); sub introduce { print "I'm " . $self->name . ', age ' . $self->age; }
  • Using a role (2) use Student; my $person = Student->new( name => 'Mike', dob => ... # yadda yadda course => 'CS', ); $person->introduce(); > Hi, I'm Mike, age 45, studying CS
  • What we'd really like use Student; my $person = Student->new( name => 'Mike', dob => '05-08-1963', course => 'CS', );
  • Redefine our attr... package Age; use Moose::Role; has dob => ( isa => 'DateStr', is =>'ro', );
  • Types to the rescue use Moose::Util::TypeConstraints; subtype 'DateStr' => as 'Str' => where { /^dd-dd-dddd$/ };
  • Types to the rescue (2) use Moose::Util::TypeConstraints; class_type 'DateTime'; coerce 'DateTime' => from 'Str' => via { my ($d, $m, $y) = split /-/, $_; return DateTime->new( year => $y, month => $m, day => $d ); };
  • And then... package Age; use Moose::Role; has dob => ( isa => 'DateTime', is =>'ro', coerce => 1, # very important! );
  • Et voila... use Student; my $person = Student->new( name => 'Mike', dob => '05-08-1963', course => 'CS', ); print $person->age(); > 45
  • Roles as interfaces package Earnings; use Moose::Role; requires qw/annual_income/; sub monthly_income { return shift->annual_income / 12; }
  • Roles as interfaces (2) package Person; with qw/Earnings/; package Student; extends qw/Person/; sub annual_income { my $self = shift; return $self->grant_amount; }
  • Role gotchas
  • Role gotchas • Roles cannot use extends
  • Role gotchas • Roles cannot use extends • requires only works with actual methods :(
  • Role gotchas • Roles cannot use extends • requires only works with actual methods :( • for now, at least
  • Role gotchas • Roles cannot use extends • requires only works with actual methods :( • for now, at least • watch out for method and attribute conflicts
  • Method Delegation package Degree; use Moose; use Moose::Utils::TypeConstraints; enum 'Grade' => qw/I IIi IIii III/; has 'grade' => ( isa => 'Grade' ); has 'awarded' => ( isa => 'DateTime', coerce => 1, );
  • Method Delegation (2) package Graduate; use Moose; extends qw/Student/; has 'degree' => ( isa => 'Degree', is => 'rw', );
  • Method Delegation (3) my $g = Graduate->new(name => 'Mike'); my $d = Degree->new( awarded => '06-06-1985', grade => 'IIii', ); $g->degree($d); print $g->degree->awarded->year; > 1985
  • Method Delegation (4) has 'degree' => ( isa => 'Degree', is => 'rw', handles => { graduated => 'awarded' }, );
  • Method Delegation (5) my $g = Graduate->new(name => 'Mike'); my $d = Degree->new( awarded => '06-06-1985', grade => 'IIii', ); $g->degree($d); print $g->graduated->year; > 1985
  • More on attributes package Student; use MooseX::Util::TypeConstraints; use Moose; extends qw/Person/; enum 'Result' => qw/pass fail/; has classes => ( isa => 'HashRef[Result]', is => 'rw', predicate => 'has_classes', );
  • Attribute Helpers my $st = Student->new( name => 'Mike' ); $st->classes( { "Compilers" => 'fail', "Numerical Methods" => 'pass' } ); %{$st->classes}->{"Lisp"} = "pass";
  • Attribute Helpers (2) use MooseX::AttributeHelpers; has classes => ( metaclass => 'Collection::Hash', isa => 'HashRef[Result]', is => 'rw', provides => { set => 'add_class', keys => 'list_classes', } )
  • Attribute Helpers (3) my $st = Student->new( name => 'Mike' ); $st->classes( { "Compilers" => 'fail', "Numerical Methods" => 'pass' } ); $st->add_class("Lisp" => 'pass'); print join ", ", $st->list_classes(); > Compilers, Numerical Methods, Lisp
  • Introspecting Moose
  • Introspecting Moose • my $metaclass = $self->meta;
  • Introspecting Moose • my $metaclass = $self->meta;
  • Introspecting Moose • my $metaclass = $self->meta; • $metaclass->superclasses;
  • Introspecting Moose • my $metaclass = $self->meta; • $metaclass->superclasses; • $metaclass->linearized_isa;
  • Introspecting Moose • my $metaclass = $self->meta; • $metaclass->superclasses; • $metaclass->linearized_isa; • $metaclass->has_method("foo");
  • Introspecting Moose • my $metaclass = $self->meta; • $metaclass->superclasses; • $metaclass->linearized_isa; • $metaclass->has_method("foo"); • $metaclass->get_all_attributes;
  • Method Signatures
  • Method Signatures • We have types...
  • Method Signatures • We have types... • Wouldn't it be nice if types weren't restricted to attrs + accessors?
  • Method Signatures • We have types... • Wouldn't it be nice if types weren't restricted to attrs + accessors? • Enter: MooseX::Method::Signature
  • Method Signatures package Student; use Moose; use MooseX::Method::Signatures; method attend (Str $class, DateTime $time) { # ... }
  • Method Signatures (2) method attend (Str $class, DateTime $time) { if (grep $class, $self->list_classes) { $self->schedule($time, $class); } }
  • Even more Java-like? use MooseX::Declare; class Student extends Person with Earnings { has 'id' => ( isa => 'StudentID' ); method attend ( Str $class, ... ) { # yadda yadda } }
  • How is this implemented?
  • Lasciate ogne speranza, voi ch'intrate
  • But seriously...
  • But seriously... • Devel::Declare sticks the interpreter on pause while it plays with your source
  • But seriously... • Devel::Declare sticks the interpreter on pause while it plays with your source • NOT a source filter
  • But seriously... • Devel::Declare sticks the interpreter on pause while it plays with your source • NOT a source filter • You don't need to know what's going on...
  • Why Moose?
  • Why Moose? • Less code = fewer errors
  • Why Moose? • Less code = fewer errors • Don't waste time on class implementation
  • Why Moose? • Less code = fewer errors • Don't waste time on class implementation • Better object model
  • Why Moose? • Less code = fewer errors • Don't waste time on class implementation • Better object model • "We do this so you don't have to"
  • Why Moose? • Less code = fewer errors • Don't waste time on class implementation • Better object model • "We do this so you don't have to" • Less need for low level tests
  • Why Moose? • Less code = fewer errors • Don't waste time on class implementation • Better object model • "We do this so you don't have to" • Less need for low level tests • More descriptive code
  • Further Reading
  • Further Reading • http://iinteractive.com/moose/
  • Further Reading • http://iinteractive.com/moose/ • Moose::Cookbook (CPAN)
  • Further Reading • http://iinteractive.com/moose/ • Moose::Cookbook (CPAN) • http://www.stonehenge.com/merlyn/ LinuxMag/col94.html
  • Complex Example package Student; use Moose; # yadda has 'id' => ( isa => 'StudentID', is => 'rw', );
  • Complex Example (2) use MooseX::ClassAttribute; class_has 'db' => ( isa => 'Str', is => 'rw', default => 'dbi:SQLite:dbname=s.db' ); class_has _schema => ( isa => 'Person::Schema', lazy_build => 1, is => 'ro', );
  • Complex Example (3) sub _build__schema { my $self = shift; return Person::Schema->connect( $self->db ); }
  • Complex Example (4) use Config::General; override BUILDARGS => sub { my $args = super; my %conf = Config::General ->new( 'db.conf' )->getall(); $args->{db} = $conf{db} if exists $conf{db}; };
  • Complex Example (5) has _row => { isa => 'DBIx::Class::Row', lazy_build => 1, } sub _build__row { return shift->_schema ->resultset('Student') ->find($self->id); }
  • Complex Example (6) has _row => { isa => 'DBIx::Class::Row', lazy_build => 1, handles => [qw/address gender/], }
  • Complex Example (7) my $student = Student->new( name => 'Mike', id => '3056', ); print $st->address(); # What happens here?
  • What happens?
  • What happens? • address method is handled by _row
  • What happens? • address method is handled by _row • _row is lazy_build, so calls _build__row
  • What happens? • address method is handled by _row • _row is lazy_build, so calls _build__row • which requires _schema, ALSO lazy_build
  • What happens? • address method is handled by _row • _row is lazy_build, so calls _build__row • which requires _schema, ALSO lazy_build • which uses id to find the right row in db
  • What happens? • address method is handled by _row • _row is lazy_build, so calls _build__row • which requires _schema, ALSO lazy_build • which uses id to find the right row in db • Tadaa!
  • But... # What if the student's ID changes? has 'id' => ( isa => 'StudentID', is => 'rw', trigger => '_build__row', );