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