Introduction To Moose

8,174 views
7,994 views

Published on

Introduction to Moose talk given at Italian Perl Workshop 2009.

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

Published in: Technology
1 Comment
13 Likes
Statistics
Notes
  • 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?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
8,174
On SlideShare
0
From Embeds
0
Number of Embeds
80
Actions
Shares
0
Downloads
287
Comments
1
Likes
13
Embeds 0
No embeds

No notes for slide
  • Introduction To Moose

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

    ×