2 Location: YAPC::Asia::2008
3 Presenter: Yuval Kogman
12 * Just another accessor builder
17 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
22 * A complete modern object framework for Perl
24 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
29 * Syntactic Sugar for `Class::MOP`
31 * CLOS (Common Lisp Object System)
36 * Stable & Production ready
39 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
51 my ( $class, @args ) = @_;
53 @args = %{$args[0]} if @args == 1;
61 my ($self, @args) = @_;
62 $self->{name} = $args[0] if @args;
67 my ($self, @args) = @_;
68 $self->{age} = $args[0] if @args;
75 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
77 A Simple Moose Example
78 ======================
84 has name => (is => 'rw');
85 has age => (is => 'rw');
90 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
92 A Simple Moose Example (cont.)
93 ==============================
97 * `use strict; use warnings;`
98 * `@ISA = qw(Moose::Object) unless @ISA`
100 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
102 A Simple Moose Example (cont.)
103 ==============================
105 * `has` declares attributes
106 * generates accessors
107 * `is => 'rw'` → read/write accessor
108 * `is => 'ro'` → read only accessor
111 * `new` inherited from `Moose::Object`
116 Now we're going to discuss more features of the attributes
118 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
120 Variations on a Moose Example
121 =============================
137 default => sub { [qw(Bob Alice Tim)] },
144 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
146 Variations on a Moose Example (cont.)
147 =====================================
151 * or non-reference (numbers, strings)
152 * used when no parameter is given to `new`
154 * `lazy` delays `default`
155 * called on first usage of `$object->staff`
161 non refs make accidental sharing hard
163 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
165 Variations on a Moose Example (cont.)
166 =====================================
168 * `isa` specifies a type
169 * `Moose::Util::TypeConstraints`
170 * `Any, Item, Bool, Undef, Defined, Value, Num, Int, Str, Ref, ScalarRef, ArrayRef, HashRef, CodeRef, RegexpRef, GlobRef, FileHandle, Object and Role`
171 * Types don't need to exist
173 has 'date' => (isa => 'DateTime'); # DWIM
177 isa, type constraints
179 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
184 * Types have a hierarchy
185 * `Item` ⊃ `Defined` ⊃ `Ref` ⊃ `Object`
190 => where { ref($_) };
194 => where { blessed($_) }
200 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
202 Conventional Delegates
203 ======================
214 manager_name => 'name',
215 coworkers => 'staff',
220 * manager `handles` certain methods for `Employee`
221 * `$emp->coworkers` == `$emp->manager->staff `
223 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
225 Conventional Delegates (cont.)
226 ==============================
231 handles => [qw(number extension)],
235 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
237 Conventional Delegates (cont.)
238 ==============================
244 handles => qr/^[a-z]\w+$/,
248 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
250 Conventional Delegates (cont.)
251 ==============================
256 handles => "Dialing", # a role
260 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
262 UnConventional Delegates
263 ========================
268 use MooseX::AttributeHelpers;
271 metaclass => 'Collection::Array',
272 isa => 'ArrayRef[Employees]',
275 push => 'add_employee',
276 pop => 'remove_employee',
277 count => 'number_of_employees',
278 empty => 'any_employees',
282 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
288 before 'employees' => sub { warn 'calling employees' };
290 after 'employees' => sub { warn 'finished calling employees' };
295 * Return value is ignored
297 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
299 Modified Methods (cont.)
300 ========================
303 around 'employees' => sub {
304 my ($next, $self, @args) = @_;
306 my @return = $self->$next(@args);
312 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
314 Modified Methods (cont.)
315 ========================
326 inner(); # call subclass here
332 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
334 Modified Methods (cont.)
335 ========================
338 package Employee::Chef;
341 extends qw(Employee);
343 augment do_work => sub {
347 $self->flip_burger(shift @burgers);
351 $chef->do_work; # punch in, flip burgers, punch out
353 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
355 Some Type of Coercion
356 =====================
361 use Moose::Util::TypeConstraints;
364 class_type 'Manager';
366 coerce 'Manager' => (
367 from 'Str' => via { Manager->new( name => $_ ) },
378 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
380 Some Type of Coercion (cont.)
381 =============================
384 # import type constraint keywords
385 use Moose::Util::TypeConstraints;
388 # define Manager, a subtype of Object
389 class_type "Manager";
392 # define the conversion
393 ... via { Manager->new( name => $_ ) }
396 # enable it per attribute
405 breakdown of the example
407 class types are automatically created for all Moose classes
409 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
411 Some Type of Digression
412 =======================
417 isa => 'ArrayRef[Employee]',
420 has shopping_carts => (
422 isa => 'ArrayRef[ArrayRef[ShinyBead]]'
428 Going to go into features of the type system for a bit
432 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
433 Some Type of Digression (cont.)
434 ===============================
439 isa => 'English | Welsh | Scots | Gaelic',
444 isa => 'Employee | ArrayRef[ Employee | Group ]',
452 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
454 Some Type of Digression (cont.)
455 ===============================
460 use Moose::Util::TypeConstraints;
462 use Test::Deep qw(eq_deeply ...);
464 type 'SomethingTricky' => where {
465 eq_deeply( $_, ... );
470 isa => 'SomethingTricky',
476 Test::Deep custom validator
478 Can use any validation from the CPAN
480 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
482 Some Parametrized Type of Coercion
483 ==================================
486 use Moose::Util::TypeConstraints;
488 subtype 'ArrayRef[Employee]' => as 'ArrayRef';
490 coerce 'ArrayRef[Employee]' => (
491 from 'ArrayRef[Str]' via {
492 [ map { Employee->new( name => $_ ) } @$_ ]
497 isa => 'ArrayRef[Employee]',
504 coerce parametrized ArrayRef[Employee] from ArrayRef[Str]
506 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
512 * Java Interface: safe
514 * A role is for small reusable behaviors
515 * better than using a multiple inheritence
517 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
519 Role of the Moose (cont.)
520 =========================
523 * `MooseX::Clone` - Flexible `clone` method
524 * `MooseX::Storage` - Flexible serialization
525 * `MooseX::Getopt` - `@ARGV` aware constructor
526 * `MooseX::LogDispatch` - `$self->logger->info("something happenned")`
527 * `MooseX::Param` - `param` method like `CGI.pm`'s,
531 Some examples of small reusable behaviors
533 Param is good for interacting with e.g. CGI::Expand or similar modules
535 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
537 Role of the Moose (cont.)
538 =========================
544 extends qw(Employee);
546 with qw(Salaried::Hourly);
552 extends qw(Employee);
554 with qw(Salaried::Monthly);
558 * `with` adds roles into your class
559 * `Salaried::Hourly` was added to `Minion`
561 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
563 Role of the Moose (cont.)
564 =========================
570 requires 'paycheck_amount';
575 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
577 Role of the Moose (cont.)
578 =========================
581 package Salaried::Hourly;
592 has logged_hours => (
598 # satisfy the Salaried interface:
599 sub paycheck_amount {
601 $self->logged_hours * $self->hourly_rate;
606 * More than an interface
608 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
610 Role of the Moose (cont.)
611 =========================
613 * More than Java Interfaces
614 * Interfaces are behavior "contracts"
615 * Roles can also have code
618 roles can have attributes and methods
619 roles provide behavior, not just interface
621 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
623 Role of the Moose (cont.)
624 =========================
631 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
633 Role of the Moose (cont.)
634 =========================
638 * Compile time errors
639 * …And ways to fix them
642 symmetric composition means no precedence - if two roles try to define the same thing you get a compile time error that needs to be resolved
643 multiple inheritence silently assumes you want the first class
645 roles cause errors at compile time, unlike multiple inheritence
647 roles also provide easy ways to fix the errors
649 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
651 Role of the Moose (cont.)
652 =========================
683 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
685 Role of the Moose (cont.)
686 =========================
700 bark => "bark_sound",
716 * Not that common in practice
720 Composition parameters
721 Easier conflict resolution
722 Finer grained control
724 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
726 MOPs Mean Cleanliness
727 =====================
729 * Moose is based on `Class::MOP`
730 * Metaobject Protocol for Perl 5
731 * "makes an object for everything"
734 my $class = $obj->meta; # $obj's metaclass
735 my $meta = MyApp->meta; # MyApp's metaclass
736 my $emo = $obj->meta->meta; # even more meta!
738 warn $obj->meta->name;
741 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
743 Looking in From the Inside
744 ===========================
747 my $metaclass = $self->meta;
749 $metaclass->superclasses;
751 $metaclass->linearized_isa;
753 $metaclass->has_method("foo");
755 $metaclass->compute_all_applicable_attributes;
763 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
765 Looking in From the Inside (cont.)
766 ==================================
769 Moose::Meta::Class->create( Bar =>
771 superclasses => [ 'Foo' ],
773 Moose::Meta::Attribute->new( bar => ... ),
774 Moose::Meta::Attribute->new( baz => ... ),
777 calculate_bar => sub { ... },
778 construct_baz => sub { ... }
782 my $anon_meta = Moose::Meta::Class->create_anon_class( ... );
787 Classes can be created programmatically
788 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
790 Looking in From the Inside (cont.)
791 ==================================
794 has foo => ( is => "rw" );
796 __PACKAGE__->meta->add_attribute(
802 * Moose is just sugar
803 * The MOP does the hard work
805 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
810 * Metaclassses control class behavior
814 metaclass => 'Collection::Array',
819 * custom attribute metaclasses
820 * change how attributes work
821 * Many customizable parts
822 * `Moose::Meta::Class`, `Moose::Meta::Attribute, ``Moose::Meta::Method`, `Moose::Meta::Method::Accessor` `Moose::Meta::Instance`, `Moose::Meta::Role`, `Moose::Meta::TypeConstraint`, …,
824 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
826 Working in the Meta Frame
827 =========================
830 * CMS for a flash website
833 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
835 Working in the Meta Frame (cont.)
836 =================================
842 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
844 Working in the Meta Frame (cont.)
845 =================================
847 * Step 2.1. Client's XML schemas → Moose classes
848 * Automatic class definitions
849 * High level objects in runtime
854 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
856 Working in the Meta Frame (cont.)
857 =================================
859 * Step 2.2. Meta descriptions
860 * Extend the metaclasses
861 * Embed additional information
865 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
867 Working in the Meta Frame (cont.)
868 =================================
870 * Step 2.3 Introspection goodness
871 * Generic web frontend
872 * Object introspection based
877 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
883 * `MooseX::Compile` is in the works
884 * Some features are slow
885 * but you only pay for what you use
886 * Extending non-Hash based classes is tricky.
887 * but possible: `MooseX::GlobRef::Object`
889 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
895 * attribute storage/access
901 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
903 Benefits of Moose (cont.)
904 =========================
909 * less code means fewer bugs
911 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
913 Benefits of Moose (cont.)
914 =========================
917 * Moose is very well tested
918 * no need to check accessor behavior, etc
919 * focus on your code's purpose
920 * not that it is "assembled" correctly
921 * http://c2.com/cgi/wiki?IntentionNotAlgorithm
923 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
925 Benefits of Moose (cont.)
926 =========================
929 * declarative style is self documenting
930 * good signal to noise ratio
932 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
934 Benefits of Moose (cont.)
935 =========================
937 * Meta object protocol
938 * Cleans up Perl's OO
939 * Provides introspection
940 * Enables powerful abstractions
942 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
944 Benefits of Moose (cont.)
945 =========================
948 * All the cool kids hang out on #moose
949 * Smart sounding buzzwords
953 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
958 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
964 package Units::Bytes;
969 sub kilobytes { $_[0] * 1024 }
970 sub megabytes { $_[0] * 1024->kilobytes }
971 sub gigabytes { $_[0] * 1024->megabytes }
972 sub terabytes { $_[0] * 1024->gigabytes }
974 Moose::Autobox->mixin_additional_role(
975 SCALAR => 'Units::Bytes',
979 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
986 use Moose::Autobox; # autoboxing is lexical
988 is(5->bytes, 5, '... got 5 bytes');
989 is(5->kilobytes, 5120, '... got 5 kilobytes');
990 is(2->megabytes, 2097152, '... got 2 megabytes');
991 is(1->gigabytes, 1073741824, '... got 1 gigabyte');
992 is(2->terabytes, 2199023255552, '... got 2 terabytes');
995 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
1000 * Moose One Liners with `oose.pm`
1003 perl -Moose -e 'has foo => ( is=> "rw" ); Class->new( foo => 1 )'
1006 * Useful for testing if something works
1008 * `Devel::REPL` is cooler though ;-)
1010 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
1018 use MooseX::AttributeHelpers;
1021 traits => [qw(Counter)],
1022 provides => { inc => "increment_count" },
1026 shift->yield('increment');
1029 event increment => sub {
1032 warn "Count is now " . $self->count;
1034 $self->increment_count;
1035 $self->yield('increment') unless $self->count > 3;
1038 Counter->new( count => 0 );
1043 * Every object has a `POE::Session`
1044 * `event` declares POE object states
1046 ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
1051 * Slides written by:
1056 * Slides deleted by: