X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=moose-class%2Fslides%2Findex.html;h=ca21a08f32393ef4e2a893aab9f21fcc3ad3421a;hb=c31b1deab0210ecbbab1c1efdf800cd12f7847af;hp=d6e036fbd6a4059ca55918396176c5d3b0920dca;hpb=8a719516e8769b73c321abca1137a33d99da6123;p=gitmo%2Fmoose-presentations.git diff --git a/moose-class/slides/index.html b/moose-class/slides/index.html index d6e036f..ca21a08 100644 --- a/moose-class/slides/index.html +++ b/moose-class/slides/index.html @@ -40,7 +40,7 @@ img#me05 {top: 43px;left: 36px;} @@ -235,7 +246,10 @@ after 'foo' my @return = $self->$real_foo( @_, bar => 42 ); - return ( @return, 'modify return values' ); + return ( + @return, + 'modify return values' + ); }; @@ -262,7 +276,7 @@ has weight => ( ); # kaboom -Person->new( weight => 'fat' ); +Person->new( weight => 'heavy' );
@@ -284,11 +298,11 @@ use Moose; has blog_uri => ( is => 'rw', isa => 'URI', - handles => { 'blog_hostname' => 'host' }, + handles => { 'blog_host' => 'host' }, ); -$person->blog_hostname; -# really calls $person->blog_uri->host +$person->blog_host; +# really calls $person->blog_uri->host
@@ -829,6 +843,16 @@ has last_name => ( );
+
+

More Why Moose?

+ + +
+

Part 1: Moose Classes

@@ -869,7 +893,7 @@ use Moose;

BUILDARGS

@@ -1057,8 +1109,7 @@ has first_name => ( is => 'ro' ); my $person = Person->new( first_name => 'Dave' ); -$person->first_name('Stevan'); -print $person->first_name; # Dave +$person->first_name('Stevan'); # dies @@ -1077,7 +1128,7 @@ print $person->first_name; # Dave use Moose; # true -Person->can('extends'); +Person->can('extends'); + + +
+

Basic Attributes Summary

+ +
@@ -2178,18 +2208,18 @@ Iterate til this passes all its tests
-

What is a Method Modifier

+

What Are Method Modifiers For?

@@ -2233,7 +2263,8 @@ before work => sub { my $self = shift; return unless $DEBUG; - warn "Called work on ", $self->full_name, + warn "Called work on ", + $self->full_name, "with the arguments: [@_]\n"; }; @@ -2265,19 +2296,17 @@ after work => sub {
-

Other Uses Example

+

More Modifier Examples

has password => (
      is      => 'rw',
      clearer => 'clear_password',
 );
-
 has hashed_password => (
      is      => 'ro',
      builder => '_build_hashed_password',
      clearer => '_clear_hashed_password',
 );
-
 after clear_password => sub {
     my $self = shift;
     $self->_clear_hashed_password;
@@ -2317,8 +2346,7 @@ after clear_password => sub {
         $self->$orig(
             $self->_munge_insert(@_) );
 
-    $new_user->_assign_uri;
-
+    $new_user->_assign_uri;
     return $new_user;
 };
@@ -2327,7 +2355,7 @@ after clear_password => sub {

Modifier Order

@@ -2382,6 +2410,7 @@ around run => sub { @@ -2390,21 +2419,21 @@ around run => sub {

Augment and Inner

-
package Document;
+  
package Document;
 
 sub xml { '<doc>' . inner() . '</doc>' }
 
 package Report;
 extends 'Document';
-
 augment xml =>
-    sub { title() . inner() . summary() };
+    sub { my $self = shift;
+          $self->title() . inner() . $self->summary() };
 
 package TPSReport;
 extends 'Report';
-
 augment xml =>
-    sub { tps_xml() . inner() };
+ sub { my $self = shift; + $self->tps_xml() . inner() };
@@ -2483,7 +2512,8 @@ extends 'Report';

Exercises

# cd exercises
-# perl bin/prove -lv t/04-method-modifiers.t
+# perl bin/prove -lv \
+      t/04-method-modifiers.t
 
 Iterate til this passes all its tests
@@ -2492,252 +2522,807 @@ Iterate til this passes all its tests

Part 5: Types

-
-

Part 6: Advanced Attributes

-
-
-

Weak References

+

A Type System for Perl

-

Circular Reference Illustrated

- -
my $foo = {};
-my $bar = { foo => $foo };
-$foo->{bar} = $bar;
+

Components of a Moose Type

-

Weakening Circular References

+

Built-in Type Hierarchy

-
use Scalar::Util qw( weaken );
+  
+Any
+Item
+    Bool
+    Maybe[`a]
+    Undef
+    Defined
+        Value
+            Str
+                Num
+                    Int
+                ClassName
+                RoleName
+
+
-my $foo = {}; -my $bar = { foo => $foo }; -$foo->{bar} = $bar; -weaken $foo->{bar} +
+

Built-in Type Hierarchy

- +
+(Item)
+    (Defined)
+        (Value)
+        Ref
+            ScalarRef
+            ArrayRef[`a]
+            HashRef[`a]
+            CodeRef
+            RegexpRef
+            GlobRef
+                FileHandle
+            Object
+
-

Circular References in Attributes

+

Bool

-
package Person;
-use Moose;
+  

True

+
1
+924.1
+'true'
+{}
-has name => ( is => 'ro' ); -has friend => ( is => 'rw' ); +

False

+
0
+0.0
+'0'
+undef
-my $alice = Person->new( name => 'Alice' ); -my $bob = Person->new( name => 'Bob' ); -$bob->friend($alice); -$alice->friend($bob);
+
-

The Fix

+

Value (and subtypes)

-
package Person;
-use Moose;
+  
    +
  • Value is true when ! ref $thing
  • +
  • Value and Str are effectively the same, but Str is more expressive
  • +
  • Num is true when a $scalar looks like a number
  • +
  • An overloaded object which numifies does not pass the Num constraint!
  • +
  • Perl 5's overloading is hopelessly broken
  • +
+
-has name => ( is => 'ro' ); -has friend => ( is => 'rw', weak_ref => 1 ); +
+

ClassName and RoleName

-my $alice = Person->new( name => 'Alice' ); -my $bob = Person->new( name => 'Bob' ); -$bob->friend($alice); -$alice->friend($bob);
+
-

Under the Hood

+

Parameterizable Types

-

Triggers

+

Maybe[`a]

+
-

Gross

+
+

Type Union

-
after salary_level => {
-    my $self = shift;
-    return unless @_;
-    $self->clear_salary;
-};
+
-

Use a Trigger Instead

+

Making Your Own Types

-

Cleaner

+
use Moose::Util::TypeConstraints;
 
-  
has salary_level => (
-    is      => 'rw',
-    trigger => sub { $_[0]->clear_salary },
+subtype 'PositiveInt',
+    as      'Int',
+    where   { $_ > 0 },
+    message
+        { "The value you provided ($_)"
+          . " was not a positive int." };
+
+has size => (
+    is  => 'ro',
+    isa => 'PositiveInt',
 );
-

Delegation

+

Automatic Types

-

Delegation Examples

+

Automatic Types

-
package Person;
+  
package Employee;
+use Moose;
 
-has lungs => (
-    is      => 'ro',
-    isa     => 'Lungs',
-    handles => [ 'inhale', 'exhale' ],
-);
+has manager => ( + is => 'rw', + isa => 'Employee', +); -
    -
  • Creates $person->inhale and ->exhale methods
  • -
  • Internally calls $person->lungs->inhale
  • -
+has start_date => ( + is => 'ro', + isa => 'DateTime', +);
-

Why Delegation?

+

Subtype Shortcuts - class_type

- -
+
use Moose::Util::TypeConstraints;
+class_type 'DateTime';
-
-

Moose's handles Parameter

+
- -
+
subtype     'DateTime',
+    as      'Object',
+    where   { $_->isa('DateTime') },
+    message { ... };
+
-

Array Reference

+

Subtype Shortcuts - role_type

- +
use Moose::Util::TypeConstraints;
+role_type 'Printable';
+ +
+ +
subtype 'Printable',
+    as  'Object',
+    where
+        { Moose::Util::does_role(
+              $_, 'Printable' ) },
+    message { ... };
-

Hash Reference

+

Subtype Shortcuts - duck_type

-
    -
  • Mapping of names in the delegating class to the delegatee class
  • -
+
use Moose::Util::TypeConstraints;
+duck_type Car => qw( run break_down );
-
package Person;
-use Moose;
+
-has account => ( - is => 'ro', - isa => 'BankAccount', - handles => { - receive_money => 'deposit', - give_money => 'withdraw', - }, -);
+
subtype 'Car',
+    as      'Object',
+    where   { all { $_->can($_) }
+              qw( run break_down ) },
+    message { ... };
-

Hash Reference Detailed

+

Subtype Shortcuts - enum

-
    handles => {
-        receive_money => 'deposit',
-        give_money    => 'withdraw',
-    },
+
use Moose::Util::TypeConstraints;
+enum Color => qw( red blue green );
-
    -
  • $person->receive_money = $person->account->deposit
  • -
  • $person->give_money = $person->account->withdraw
  • -
+
+ +
my %ok = map { $_ => 1 }
+             qw( red blue green );
+
+subtype     'Color'
+    as      'Str',
+    where   { $ok{$_} },
+    message { ... };
-

Regex

+

Anonymous Subtypes

package Person;
-use Moose;
 
-has name => (
-    is      => 'ro',
-    isa     => 'Name',
-    handles => qr/.*/,
+my $posint =
+    subtype as 'Int', where { $_ > 0 };
+
+has size => (
+    is  => 'ro',
+    isa => $posint,
 );
    -
  • Creates a delegation for every method in the Name class
  • -
  • Excludes meta and methods inherited from Moose::Object
  • +
  • Shortcuts have anonymous forms as well
-

Role Name

+

Coercions

-
package Auditor;
-use Moose::Role;
+  
use Moose::Util::TypeConstraints;
 
-sub record_change  { ... }
-sub change_history { ... }
+subtype 'UCStr',
+    as    'Str',
+    where { ! /[a-z]/ };
+
-package Account; -use Moose; +
+

Coercions

-has history => ( - is => 'ro', - does => 'Auditor', - handles => 'Auditor', +
coerce 'UCStr',
+    from 'Str',
+    via  { uc };
+
+has shouty_name => (
+    is     => 'ro',
+    isa    => 'UCStr',
+    coerce => 1,
 );
-

Role Name Detailed

+

Coercion Examples

+ +
subtype 'My::DateTime',
+    as class_type 'DateTime';
+
+coerce 'My::DateTime',
+    from 'HashRef',
+    via  { DateTime->new( %{$_} ) };
+
+coerce 'My::DateTime',
+    from 'Int',
+    via  { DateTime->from_epoch(
+               epoch => $_ ) };
+ +
    +
  • Use coercion to inflate a value
  • +
+
+ +
+

Coercion Examples

+ +
coerce 'ArrayRef[Int]',
+    from 'Int',
+    via  { [ $_ ] };
+ +
    +
  • Instead of union - Int | ArrayRef[Int]
  • +
+
+ +
+

Using Types with Attributes

+ +
package Person;
+
+has height => (
+    is  => 'rw',
+    isa => 'Num',
+);
+
+has favorite_numbers => (
+    is     => 'rw',
+    isa    => 'ArrayRef[Int]',
+    coerce => 1,
+);
+
+ +
+

More Droppings

+ +
    +
  • Moose::Util::TypeConstraints also needs cleanup
  • +
+ +
package Person;
+
+use Moose;
+use Moose::Util::TypeConstraints;
+
+subtype ...;
+
+no Moose;
+no Moose::Util::TypeConstraints;
+
+ +
+

Questions So Far?

+
+ +
+

Exercises

+ +
# cd exercises
+# perl bin/prove -lv t/05-types.t
+
+Iterate til this passes all its tests
+
+ +
+

Typed Methods (Low-tech)

+ +
package Person;
+use MooseX::Params::Validate qw( validated_list );
+
+sub work {
+    my $self = shift;
+    my ( $tasks, $can_rest ) =
+        validated_list(
+            \@_,
+            tasks    =>
+                { isa    => 'ArrayRef[Task]',
+                  coerce => 1 },
+            can_rest =>
+                { isa     => 'Bool',
+                  default => 0 },
+        );
+    ...
+}
+
+ +
+

Typed Methods (High-tech)

+ +
package Person;
+
+use MooseX::Method::Signatures;
+
+method work ( ArrayRef[Task] :$tasks,
+                        Bool :$can_rest = 0 ) {
+    my $self = shift;
+
+    ...
+}
+
+ +
+

Digression: The Type Registry

+ +
    +
  • Types are actually Moose::Meta::TypeConstraints objects
  • +
  • Stored in an interpreter-global registry mapping names to objects
  • +
+
+ +
+

Danger!

+ +
    +
  • Coercions are attached to type objects
  • +
  • Therefore also global
  • +
  • Name conflicts between modules!
  • +
  • Coercion conflicts between modules!
  • +
+
+ +
+

Namespace Fix

+ +
    +
  • Use some sort of pseudo-namespacing scheme
  • +
  • Never coerce directly to a class name, or to built-in types
  • +
+
+ +
+

Namespace Fix

+ +
use Moose::Util::TypeConstraints;
+subtype 'MyApp::Type::DateTime',
+    as 'DateTime';
+
+coerce 'MyApp::Type::DateTime',
+    from 'HashRef',
+    via  { DateTime->new( %{$_} ) }
+
+has creation_date => (
+    is     => 'ro',
+    isa    => 'MyApp::Type::DateTime',
+    coerce => 1,
+);
+
+ +
+

Namespace Fix

+ +
subtype 'MyApp::Type::ArrayOfInt',
+    as 'ArrayRef[Int]';
+
+coerce 'MyApp::Type::ArrayOfInt',
+    from 'Int',
+    via  { [ $_ ] };
+
+ +
+

Namespace Fix Pros and Cons

+ +
    +
  • Relatively simple
  • +
  • Already built into Moose
  • +
  • Conflates type and module namespaces
  • +
  • Type names are strings, so typos are easy to make and may be hard to find
  • +
+
+ +
+

MooseX::Types

+ +
package MyApp::Types;
+
+use MooseX::Types
+    -declare => [ qw( ArrayOfInt ) ];
+use MooseX::Types::Moose
+    qw( ArrayRef Int );
+
+subtype ArrayOfInt,
+    as ArrayRef[Int];
+
+coerce ArrayOfInt
+    from Int,
+    via  { [ $_ ] };
+
+ +
+

MooseX::Types

+ +
package MyApp::Account;
+
+use MyApp::Types qw( ArrayOfInt );
+
+has transaction_history => (
+    is  => 'rw',
+    isa => ArrayOfInt,
+);
+
+ +
+

MooseX::Types

+ +
    +
  • Type names are exported functions, catches typos early
  • +
  • Types must be pre-declared
  • +
  • Types are stored with namespaces internally, but you use short names
  • +
  • Import existing Moose types as functions from MooseX::Types::Moose
  • +
  • Still need string names for things like ArrayRef['Email::Address']
  • +
+
+ +
+

MooseX::Types Pros and Cons

+ +
    +
  • Catches typos at compile time
  • +
  • Automatic namespacing
  • +
  • One more thing to install and learn
  • +
  • Every name is typed twice (declared and then defined)
  • +
  • Still stuck with strings when referring to class or role names
  • +
  • Coercion gotcha from earlier still applies to types exported from MooseX::Types::Moose
  • +
+
+ +
+

Recommendation

+ +
    +
  • Use MooseX::Types
  • +
  • Compile time error catching and automatic namespacing are huge wins
  • +
  • Docs from Moose::Util::TypeConstraints are 98% compatible with MooseX::Types anyway
  • +
  • A function exported by a type library works wherever a type name would
  • +
+
+ +
+

Questions?

+
+ +
+

Part 6: Advanced Attributes

+
+ +
+

Weak References

+ +
    +
  • A weak reference lets you avoid circular references
  • +
  • Weak references do not increase the reference count
  • +
+
+ +
+

Circular Reference Illustrated

+ +
my $foo = {};
+my $bar = { foo => $foo };
+$foo->{bar} = $bar;
+ +
    +
  • Neither $foo nor $bar go out of scope
    + (until the program exits)
  • +
+
+ +
+

Weakening Circular References

+ +
use Scalar::Util qw( weaken );
+
+my $foo = {};
+my $bar = { foo => $foo };
+$foo->{bar} = $bar;
+weaken $foo->{bar}
+ +
    +
  • When $bar goes out of scope, $foo->{bar} becomes undef
  • +
+
+ +
+

Circular References in Attributes

+ +
package Person;
+use Moose;
+
+has name   => ( is => 'ro' );
+has friend => ( is => 'rw' );
+
+my $alice = Person->new( name => 'Alice' );
+my $bob   = Person->new( name => 'Bob' );
+$bob->friend($alice);
+$alice->friend($bob);
+
+ +
+

The Fix

+ +
package Person;
+use Moose;
+
+has name   => ( is => 'ro' );
+has friend => ( is       => 'rw',
+                weak_ref => 1 );
+
+my $alice = Person->new( name => 'Alice' );
+my $bob   = Person->new( name => 'Bob' );
+$bob->friend($alice);
+$alice->friend($bob);
+
+ +
+

Under the Hood

+ +
    +
  • A weak_ref attribute calls weaken ... +
      +
    • during object construction
    • +
    • when the attribute is set via a writer
    • +
    +
  • +
+
+ +
+

Triggers

+ +
    +
  • A code reference run after an attribute is set
  • +
  • Like an after modifier, but makes intentions clearer
  • +
+ +

Gross

+ +
after salary_level => {
+    my $self = shift;
+    return unless @_;
+    $self->clear_salary;
+};
+
+ +
+

Use a Trigger Instead

+ +

Cleaner

+ +
has salary_level => (
+    is      => 'rw',
+    trigger =>
+        sub { $_[0]->clear_salary },
+);
+
+ +
+

Trigger Arguments

+ +
    +
  • $self
  • +
  • $new_value
  • +
  • $old_value - if one exists
  • +
+
+ +
+

Delegation

+ +
    +
  • Attributes can be objects
  • +
  • Delegation transparently calls methods on those objects
  • +
+
+ +
+

Delegation Examples

+ +
package Person;
+
+has lungs => (
+    is      => 'ro',
+    isa     => 'Lungs',
+    handles => [ 'inhale', 'exhale' ],
+);
+ +
    +
  • Creates $person->inhale and ->exhale methods
  • +
  • Internally calls $person->lungs->inhale
  • +
+
+ +
+

Why Delegation?

+ +
    +
  • Reduce the number of classes exposed
  • +
  • Re-arrange class internals -
    + turn a method into an attribute with delegation
  • +
  • Provide convenenience methods
  • +
+
+ +
+

Moose's handles Parameter

+ +
    +
  • Accepts many arguments ... +
      +
    • Array reference - list of methods to delegate as-is
    • +
    • Hash reference - map of method names
    • +
    • Regex - delegates all matching methods
    • +
    • Role name - delegates all methods in the role
    • +
    • Sub reference - does something complicated ;)
    • +
    +
  • +
+
+ +
+

Array Reference

+ +
    +
  • 1-to-1 mapping
  • +
  • Takes each method name and creates a simple delegation from the delegating class to the delegatee attribute
  • +
+
+ +
+

Hash Reference

+ +
    +
  • Mapping of names in the delegating class to the delegatee class
  • +
+ +
package Person;
+use Moose;
+has account => (
+    is      => 'ro',
+    isa     => 'BankAccount',
+    handles => {
+        receive_money => 'deposit',
+        give_money    => 'withdraw',
+    },
+);
+
+ +
+

Hash Reference Detailed

+ +
    handles => {
+        receive_money => 'deposit',
+        give_money    => 'withdraw',
+    },
+ +
    +
  • $person->receive_money = $person->account->deposit
  • +
  • $person->give_money = $person->account->withdraw
  • +
+
+ +
+

Regex

+ +
package Person;
+use Moose;
+
+has name => (
+    is      => 'ro',
+    isa     => 'Name',
+    handles => qr/.*/,
+);
+ +
    +
  • Creates a delegation for every method in the Name class
  • +
  • Excludes meta and methods inherited from Moose::Object
  • +
+
+ +
+

Role Name

+ +
package Auditor;
+use Moose::Role;
+sub record_change  { ... }
+sub change_history { ... }
+
+package Account;
+use Moose;
+
+has history => (
+    is      => 'ro',
+    does    => 'Auditor',
+    handles => 'Auditor',
+);
+
+ +
+

Role Name Detailed

  • Account gets delegate methods for each method in the Auditor role @@ -2750,6 +3335,120 @@ has history => (
+

Native Delegation

+ +
    +
  • Delegate to unblessed Perl types
  • +
  • Scalar, array or hash ref, etc
  • +
  • Treat Perl types as objects
  • +
  • Still uses handles
  • +
  • Pretend that native Perl types have methods
  • +
+
+ +
+

Native Delegation - Array(Ref)

+ +
    +
  • Methods include: +
      +
    • push
    • +
    • shift
    • +
    • elements - returns all elements
    • +
    • count
    • +
    • is_empty
    • +
    • quite a few more
    • +
    +
  • +
+
+ +
+

Native Delegation - Array(Ref)

+ +
package Person;
+use Moose;
+has _favorite_numbers => (
+    traits   => [ 'Array' ],
+    is       => 'bare',
+    isa      => 'ArrayRef[Int]',
+    default  => sub { [] },
+    init_arg => undef,
+    handles  =>
+      { favorite_numbers    => 'elements',
+        add_favorite_number => 'push',
+      },
+);
+
+ +
+

Native Delegation - Array(Ref)

+ +
my $person = Person->new();
+
+$person->add_favorite_number(7);
+$person->add_favorite_number(42);
+
+print "$_\n"
+    for $person->favorite_numbers;
+
+# 7
+# 42
+
+ +
+

Native Delegation

+ +
    +
  • Native types are ... +
      +
    • Number - add, mul, ...
    • +
    • String - append, chop, ...
    • +
    • Counter - inc, dec, ...
    • +
    • Bool - set, toggle, ...
    • +
    • Hash - get, set, ...
    • +
    • Array - already saw it
    • +
    • Code - execute and execute_method
    • +
    +
  • +
+
+ +
+

Curried Delegation

+ +
    +
  • A delegation with some preset arguments
  • +
  • Works with object or Native delegation
  • +
+
+ +
+

Curried Delegation

+ +
package Person;
+use Moose;
+has account => (
+    is      => 'ro',
+    isa     => 'BankAccount',
+    handles => {
+        receive_100 =>
+            [ 'deposit', 100 ]
+        give_100    =>
+            [ 'withdraw', 100 ]
+    },
+);
+
+ +
+

Curried Delegation

+ +
$person->receive_100;
+# really is
+$person->account->deposit(100);
+
+ +

Traits and Metaclasses

    @@ -2774,7 +3473,7 @@ has history => (

    Traits and Metaclasses

      -
    • Can add/alter/remove attribute parameter (from has)
    • +
    • Can add/alter/remove an attribute parameter (from has)
    • Can change behavior of created attribute
@@ -2792,7 +3491,6 @@ has ssn => ( isa => 'Str', label => 'Social Security Number', ); - print Person->meta ->get_attribute('ssn')->label;
@@ -2811,7 +3509,6 @@ has ssn => ( isa => 'Str', label => 'Social Security Number', ); - print Person->meta ->get_attribute('ssn')->label;
@@ -2834,37 +3531,243 @@ print Person->meta
  • Use weak_ref to avoid circular references
  • Use trigger to do an action post-attribute write
  • Use delegations to hide "internal" objects
  • +
  • Use native delegations to treat Perl types as objects
  • Traits and metaclasses let you extend Moose's core attribute features
  • -

    Questions?

    -
    - -

    Exercises

    # cd exercises
    -# perl bin/prove -lv t/06-advanced-attributes.t
    +# perl bin/prove -lv \
    +      t/06-advanced-attributes.t
     
     Iterate til this passes all its tests
    -
    -

    Part 7: Introspection

    +
    +

    CYOA

    + +

    + If there is time, keep going ... +

    + +

    + Otherwise, jump to slide 269 ... +

    -

    Part 8: A Tour of MooseX

    +

    Bonus: A Brief Tour of MooseX

    -
    -

    Part 9: Writing Moose Extensions

    +
    +

    Notable MX Modules on CPAN

    + +
      +
    • Not comprehensive
    • +
    • 152 MooseX distributions on CPAN as of 02/02/2010
    • +
    • Some of them are crap
    • +
    -
    -

    The End +
    +

    Already Mentioned Several

    + +
      +
    • MooseX::NonMoose - best solution for subclassing non-Moose parents
    • +
    • MooseX::Declare - real Perl 5 OO
    • +
    • MooseX::FollowPBP and MooseX::SemiAffordanceAccessor
    • +
    • MooseX::Params::Validate and MooseX::Method::Signatures
    • +
    • MooseX::Types
    • +
    +
    + +
    +

    MooseX::Declare

    + +
    use MooseX::Declare;
    +use 5.10.0; # for say
    +
    +class Person {
    +    has greeting =>
    +        ( is => 'ro', isa => 'Str' );
    +
    +    method speak {
    +        say $self->greeting;
    +    }
    +}
    +
    + +
    +

    MooseX::Declare

    + +
      +
    • Still experimental-ish, but seeing more and more use
    • +
    • Not a source filter!
    • +
    • Hooks into the Perl parser rather than filtering all your code
    • +
    • But not supported by PPI, perltidy, etc.
    • (yet?) +
    +
    + +
    +

    MooseX::StrictConstructor

    + +
      +
    • By default, unknown constructor arguments are ignored
    • +
    • MX::StrictConstructor turns these into an error
    • +
    +
    + +
    +

    MooseX::StrictConstructor

    + +
    package Person;
    +
    +use Moose;
    +use MooseX::StrictConstructor;
    +
    +has name => ( is => 'ro' );
    +
    +Person->new
    +    ( nane => 'Ringo Shiina' ); # kaboom
    +
    + +
    +

    MooseX::Traits

    + +
      +
    • Combines object construction and role application
    • +
    • Makes it easy to create one-off customized objects
    • +
    +
    + +
    +

    MooseX::Traits

    + +
    package MyApp::Thingy;
    +use Moose;
    +
    +with 'MooseX::Traits';
    +
    +my $thing =
    +    MyApp::Thingy->new_with_traits
    +        ( traits => [ 'Foo', 'Bar' ],
    +          size   => 42 );
    +
    + +
    +

    MooseX::Getopt

    + +
      +
    • Makes command-line interface programs easy!
    • +
    • Construct an object from CLI arguments
    • +
    +
    + +
    +

    MooseX::Getopt

    + +
    package App::CLI;
    +use Moose;
    +
    +with 'MooseX::Getopt';
    +
    +has file    =>
    +    ( is => 'ro', required => 1 );
    +has filters =>
    +    ( is => 'ro', isa => 'ArrayRef[Str]' );
    +
    +sub run { ... }
    +
    + +
    +

    MooseX::Getopt

    + +
      +
    • Then call it like this:
    • +
    + +
    #!/usr/bin/perl
    +
    +use App::CLI;
    +
    +App::CLI->new_with_options()->run();
    + +
    $ myapp-cli \
    +   --file foo \
    +   --filters compress \
    +   --filters sanitize
    +
    + +
    +

    MooseX::Clone

    + +
    package Person;
    +
    +use Moose;
    +with 'MooseX::Clone';
    +
    +my $person = Person->new;
    +my $clone  = $person->clone;
    +
    + +
    +

    MooseX::NonMoose

    + +
      +
    • Highly recommended for subclassing non-Moose parents
    • +
    • Gets all the little annoying details right
    • +
    +
    + +
    +

    MooseX::Role::Parameterized

    + +
    package HasCollection;
    +use MooseX::Role::Parameterized;
    +parameter type => ( isa     => 'Str',
    +                    default => 'Item' );
    +role {
    +    my $p = shift;
    +
    +    my $type =
    +        'ArrayRef[' . $p->type() . ']';
    +    has collection =>
    +        ( is  => 'ro',
    +          isa => $type );
    +};
    +
    + +
    +

    MooseX::Role::Parameterized

    + +
    package Person;
    +
    +use Moose;
    +with HasCollection => { type => 'Int' };
    +
    + +
    +

    Questions?

    +
    + +
    +

    Moose-using Modules

    + +

    + For further reading, a few modules which use Moose ... +

    + +
    @@ -2877,10 +3780,14 @@ Iterate til this passes all its tests
  • mailing list - moose@perl.org
  • Slides and exercises are in Moose's git repo:
    - git://jules.scsys.co.uk/gitmo/moose-presentations
  • + git://jules.scsys.co.uk/gitmo/moose-presentations
    +
    +

    The End

    +
    +