From: Dave Rolsky Date: Sun, 7 Jun 2009 23:20:14 +0000 (-0500) Subject: Added CC license X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=55906a14944d237ebf5785dac984d5dc632ef4a2;p=gitmo%2Fmoose-presentations.git Added CC license First draft of role slides --- diff --git a/moose-class/slides/index.html b/moose-class/slides/index.html index 523fc25..e2c526b 100644 --- a/moose-class/slides/index.html +++ b/moose-class/slides/index.html @@ -5,6 +5,7 @@ Introduction to Moose + @@ -39,6 +40,11 @@ img#me05 {top: 43px;left: 36px;}
@@ -60,20 +66,21 @@ img#me05 {top: 43px;left: 36px;} -
-

Part 0: Moose Concepts

-
-
-

Moose background

+

Moose Background

+
+

Part 0: Moose Concepts

+
+

Classes

@@ -138,7 +145,7 @@ img#me05 {top: 43px;left: 36px;}
package Person;
 use Moose;
 
-has 'first_name' => ( is => 'rw' );
+has first_name => ( is => 'rw' );
@@ -250,7 +257,10 @@ after 'foo'
package Person;
 use Moose;
 
-has 'weight' => ( is => 'ro', isa => 'Int' );
+has weight => (
+    is  => 'ro',
+    isa => 'Int',
+);
 
 # kaboom
 Person->new( weight => 'fat' );
@@ -272,14 +282,14 @@ Person->new( weight => 'fat' );
package Person;
 use Moose;
 
-has 'blog_uri' => (
+has blog_uri => (
     is      => 'rw',
     isa     => 'URI',
     handles => { 'blog_hostname' => 'host' },
 );
 
 $person->blog_hostname;
-# really calls $person->blog_uri->host
+# really calls $person->blog_uri->host
@@ -880,13 +890,13 @@ use Moose;
package EvilEmployee;
 use Moose;
 extends 'Person';
-extends 'Thief';
+extends 'Thief';

RIGHT

package EvilEmployee;
 use Moose;
-extends 'Person', 'Thief';
+extends 'Person', 'Thief';
@@ -894,7 +904,7 @@ extends 'Person', 'Thief';
package My::LWP;
 use Moose;
-extends 'LWP';
+extends 'LWP';

Caveat super

@@ -958,7 +969,7 @@ use Moose;
package Person;
 use Moose;
 
-has 'first_name' => ( is => 'rw' );
+has first_name => ( is => 'rw' );
 
 my $person =
     Person->new( first_name => 'Dave' );
@@ -974,7 +985,7 @@ print $person->first_name; # Stevan
package Person;
 use Moose;
 
-has 'first_name' => ( is => 'ro' );
+has first_name => ( is => 'ro' );
 
 my $person =
     Person->new( first_name => 'Dave' );
@@ -1064,6 +1075,20 @@ use Moose;
 
+

Classes Summary

+ +
    +
  • use Moose
  • +
  • Class->meta
  • +
  • Moose::Object base class
  • +
  • extends, overrides, and super
  • +
  • Simple attributes: has, is => 'ro', & is => 'rw'
  • +
  • no Moose
  • +
  • __PACKAGE__->meta->make_immutable
  • +
+
+ +

Exercises

$ cd exercises
@@ -1073,7 +1098,500 @@ Missing anything? Install it. (see tarballs/)
 
 # perl bin/prove -lv t/01-classes.t
 
-Iterate til this passes all its tests
+Iterate til this passes all its tests
+
+ +
+

Part 2: Roles

+
+ +
+

Just What Is a Role?

+ +
    +
  • Mixin? Interface? Trait?
  • +
  • Yes ... and more!
  • +
+
+ +
+

Roles Can Have State and Behavior

+ +
package HasPermissions;
+use Moose::Role;
+
+# state
+has access_level => ( is => 'rw' );
+
+# behavior
+sub can_access {
+    my $self     = shift;
+    my $required = shift;
+
+    return $self->access_level >= $required;
+}
+ +
+ +
+

Roles Can Define Interfaces

+ +
package Printable;
+use Moose::Role;
+
+requires 'as_string';
+
+ +
+

Roles Can Do All Three

+ +
package Printable;
+use Moose::Role;
+
+requires 'as_string';
+
+has has_been_printed => ( is => 'rw'  );
+
+sub print {
+    my $self = shift;
+    print $self->as_string;
+    $self->has_been_printed(1);
+}
+
+ +
+

Classes Consume Roles

+ +
package Person;
+use Moose;
+
+with 'HasPermissions';
+
+ +
+

Classes Consume Roles

+ +
my $person = Person->new(
+    first_name => 'Kenichi',
+    last_name => 'Asai',
+    access_level => 42,
+);
+
+print $person->full_name
+    . ' has '
+    . $person->can_access(42)
+        ? 'great power'
+        : 'little power';
+
+ +
+

Roles in Practice

+ +
    +
  • Consuming a role =~ inlining the role
  • +
+
+ +
+

In Other Words ...

+ +
package Person;
+use Moose;
+
+with 'Printable';
+
+ +
+

In Other Words ...

+ +
package Person;
+use Moose;
+
+with 'Printable';
+
+has has_been_printed => ( is => 'rw'  );
+
+sub print {
+    my $self = shift;
+    print $self->as_string;
+    $self->has_been_printed(1);
+}
+
+ +
+

Except

+ +
    +
  • Role consumption is introspectable
  • +
+ +
if ( Person->does('Printable') ) { ... }
+
+# or ...
+
+if ( Person->meta->does('Printable') ) { ... }
+ +
+ +
+

These Names Are the Same

+ +
    +
  • What if a role and class define the same method?
  • +
  • A class's local methods win over the role's
  • +
  • The role's methods win over the class's inherited methods
  • +
+
+ +
+

Conflicts Between Roles

+ +
    +
  • Two roles with a method of the same name
  • +
  • Generates a compile-time error when consumed by a class
  • +
+
+ +
+

Conflict Example

+ +
package IsFragile;
+use Moose::Role;
+
+sub break { ... }
+
+package CanBreakdance;
+use Moose::Role;
+
+sub break { ... }
+
+ +
+

Conflict Example

+ +
package FragileDancer;
+use Moose;
+
+with 'IsFragile', 'CanBreakdance';
+ +
    +
  • Only one with!
  • +
+
+ +
+

Conflict Resolution

+ +
    +
  • The consuming class must resolve the conflict by implementing th emethod
  • +
  • Can use some combination of method exclusion and aliasing
  • +
+
+ +
+

Method Aliasing

+ +
package FragileDancer;
+use Moose;
+
+with 'IsFragile' =>
+         { alias =>
+               { break => 'break_bone' } },
+     'CanBreakdance' =>
+         { alias =>
+               { break => 'break_it_down' } };
+ +
    +
  • Renames the roles' methods
  • +
  • Still conflicts, need to exclude as well
  • +
+
+ +
+

Method Exclusion

+ +
package FragileDancer;
+use Moose;
+
+with 'IsFragile' =>
+         { alias =>
+               { break => 'break_bone' },
+           exclude => 'break' },
+     'CanBreakdance' =>
+         { alias =>
+               { break => 'break_dance' },
+           exclude => 'break' };
+
+ +
+

And then ...

+ +
package FragileDancer;
+use Moose;
 
+sub break {
+    my $self = shift;
+
+    $self->break_dance;
+    if ( rand(1) < 0.5 ) {
+        $self->break_bone;
+    }
+}
+
+ +
+

Still Full of Fail

+ +
    +
  • Roles are also about semantics!
  • +
  • We've fulfilled the letter and lost the spirit
  • +
  • Roles have a meaning
  • +
  • Think twice before blindly aliasing and excluding methods!
  • +
+
+ +
+

Hot Role-on-Role Action

+ +
package Comparable;
+use Moose::Role;
+
+requires 'compare';
+
+ +
+

Hot Role-on-Role Action

+ +
package TestsEquality;
+use Moose::Role;
+
+with 'Comparable';
+
+sub is_equal {
+    my $self = shift;
+    return $self->compare(@_) == 0;
+}
+
+ +
+

And then ...

+ +
package Integer;
+use Moose;
+
+with 'TestsEquality';
+
+# Satisfies the Comparable role
+sub compare { ... }
+
+Integer->does('TestsEquality'); # true
+Integer->does('Comparable'); # also true!
+
+ +
+

Name Conflicts Between Roles

+ +
package HasSubProcess;
+use Moose::Role;
+
+sub execute { ... }
+
+package Killer;
+use Moose::Role;
+
+with 'HasSubProcess';
+
+sub execute { ... }
+
+ +
+

Delayed Conflict

+ +
package StateOfTexas;
+with 'Killer';
+ +
    +
  • StateOfTexas must implement its own execute
  • +
  • But loading the Killer role by itself does not cause an error
  • +
+
+ +
+

Roles as Interfaces

+ +
    +
  • Roles can require methods of their consumers
  • +
  • Compile-time checks
  • +
  • Method must exist when the role is consumed
  • +
+
+ +
+

The Attribute Gotcha

+ +
package HasSize;
+use Moose::Role;
+
+requires 'size';
+
+package Shirt;
+use Moose;
+
+with 'HasSize';
+
+has size => ( is => 'ro' );
+
+ +
+

The Attribute Gotcha Workaround

+ +
package HasSize;
+use Moose::Role;
+
+requires 'size';
+
+package Shirt;
+use Moose;
+
+has size => ( is => 'ro' );
+
+with 'HasSize';
+
+ +
+

Compile-time Is a Lie

+ +
    +
  • Really, it's package load time
  • +
  • That's run-time, but before the "real" run-time
  • +
  • Moose does not rewire Perl, it's just sugar!
  • +
  • (but MooseX::Declare does rewire Perl)
  • +
+
+ +
+

Enforcing Roles

+ +
package Comparison;
+use Moose;
+
+has [ 'left', 'right' ] => (
+    is   => 'ro',
+    does => 'Comparable',
+);
+
+ +
    +
  • A sneak peek at type constraints
  • +
+
+ + +
+

Roles Can Be Applied to Objects

+ +
use Moose::Util qw( apply_all_roles );
+
+my $fragile_person = Person->new( ... );
+apply_all_roles( $fragile_person, 'IsFragile' );
+ +
    +
  • Does not change the Person class
  • +
  • Works with non-Moose classes, great for monkey-patching!
  • +
+
+ +
+

Roles Are Dirty Too

+ +
    +
  • Once again, clean up those Moose droppings
  • +
+ +
package Comparable;
+use Moose::Role;
+
+requires 'compare';
+
+no Moose::Role;
+ +
    +
  • But roles cannot be made immutable
  • +
+
+ +
+

The Zen of Roles

+ +
    +
  • Roles represent discrete units of ... +
      +
    • state
    • +
    • behavior
    • +
    • interface
    • +
    +
  • +
  • Roles are shareable between unrelated classes
  • +
  • Roles are what a class does, not what it is
  • +
  • Roles add functionality, inheritance specializes
  • +
+
+ +
+

Abstract Examples

+ +
    +
  • Human @ISA Animal
  • +
  • Human does Toolmaker (as does Chimpanzee)
  • +
  • Car @ISA Vehicle
  • +
  • Car does HasEngine
  • +
+
+ +
+

Real Examples

+ +
    +
  • Objects representing SQL database components and queries +
      +
    • Schema, Table, Column, ColumnAlias
    • +
    • Select, Insert, Update, Delete
    • +
    +
  • +
+
+ +
+

Real Examples

+ +
    +
  • Column and ColumnAlias both do ColumnLike
  • +
  • ColumnLike things can be used in certain parts of queries
  • +
  • All queries do HasWhereClause
  • +
  • Select does Comparable and Selectable (for subselects)
  • +
  • A where clause requires its components to do Comparable
  • +
+
+ +
+

Exercises

+ +
$ cd exercises
+# perl bin/prove -lv t/02-roles.t
+
+Iterate til this passes all its tests
+
+ + + +