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