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

Introduction To Moose

  • 7,233 views
Uploaded on

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/

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
  • 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
No Downloads

Views

Total Views
7,233
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
267
Comments
1
Likes
13

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Introduction to Moose Italian Perl Workshop 2009 Mike Whitaker - BBC / EnlightenedPerl.org
  • 2. About me
  • 3. About me • BBC iPlayer team
  • 4. About me • BBC iPlayer team • ex-Yahoo Europe (News team)
  • 5. About me • BBC iPlayer team • ex-Yahoo Europe (News team) • ex-CricInfo.com
  • 6. About me • BBC iPlayer team • ex-Yahoo Europe (News team) • ex-CricInfo.com • Board member of EnlightenedPerl.org
  • 7. Why Moose?
  • 8. Why Moose? • For that, we need a bit of history:
  • 9. In the Beginning...
  • 10. In the Beginning... • ...there was Perl 5
  • 11. In the Beginning... • ...there was Perl 5 • DIY OO
  • 12. In the Beginning... • ...there was Perl 5 • DIY OO • perldoc perltoot
  • 13. In the Beginning... • ...there was Perl 5 • DIY OO • perldoc perltoot package Foo; sub new { my $self = {}; return bless $self; }
  • 14. 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}; } } }
  • 15. Perl 5 Native OO
  • 16. Perl 5 Native OO • A bit of a hack
  • 17. Perl 5 Native OO • A bit of a hack • Not really a first-class part of the language
  • 18. Perl 5 Native OO • A bit of a hack • Not really a first-class part of the language • Have to roll your own
  • 19. So... People started writing classes to make it easier....
  • 20. 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
  • 21. Moose
  • 22. What is Moose?
  • 23. What is Moose? • (Post)modern Perl OO framework
  • 24. What is Moose? • (Post)modern Perl OO framework • Deals with the overhead of implementing OO, allows you to get on with coding
  • 25. 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
  • 26. 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
  • 27. My First Class package Person; use Moose; has name => ( is => 'rw', ); no Moose;
  • 28. Using the class use Person; my $person = Person->new(); $person->name('Mike'); print $person->name(); > Mike
  • 29. Adding a method package Person; use Moose; has name => ( is => 'rw' ); sub introduce { print "I'm " . $self->name; }
  • 30. Using it use Person; my $person = Person->new(); $person->name('Mike'); $person->introduce(); > I'm Mike
  • 31. Read-only attributes package Person; use Moose; has name => ( is => 'ro' ); sub introduce { print "I'm " . $self->name; }
  • 32. Read-only attributes (2) use Person; my $person = Person->new(); $person->name('Mike'); # boom!
  • 33. Read-only attributes (3) use Person; my $person = Person->new( { name => 'Mike' }, ); # no boom today!
  • 34. Changing defaults has 'name' => ( isa => 'Str', reader => 'get_name', writer => 'set_name', init_arg => 'name', required => 1, );
  • 35. Types package Person; use Moose; has name => ( is => 'rw', isa => 'Str', );
  • 36. Types (2) use Person; my $person = Person->new(); $person->name('Mike'); # shiny! $person->name( [] ); # boom! # Not a Str
  • 37. Types (3) package Person; use Moose; has name => ( is => 'rw', isa => 'Str' ); has dob => ( is => 'rw', isa => 'DateTime', );
  • 38. 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
  • 39. Subclassing package Student; use Moose; extends qw/Person/; has overdraft => ( isa => 'Bool', is => 'rw', );
  • 40. Compound Types package Student; use Moose; extends qw/Person/; has classes => ( isa => 'HashRef[Str]', is => 'rw', );
  • 41. Required attributes package Student; use Moose; extends qw/Person/; # ... has course => ( isa => 'Str', is => 'ro', required => 1, );
  • 42. Setting defaults package Student; use Moose; has 'overdraft' => ( isa => 'Bool', default => 1, );
  • 43. But, what if... package BankAccount; sub balance { # yadda yadda }
  • 44. And then... package Student; use Moose; extends qw/Person/; has 'account' => ( isa => 'BankAccount', is => 'rw', required => 1, );
  • 45. Lazy default has 'overdraft' => ( isa => 'Bool', is => 'ro', lazy => 1, default => sub { shift->account->balance < 0; } );
  • 46. Lazy builder has 'overdraft' => ( isa => 'Bool', is => 'ro', lazy_build => 1, init_arg => undef, ); sub _build_overdraft { return shift->account->balance < 0; }
  • 47. Method modifiers package Student; # yadda yadda after 'introduce' => sub { my $self = shift; print ', studying ' . $self->course; }
  • 48. Using it use Student; my $person = Student->new( name => 'Mike', course => 'Computer Science', ); $person->introduce(); > I'm Mike, studying Computer Science
  • 49. Method modifiers (2) package Student; # yadda yadda around 'introduce' => sub { my ($next, $self, @args) = @_; print "Hi, "; $self->$next(@args); print ', studying ' . $self->course; }
  • 50. Using around use Student; my $person = Student->new( name => 'Mike', course => 'Computer Science', ); $person->introduce(); > Hi, I'm Mike, studying Computer Science
  • 51. Roles
  • 52. Roles • Code fragments that define and provide a small, reusable behaviour
  • 53. Roles • Code fragments that define and provide a small, reusable behaviour • Not inherited - methods become part of consuming class
  • 54. 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
  • 55. 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!
  • 56. Example role package Age; use Moose::Role; has dob => ( isa => 'DateTime', is =>'ro' ); sub age { return DateTime->now ->subtract( shift->dob() ) ->years; }
  • 57. 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; }
  • 58. 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
  • 59. What we'd really like use Student; my $person = Student->new( name => 'Mike', dob => '05-08-1963', course => 'CS', );
  • 60. Redefine our attr... package Age; use Moose::Role; has dob => ( isa => 'DateStr', is =>'ro', );
  • 61. Types to the rescue use Moose::Util::TypeConstraints; subtype 'DateStr' => as 'Str' => where { /^dd-dd-dddd$/ };
  • 62. 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 ); };
  • 63. And then... package Age; use Moose::Role; has dob => ( isa => 'DateTime', is =>'ro', coerce => 1, # very important! );
  • 64. Et voila... use Student; my $person = Student->new( name => 'Mike', dob => '05-08-1963', course => 'CS', ); print $person->age(); > 45
  • 65. Roles as interfaces package Earnings; use Moose::Role; requires qw/annual_income/; sub monthly_income { return shift->annual_income / 12; }
  • 66. Roles as interfaces (2) package Person; with qw/Earnings/; package Student; extends qw/Person/; sub annual_income { my $self = shift; return $self->grant_amount; }
  • 67. Role gotchas
  • 68. Role gotchas • Roles cannot use extends
  • 69. Role gotchas • Roles cannot use extends • requires only works with actual methods :(
  • 70. Role gotchas • Roles cannot use extends • requires only works with actual methods :( • for now, at least
  • 71. Role gotchas • Roles cannot use extends • requires only works with actual methods :( • for now, at least • watch out for method and attribute conflicts
  • 72. 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, );
  • 73. Method Delegation (2) package Graduate; use Moose; extends qw/Student/; has 'degree' => ( isa => 'Degree', is => 'rw', );
  • 74. 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
  • 75. Method Delegation (4) has 'degree' => ( isa => 'Degree', is => 'rw', handles => { graduated => 'awarded' }, );
  • 76. 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
  • 77. 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', );
  • 78. Attribute Helpers my $st = Student->new( name => 'Mike' ); $st->classes( { "Compilers" => 'fail', "Numerical Methods" => 'pass' } ); %{$st->classes}->{"Lisp"} = "pass";
  • 79. Attribute Helpers (2) use MooseX::AttributeHelpers; has classes => ( metaclass => 'Collection::Hash', isa => 'HashRef[Result]', is => 'rw', provides => { set => 'add_class', keys => 'list_classes', } )
  • 80. 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
  • 81. Introspecting Moose
  • 82. Introspecting Moose • my $metaclass = $self->meta;
  • 83. Introspecting Moose • my $metaclass = $self->meta;
  • 84. Introspecting Moose • my $metaclass = $self->meta; • $metaclass->superclasses;
  • 85. Introspecting Moose • my $metaclass = $self->meta; • $metaclass->superclasses; • $metaclass->linearized_isa;
  • 86. Introspecting Moose • my $metaclass = $self->meta; • $metaclass->superclasses; • $metaclass->linearized_isa; • $metaclass->has_method("foo");
  • 87. Introspecting Moose • my $metaclass = $self->meta; • $metaclass->superclasses; • $metaclass->linearized_isa; • $metaclass->has_method("foo"); • $metaclass->get_all_attributes;
  • 88. Method Signatures
  • 89. Method Signatures • We have types...
  • 90. Method Signatures • We have types... • Wouldn't it be nice if types weren't restricted to attrs + accessors?
  • 91. Method Signatures • We have types... • Wouldn't it be nice if types weren't restricted to attrs + accessors? • Enter: MooseX::Method::Signature
  • 92. Method Signatures package Student; use Moose; use MooseX::Method::Signatures; method attend (Str $class, DateTime $time) { # ... }
  • 93. Method Signatures (2) method attend (Str $class, DateTime $time) { if (grep $class, $self->list_classes) { $self->schedule($time, $class); } }
  • 94. Even more Java-like? use MooseX::Declare; class Student extends Person with Earnings { has 'id' => ( isa => 'StudentID' ); method attend ( Str $class, ... ) { # yadda yadda } }
  • 95. How is this implemented?
  • 96. Lasciate ogne speranza, voi ch'intrate
  • 97. But seriously...
  • 98. But seriously... • Devel::Declare sticks the interpreter on pause while it plays with your source
  • 99. But seriously... • Devel::Declare sticks the interpreter on pause while it plays with your source • NOT a source filter
  • 100. 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...
  • 101. Why Moose?
  • 102. Why Moose? • Less code = fewer errors
  • 103. Why Moose? • Less code = fewer errors • Don't waste time on class implementation
  • 104. Why Moose? • Less code = fewer errors • Don't waste time on class implementation • Better object model
  • 105. 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"
  • 106. 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
  • 107. 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
  • 108. Further Reading
  • 109. Further Reading • http://iinteractive.com/moose/
  • 110. Further Reading • http://iinteractive.com/moose/ • Moose::Cookbook (CPAN)
  • 111. Further Reading • http://iinteractive.com/moose/ • Moose::Cookbook (CPAN) • http://www.stonehenge.com/merlyn/ LinuxMag/col94.html
  • 112. Complex Example package Student; use Moose; # yadda has 'id' => ( isa => 'StudentID', is => 'rw', );
  • 113. 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', );
  • 114. Complex Example (3) sub _build__schema { my $self = shift; return Person::Schema->connect( $self->db ); }
  • 115. 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}; };
  • 116. Complex Example (5) has _row => { isa => 'DBIx::Class::Row', lazy_build => 1, } sub _build__row { return shift->_schema ->resultset('Student') ->find($self->id); }
  • 117. Complex Example (6) has _row => { isa => 'DBIx::Class::Row', lazy_build => 1, handles => [qw/address gender/], }
  • 118. Complex Example (7) my $student = Student->new( name => 'Mike', id => '3056', ); print $st->address(); # What happens here?
  • 119. What happens?
  • 120. What happens? • address method is handled by _row
  • 121. What happens? • address method is handled by _row • _row is lazy_build, so calls _build__row
  • 122. What happens? • address method is handled by _row • _row is lazy_build, so calls _build__row • which requires _schema, ALSO lazy_build
  • 123. 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
  • 124. 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!
  • 125. But... # What if the student's ID changes? has 'id' => ( isa => 'StudentID', is => 'rw', trigger => '_build__row', );