Commit | Line | Data |
720accfe |
1 | Title: Moose |
2 | Location: YAPC::Asia::2008 |
3 | Presenter: Yuval Kogman |
4 | Date: 2008 |
5 | Theme: moose |
6 | |
7 | Moose Is Not |
8 | ============ |
9 | |
10 | * Experimental |
11 | * A toy |
12 | * Just another accessor builder |
13 | * A source filter |
14 | * Perl black magic |
15 | * Perl 6 in Perl 5 |
16 | |
17 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
18 | |
19 | Moose Is |
20 | ======== |
21 | |
22 | * A complete modern object framework for Perl |
23 | |
24 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
25 | |
26 | Moose Is |
27 | ======== |
28 | |
29 | * Syntactic Sugar for `Class::MOP` |
30 | * Rich ancestry |
31 | * CLOS (Common Lisp Object System) |
32 | * Smalltalk |
33 | * Alces latifrons |
34 | * Perl 6 |
35 | * … |
36 | * Stable & Production ready |
37 | * Polite, incremental |
38 | |
39 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
40 | |
41 | A Simple Example |
42 | ================ |
43 | |
44 | <pre><code> |
45 | package Person; |
46 | |
47 | use strict; |
48 | use warnings; |
49 | |
50 | sub new { |
51 | my ( $class, @args ) = @_; |
52 | |
53 | @args = %{$args[0]} if @args == 1; |
54 | |
55 | return bless { |
56 | @args, |
57 | }, $class; |
58 | } |
59 | |
60 | sub name { |
61 | my ($self, @args) = @_; |
62 | $self->{name} = $args[0] if @args; |
63 | return $self->{name}; |
64 | } |
65 | |
66 | sub age { |
67 | my ($self, @args) = @_; |
68 | $self->{age} = $args[0] if @args; |
69 | return $self->{age}; |
70 | } |
71 | |
72 | 1; |
73 | </code></pre> |
74 | |
75 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
76 | |
77 | A Simple Moose Example |
78 | ====================== |
79 | |
80 | <pre><code> |
81 | package Person; |
82 | use Moose; |
83 | |
84 | has name => (is => 'rw'); |
85 | has age => (is => 'rw'); |
86 | |
87 | 1; |
88 | </code></pre> |
89 | |
90 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
91 | |
92 | A Simple Moose Example (cont.) |
93 | ============================== |
94 | |
95 | * `use Moose;` |
96 | * imports keywords |
97 | * `use strict; use warnings;` |
98 | * `@ISA = qw(Moose::Object) unless @ISA` |
99 | |
100 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
101 | |
102 | A Simple Moose Example (cont.) |
103 | ============================== |
104 | |
105 | * `has` declares attributes |
106 | * generates accessors |
107 | * `is => 'rw'` → read/write accessor |
108 | * `is => 'ro'` → read only accessor |
109 | * `writer`, `reader` |
110 | |
111 | * `new` inherited from `Moose::Object` |
112 | |
113 | |
114 | ########## |
115 | |
116 | Now we're going to discuss more features of the attributes |
117 | |
118 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
119 | |
120 | Variations on a Moose Example |
121 | ============================= |
122 | |
123 | <pre><code> |
124 | package Manager; |
125 | use Moose; |
126 | |
127 | has name => ( |
128 | is => 'rw', |
129 | isa => 'Str', |
130 | default => 'Bob' |
131 | ); |
132 | |
133 | has staff => ( |
134 | is => 'ro', |
135 | isa => 'ArrayRef', |
136 | lazy => 1, |
137 | default => sub { [qw(Bob Alice Tim)] }, |
138 | ); |
139 | </code></pre> |
140 | ########## |
141 | |
142 | Adds default, isa |
143 | |
144 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
145 | |
146 | Variations on a Moose Example (cont.) |
147 | ===================================== |
148 | |
149 | * `default` is a |
150 | * code reference |
151 | * or non-reference (numbers, strings) |
152 | * used when no parameter is given to `new` |
153 | |
154 | * `lazy` delays `default` |
155 | * called on first usage of `$object->staff` |
156 | * not inside `new` |
157 | |
158 | ########## |
159 | discusses default |
160 | |
161 | non refs make accidental sharing hard |
162 | |
163 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
164 | |
165 | Variations on a Moose Example (cont.) |
166 | ===================================== |
167 | |
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 |
172 | <pre><code> |
173 | has 'date' => (isa => 'DateTime'); # DWIM |
174 | </code></pre> |
175 | ########## |
176 | |
177 | isa, type constraints |
178 | |
179 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
180 | |
181 | Typical Family |
182 | ============== |
183 | |
184 | * Types have a hierarchy |
185 | * `Item` ⊃ `Defined` ⊃ `Ref` ⊃ `Object` |
186 | |
187 | <pre><code> |
188 | subtype 'Ref' |
189 | => as 'Defined' |
190 | => where { ref($_) }; |
191 | |
192 | subtype 'Object' |
193 | => as 'Ref' |
194 | => where { blessed($_) } |
195 | </code></pre> |
196 | ########## |
197 | |
198 | type hierarchy |
199 | |
200 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
201 | |
202 | Conventional Delegates |
203 | ====================== |
204 | |
205 | <pre><code> |
206 | package Employee; |
207 | use Moose; |
208 | extends qw(Person); |
209 | |
210 | has manager => ( |
211 | is => 'ro', |
212 | isa => 'Manager', |
213 | handles => { |
214 | manager_name => 'name', |
215 | coworkers => 'staff', |
216 | } |
217 | ); |
218 | </code></pre> |
219 | |
220 | * manager `handles` certain methods for `Employee` |
221 | * `$emp->coworkers` == `$emp->manager->staff ` |
222 | |
223 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
224 | |
225 | Conventional Delegates (cont.) |
226 | ============================== |
227 | |
228 | <pre><code> |
229 | has phone => ( |
230 | ... |
231 | handles => [qw(number extension)], |
232 | ); |
233 | </code></pre> |
234 | |
235 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
236 | |
237 | Conventional Delegates (cont.) |
238 | ============================== |
239 | |
240 | <pre><code> |
241 | has phone => ( |
242 | ... |
243 | isa => "Phone", |
244 | handles => qr/^[a-z]\w+$/, |
245 | ); |
246 | </code></pre> |
247 | |
248 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
249 | |
250 | Conventional Delegates (cont.) |
251 | ============================== |
252 | |
253 | <pre><code> |
254 | has phone => ( |
255 | ... |
256 | handles => "Dialing", # a role |
257 | ); |
258 | </code></pre> |
259 | |
260 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
261 | |
262 | UnConventional Delegates |
263 | ======================== |
264 | |
265 | <pre><code> |
266 | package Company; |
267 | use Moose; |
268 | use MooseX::AttributeHelpers; |
269 | |
270 | has employees => ( |
271 | metaclass => 'Collection::Array', |
272 | isa => 'ArrayRef[Employees]', |
273 | is => 'rw', |
274 | provides => { |
275 | push => 'add_employee', |
276 | pop => 'remove_employee', |
277 | count => 'number_of_employees', |
278 | empty => 'any_employees', |
279 | }, |
280 | ); |
281 | </code></pre> |
282 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
283 | |
284 | Modified Methods |
285 | ================ |
286 | |
287 | <pre><code> |
288 | before 'employees' => sub { warn 'calling employees' }; |
289 | |
290 | after 'employees' => sub { warn 'finished calling employees' }; |
291 | </code></pre> |
292 | |
293 | * Pre/Post hooks |
294 | * Get a copy of `@_` |
295 | * Return value is ignored |
296 | |
297 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
298 | |
299 | Modified Methods (cont.) |
300 | ======================== |
301 | |
302 | <pre><code> |
303 | around 'employees' => sub { |
304 | my ($next, $self, @args) = @_; |
305 | ... |
306 | my @return = $self->$next(@args); |
307 | ... |
308 | return @return; |
309 | }; |
310 | </code></pre> |
311 | |
312 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
313 | |
314 | Modified Methods (cont.) |
315 | ======================== |
316 | |
317 | <pre><code> |
318 | package Employee; |
319 | use Moose; |
320 | |
321 | sub do_work { |
322 | my $self = shift; |
323 | |
324 | $self->punch_in; |
325 | |
326 | inner(); # call subclass here |
327 | |
328 | $self->punch_out; |
329 | } |
330 | </code></pre> |
331 | |
332 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
333 | |
334 | Modified Methods (cont.) |
335 | ======================== |
336 | |
337 | <pre><code> |
338 | package Employee::Chef; |
339 | use Moose; |
340 | |
341 | extends qw(Employee); |
342 | |
343 | augment do_work => sub { |
344 | my $self = shift; |
345 | |
346 | while ( @burgers ) { |
347 | $self->flip_burger(shift @burgers); |
348 | } |
349 | }; |
350 | |
351 | $chef->do_work; # punch in, flip burgers, punch out |
352 | </code></pre> |
353 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
354 | |
355 | Some Type of Coercion |
356 | ===================== |
357 | |
358 | <pre><code> |
359 | package Employee; |
360 | use Moose; |
361 | use Moose::Util::TypeConstraints; |
362 | extends qw(Person); |
363 | |
364 | class_type 'Manager'; |
365 | |
366 | coerce 'Manager' => ( |
367 | from 'Str' => via { Manager->new( name => $_ ) }, |
368 | ); |
369 | |
370 | has manager => ( |
371 | is => 'ro', |
372 | isa => 'Manager', |
373 | required => 1, |
374 | coerce => 1, |
375 | ); |
376 | </code></pre> |
377 | |
378 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
379 | |
380 | Some Type of Coercion (cont.) |
381 | ============================= |
382 | |
383 | <pre><code> |
384 | # import type constraint keywords |
385 | use Moose::Util::TypeConstraints; |
386 | |
387 | |
388 | # define Manager, a subtype of Object |
389 | class_type "Manager"; |
390 | |
391 | |
392 | # define the conversion |
393 | ... via { Manager->new( name => $_ ) } |
394 | |
395 | |
396 | # enable it per attribute |
397 | has manager => ( |
398 | ... |
399 | coerce => 1, |
400 | ); |
401 | </code></pre> |
402 | |
403 | ########## |
404 | |
405 | breakdown of the example |
406 | |
407 | class types are automatically created for all Moose classes |
408 | |
409 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
410 | |
411 | Some Type of Digression |
412 | ======================= |
413 | |
414 | <pre><code> |
415 | has employees => ( |
416 | is => 'rw', |
417 | isa => 'ArrayRef[Employee]', |
418 | ); |
419 | |
420 | has shopping_carts => ( |
421 | is => 'rw', |
422 | isa => 'ArrayRef[ArrayRef[ShinyBead]]' |
423 | ); |
424 | </code></pre> |
425 | |
426 | ########## |
427 | |
428 | Going to go into features of the type system for a bit |
429 | |
430 | Parametrized types |
431 | |
432 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
433 | Some Type of Digression (cont.) |
434 | =============================== |
435 | |
436 | <pre><code> |
437 | has language => ( |
438 | is => 'rw', |
439 | isa => 'English | Welsh | Scots | Gaelic', |
440 | ); |
441 | |
442 | has member => ( |
443 | is => 'rw', |
444 | isa => 'Employee | ArrayRef[ Employee | Group ]', |
445 | ); |
446 | </code></pre> |
447 | |
448 | ########## |
449 | |
450 | Union types |
451 | |
452 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
453 | |
454 | Some Type of Digression (cont.) |
455 | =============================== |
456 | |
457 | <pre><code> |
458 | package Foo; |
459 | use Moose; |
460 | use Moose::Util::TypeConstraints; |
461 | |
462 | use Test::Deep qw(eq_deeply ...); |
463 | |
464 | type 'SomethingTricky' => where { |
465 | eq_deeply( $_, ... ); |
466 | }; |
467 | |
468 | has 'bar' => ( |
469 | is => 'rw', |
470 | isa => 'SomethingTricky', |
471 | ); |
472 | </code></pre> |
473 | |
474 | ########## |
475 | |
476 | Test::Deep custom validator |
477 | |
478 | Can use any validation from the CPAN |
479 | |
480 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
481 | |
482 | Some Parametrized Type of Coercion |
483 | ================================== |
484 | |
485 | <pre><code> |
486 | use Moose::Util::TypeConstraints; |
487 | |
488 | subtype 'ArrayRef[Employee]' => as 'ArrayRef'; |
489 | |
490 | coerce 'ArrayRef[Employee]' => ( |
491 | from 'ArrayRef[Str]' via { |
492 | [ map { Employee->new( name => $_ ) } @$_ ] |
493 | }, |
494 | ); |
495 | |
496 | has staff => ( |
497 | isa => 'ArrayRef[Employee]', |
498 | coerce => 1, |
499 | ); |
500 | </code></pre> |
501 | |
502 | ########## |
503 | |
504 | coerce parametrized ArrayRef[Employee] from ArrayRef[Str] |
505 | |
506 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
507 | |
508 | Role of the Moose |
509 | ================= |
510 | |
511 | * A role is like a… |
512 | * Java Interface: safe |
513 | * mixin: useful |
514 | * A role is for small reusable behaviors |
515 | * better than using a multiple inheritence |
516 | |
517 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
518 | |
519 | Role of the Moose (cont.) |
520 | ========================= |
521 | |
522 | * Roles on the CPAN: |
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, |
528 | |
529 | ########## |
530 | |
531 | Some examples of small reusable behaviors |
532 | |
533 | Param is good for interacting with e.g. CGI::Expand or similar modules |
534 | |
535 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
536 | |
537 | Role of the Moose (cont.) |
538 | ========================= |
539 | |
540 | <pre><code> |
541 | package Minion; |
542 | use Moose; |
543 | |
544 | extends qw(Employee); |
545 | |
546 | with qw(Salaried::Hourly); |
547 | |
548 | |
549 | package Boss; |
550 | use Moose; |
551 | |
552 | extends qw(Employee); |
553 | |
554 | with qw(Salaried::Monthly); |
555 | |
556 | </code></pre> |
557 | |
558 | * `with` adds roles into your class |
559 | * `Salaried::Hourly` was added to `Minion` |
560 | |
561 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
562 | |
563 | Role of the Moose (cont.) |
564 | ========================= |
565 | |
566 | <pre><code> |
567 | package Salaried; |
568 | use Moose::Role; |
569 | |
570 | requires 'paycheck_amount'; |
571 | </code></pre> |
572 | |
573 | * Just an interface |
574 | |
575 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
576 | |
577 | Role of the Moose (cont.) |
578 | ========================= |
579 | |
580 | <pre><code> |
581 | package Salaried::Hourly; |
582 | use Moose::Role; |
583 | |
584 | with qw(Salaried); |
585 | |
586 | has hourly_rate => ( |
587 | isa => "Num", |
588 | is => "rw", |
589 | required => 1, |
590 | ); |
591 | |
592 | has logged_hours => ( |
593 | isa => "Num", |
594 | is => "rw", |
595 | default => 0, |
596 | ); |
597 | |
598 | # satisfy the Salaried interface: |
599 | sub paycheck_amount { |
600 | my $self = shift; |
601 | $self->logged_hours * $self->hourly_rate; |
602 | } |
603 | |
604 | </code></pre> |
605 | |
606 | * More than an interface |
607 | |
608 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
609 | |
610 | Role of the Moose (cont.) |
611 | ========================= |
612 | |
613 | * More than Java Interfaces |
614 | * Interfaces are behavior "contracts" |
615 | * Roles can also have code |
616 | |
617 | ########## |
618 | roles can have attributes and methods |
619 | roles provide behavior, not just interface |
620 | |
621 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
622 | |
623 | Role of the Moose (cont.) |
624 | ========================= |
625 | |
626 | * Role Composition |
627 | * Not inheritence |
628 | * Symmetric |
629 | * Unordered |
630 | |
631 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
632 | |
633 | Role of the Moose (cont.) |
634 | ========================= |
635 | |
636 | * Role Composition |
637 | * Less ambiguity |
638 | * Compile time errors |
639 | * …And ways to fix them |
640 | |
641 | ########## |
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 |
644 | |
645 | roles cause errors at compile time, unlike multiple inheritence |
646 | |
647 | roles also provide easy ways to fix the errors |
648 | |
649 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
650 | |
651 | Role of the Moose (cont.) |
652 | ========================= |
653 | |
654 | <pre><code> |
655 | package Ballet; |
656 | use Moose::Role; |
657 | |
658 | sub dance { |
659 | pirouette(); |
660 | } |
661 | |
662 | package Punk; |
663 | use Moose::Role |
664 | |
665 | sub dance { |
666 | MOSH!!!11one(); |
667 | } |
668 | |
669 | package Foo; |
670 | use Moose; |
671 | |
672 | # KABOOM: |
673 | with qw( |
674 | Punk |
675 | Ballet |
676 | ); |
677 | </code></pre> |
678 | |
679 | ########## |
680 | |
681 | conflicts |
682 | |
683 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
684 | |
685 | Role of the Moose (cont.) |
686 | ========================= |
687 | |
688 | <pre><code> |
689 | package Ent::Puppy; |
690 | use Moose; |
691 | |
692 | with ( |
693 | Tree => { |
694 | alias => { |
695 | bark => "tree_bark", |
696 | }, |
697 | }, |
698 | Dog => { |
699 | alias => { |
700 | bark => "bark_sound", |
701 | } |
702 | }, |
703 | ); |
704 | |
705 | sub bark { |
706 | my $self = shift; |
707 | |
708 | if ( $condition ) { |
709 | $self->tree_bark; |
710 | } else { |
711 | $self->bark_sound; |
712 | } |
713 | } |
714 | </code></pre> |
715 | |
716 | * Not that common in practice |
717 | |
718 | ########## |
719 | |
720 | Composition parameters |
721 | Easier conflict resolution |
722 | Finer grained control |
723 | |
724 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
725 | |
726 | MOPs Mean Cleanliness |
727 | ===================== |
728 | |
729 | * Moose is based on `Class::MOP` |
730 | * Metaobject Protocol for Perl 5 |
731 | * "makes an object for everything" |
732 | |
733 | <pre><code> |
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! |
737 | |
738 | warn $obj->meta->name; |
739 | </code></pre> |
740 | |
741 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
742 | |
743 | Looking in From the Inside |
744 | =========================== |
745 | |
746 | <pre><code> |
747 | my $metaclass = $self->meta; |
748 | |
749 | $metaclass->superclasses; |
750 | |
751 | $metaclass->linearized_isa; |
752 | |
753 | $metaclass->has_method("foo"); |
754 | |
755 | $metaclass->compute_all_applicable_attributes; |
756 | |
757 | # … lots more |
758 | </code></pre> |
759 | ########## |
760 | |
761 | simple introspection |
762 | |
763 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
764 | |
765 | Looking in From the Inside (cont.) |
766 | ================================== |
767 | |
768 | <pre><code> |
769 | Moose::Meta::Class->create( Bar => |
770 | version => '0.01', |
771 | superclasses => [ 'Foo' ], |
772 | attributes => [ |
773 | Moose::Meta::Attribute->new( bar => ... ), |
774 | Moose::Meta::Attribute->new( baz => ... ), |
775 | ], |
776 | methods => { |
777 | calculate_bar => sub { ... }, |
778 | construct_baz => sub { ... } |
779 | }, |
780 | ); |
781 | |
782 | my $anon_meta = Moose::Meta::Class->create_anon_class( ... ); |
783 | </code></pre> |
784 | |
785 | ########## |
786 | |
787 | Classes can be created programmatically |
788 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
789 | |
790 | Looking in From the Inside (cont.) |
791 | ================================== |
792 | |
793 | <pre><code> |
794 | has foo => ( is => "rw" ); |
795 | |
796 | __PACKAGE__->meta->add_attribute( |
797 | "foo", |
798 | is => "rw", |
799 | ); |
800 | </code></pre> |
801 | |
802 | * Moose is just sugar |
803 | * The MOP does the hard work |
804 | |
805 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
806 | |
807 | The Metaclass Tango |
808 | =================== |
809 | |
810 | * Metaclassses control class behavior |
811 | |
812 | <pre><code> |
813 | has employees => ( |
814 | metaclass => 'Collection::Array', |
815 | ... |
816 | ); |
817 | </code></pre> |
818 | |
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`, …, |
823 | |
824 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
825 | |
826 | Working in the Meta Frame |
827 | ========================= |
828 | |
829 | * `$work` project: |
830 | * CMS for a flash website |
831 | * Content is in XML |
832 | |
833 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
834 | |
835 | Working in the Meta Frame (cont.) |
836 | ================================= |
837 | |
838 | * Step 1. use Moose |
839 | * Step 2. ??? |
840 | * Step 3. Profit! |
841 | |
842 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
843 | |
844 | Working in the Meta Frame (cont.) |
845 | ================================= |
846 | |
847 | * Step 2.1. Client's XML schemas → Moose classes |
848 | * Automatic class definitions |
849 | * High level objects in runtime |
850 | * XML storage backed |
851 | * SAX → Moose |
852 | * Moose → SAX |
853 | |
854 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
855 | |
856 | Working in the Meta Frame (cont.) |
857 | ================================= |
858 | |
859 | * Step 2.2. Meta descriptions |
860 | * Extend the metaclasses |
861 | * Embed additional information |
862 | * field types |
863 | * access control |
864 | |
865 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
866 | |
867 | Working in the Meta Frame (cont.) |
868 | ================================= |
869 | |
870 | * Step 2.3 Introspection goodness |
871 | * Generic web frontend |
872 | * Object introspection based |
873 | * HTML view |
874 | * Editing widgets |
875 | * Clean, extensible |
876 | |
877 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
878 | |
879 | Drawbacks of Moose |
880 | ================== |
881 | |
882 | * Load time |
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` |
888 | |
889 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
890 | |
891 | Benefits of Moose |
892 | ================= |
893 | |
894 | * Less boilerplate |
895 | * attribute storage/access |
896 | * construction |
897 | * destruction |
898 | * verification |
899 | * … |
900 | |
901 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
902 | |
903 | Benefits of Moose (cont.) |
904 | ========================= |
905 | |
906 | * Shorter |
907 | * less reading |
908 | * less writing |
909 | * less code means fewer bugs |
910 | |
911 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
912 | |
913 | Benefits of Moose (cont.) |
914 | ========================= |
915 | |
916 | * Less testing |
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 |
922 | |
923 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
924 | |
925 | Benefits of Moose (cont.) |
926 | ========================= |
927 | |
928 | * More readable |
929 | * declarative style is self documenting |
930 | * good signal to noise ratio |
931 | |
932 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
933 | |
934 | Benefits of Moose (cont.) |
935 | ========================= |
936 | |
937 | * Meta object protocol |
938 | * Cleans up Perl's OO |
939 | * Provides introspection |
940 | * Enables powerful abstractions |
941 | |
942 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
943 | |
944 | Benefits of Moose (cont.) |
945 | ========================= |
946 | |
947 | * It's the new black |
948 | * All the cool kids hang out on #moose |
949 | * Smart sounding buzzwords |
950 | * Chicks dig antlers |
951 | * Ruby is so 2007 |
952 | |
953 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
954 | |
955 | Bonus Material |
956 | ============== |
957 | |
958 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
959 | |
960 | Autobox |
961 | ======= |
962 | |
963 | <pre><code> |
964 | package Units::Bytes; |
965 | use Moose::Role; |
966 | use Moose::Autobox; |
967 | |
968 | sub bytes { $_[0] } |
969 | sub kilobytes { $_[0] * 1024 } |
970 | sub megabytes { $_[0] * 1024->kilobytes } |
971 | sub gigabytes { $_[0] * 1024->megabytes } |
972 | sub terabytes { $_[0] * 1024->gigabytes } |
973 | |
974 | Moose::Autobox->mixin_additional_role( |
975 | SCALAR => 'Units::Bytes', |
976 | ); |
977 | </code></pre> |
978 | |
979 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
980 | |
981 | Autobox (cont.) |
982 | =============== |
983 | |
984 | <pre><code> |
985 | use Units::Bytes; |
986 | use Moose::Autobox; # autoboxing is lexical |
987 | |
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'); |
993 | </code></pre> |
994 | |
995 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
996 | |
997 | perl -Moose |
998 | =========== |
999 | |
1000 | * Moose One Liners with `oose.pm` |
1001 | |
1002 | <pre><code> |
1003 | perl -Moose -e 'has foo => ( is=> "rw" ); Class->new( foo => 1 )' |
1004 | </code></pre> |
1005 | |
1006 | * Useful for testing if something works |
1007 | * Helpful on IRC |
1008 | * `Devel::REPL` is cooler though ;-) |
1009 | |
1010 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
1011 | |
1012 | MooseX::POE |
1013 | =========== |
1014 | |
1015 | <pre><code> |
1016 | package Counter; |
1017 | use MooseX::POE; |
1018 | use MooseX::AttributeHelpers; |
1019 | |
1020 | has count => ( |
1021 | traits => [qw(Counter)], |
1022 | provides => { inc => "increment_count" }, |
1023 | ); |
1024 | |
1025 | sub START { |
1026 | shift->yield('increment'); |
1027 | } |
1028 | |
1029 | event increment => sub { |
1030 | my $self = shift; |
1031 | |
1032 | warn "Count is now " . $self->count; |
1033 | |
1034 | $self->increment_count; |
1035 | $self->yield('increment') unless $self->count > 3; |
1036 | }; |
1037 | |
1038 | Counter->new( count => 0 ); |
1039 | POE::Kernel->run(); |
1040 | </code></pre> |
1041 | |
1042 | * PoCos made easy |
1043 | * Every object has a `POE::Session` |
1044 | * `event` declares POE object states |
1045 | |
1046 | ✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------ |
1047 | |
1048 | Fin |
1049 | === |
1050 | |
1051 | * Slides written by: |
1052 | * Chris Prather |
1053 | * Stevan Little |
1054 | * Robert Boone |
1055 | |
1056 | * Slides deleted by: |
1057 | * Yuval Kogman |