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