Commit | Line | Data |
b751d33f |
1 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
2 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
3 | |
4 | <html xmlns="http://www.w3.org/1999/xhtml"> |
5 | |
6 | <head> |
7 | <title>Introduction to Moose</title> |
8 | <!-- metadata --> |
9 | <meta name="generator" content="S5" /> |
10 | <meta name="version" content="S5 1.2a2" /> |
11 | <meta name="author" content="Eric A. Meyer" /> |
12 | <meta name="company" content="Complex Spiral Consulting" /> |
13 | <!-- configuration parameters --> |
14 | <meta name="defaultView" content="slideshow" /> |
15 | <meta name="controlVis" content="hidden" /> |
16 | <!-- style sheet links --> |
17 | <link rel="stylesheet" href="ui/default/slides.css" type="text/css" media="projection" id="slideProj" /> |
18 | <link rel="stylesheet" href="ui/default/outline.css" type="text/css" media="screen" id="outlineStyle" /> |
19 | <link rel="stylesheet" href="ui/default/print.css" type="text/css" media="print" id="slidePrint" /> |
20 | <link rel="stylesheet" href="ui/default/opera.css" type="text/css" media="projection" id="operaFix" /> |
21 | <!-- embedded styles --> |
22 | <style type="text/css" media="all"> |
23 | .imgcon {width: 525px; margin: 0 auto; padding: 0; text-align: center;} |
24 | #anim {width: 270px; height: 320px; position: relative; margin-top: 0.5em;} |
25 | #anim img {position: absolute; top: 42px; left: 24px;} |
26 | img#me01 {top: 0; left: 0;} |
27 | img#me02 {left: 23px;} |
28 | img#me04 {top: 44px;} |
29 | img#me05 {top: 43px;left: 36px;} |
30 | </style> |
31 | <!-- S5 JS --> |
32 | <script src="ui/default/slides.js" type="text/javascript"></script> |
33 | <link rel="stylesheet" href="ui/custom.css" type="text/css" /> |
34 | </head> |
35 | <body> |
36 | |
37 | <div class="layout"> |
38 | <div id="controls"><!-- DO NOT EDIT --></div> |
39 | <div id="currentSlide"><!-- DO NOT EDIT --></div> |
40 | <div id="header"></div> |
41 | <div id="footer"> |
42 | <h2>Introduction to Moose</h2> |
43 | </div> |
44 | </div> |
45 | |
46 | <div class="presentation"> |
47 | |
48 | <div class="slide"> |
49 | <h1>Introduction to Moose</h1> |
50 | <h2>YAPC 2009</h2> |
51 | </div> |
52 | |
53 | <div class="slide"> |
54 | <h1>Moose Summed Up</h1> |
55 | |
56 | <ul> |
57 | <li><strong>Declarative</strong> OO sugar</li> |
58 | <li>Introspectable</li> |
59 | <li>Extensible</li> |
60 | </ul> |
61 | </div> |
62 | |
63 | <div class="slide"> |
64 | <h1>Concepts</h1> |
65 | |
66 | <ul> |
67 | <li>Moose builds on Perl 5's native OO</li> |
68 | <li>Borrows ideas from other languages, notably Perl 6</li> |
69 | <li>Provides semantics for common operations</li> |
70 | </ul> |
71 | </div> |
72 | |
73 | <div class="slide"> |
74 | <h1>Classes</h1> |
75 | |
76 | <ul> |
77 | <li> |
78 | Classes have ... |
79 | <ul> |
80 | <li>Attributes</li> |
81 | <li>Methods</li> |
82 | <li>Superclasses</li> |
83 | <li>Method modifiers</li> |
84 | <li>Constructor and destructor</li> |
85 | <li>One metaclass object</li> |
86 | </ul> |
87 | </li> |
88 | <li>Classes do roles</li> |
89 | </ul> |
90 | </div> |
91 | |
92 | <div class="slide"> |
93 | <h1>Class Example</h1> |
94 | |
95 | <pre><code>package Person; |
96 | <span class="highlight">use Moose;</span></code></pre> |
97 | |
98 | <ul> |
99 | <li>Poof, a Moose-based class!</li> |
100 | </ul> |
101 | </div> |
102 | |
103 | <div class="slide"> |
104 | <h1>Attributes</h1> |
105 | |
106 | <ul> |
107 | <li>Aka property, slot, field, member variable</li> |
108 | <li>A piece of data owned by an object</li> |
109 | </ul> |
110 | </div> |
111 | |
112 | <div class="slide"> |
113 | <h1>Attributes</h1> |
114 | |
115 | <ul> |
116 | <li> |
117 | Attributes have ... |
118 | <ul> |
119 | <li>Access-control (read-only vs read-write)</li> |
120 | <li>An optional type</li> |
121 | <li>Accessor methods</li> |
122 | <li>Delegation methods</li> |
123 | <li>Optional default value</li> |
124 | <li>Many more features</li> |
125 | </ul> |
126 | </li> |
127 | <li>Stored in the object, but don't worry about that</li> |
128 | </ul> |
129 | </div> |
130 | |
131 | <div class="slide"> |
132 | <h1>Attribute Example</h1> |
133 | |
134 | <pre><code>package Person; |
135 | use Moose; |
136 | |
137 | <span class="highlight">has 'first_name' => ( is => 'rw' );</span></code></pre> |
138 | |
139 | </div> |
140 | |
141 | <div class="slide"> |
142 | <h1>Methods</h1> |
143 | |
144 | <ul> |
145 | <li>Nothing fancy here, just Perl subroutines</li> |
146 | </ul> |
147 | |
148 | <pre><code>package Person; |
149 | use Moose; |
150 | |
151 | <span class="highlight">sub greet { ... }</span></code></pre> |
152 | </div> |
153 | |
154 | <div class="slide"> |
155 | <h1>Roles</h1> |
156 | |
157 | <ul> |
158 | <li>Classes <strong>do</strong> (or consume) roles</li> |
159 | <li>Similar to mixins and Java interfaces</li> |
160 | </ul> |
161 | </div> |
162 | |
163 | <div class="slide"> |
164 | <h1>Roles</h1> |
165 | |
166 | <ul> |
167 | <li>Like classes, can have attributes, methods, do roles</li> |
168 | <li>Roles can require methods</li> |
169 | <li>Roles are composed (flattened) into classes</li> |
170 | </ul> |
171 | </div> |
172 | |
173 | <div class="slide"> |
174 | <h1>Role Example</h1> |
175 | |
176 | <pre><code>package HasPermissions; |
177 | <span class="highlight">use Moose::Role;</span> |
178 | |
179 | has is_admin => ( is => 'rw' );</code></pre> |
180 | </div> |
181 | |
182 | <div class="slide"> |
183 | <h1>Role Example</h1> |
184 | |
185 | <p> |
186 | And then ... |
187 | </p> |
188 | |
189 | <pre><code>package Person; |
190 | use Moose; |
191 | |
192 | <span class="highlight">with 'HasPermissions';</span></code></pre> |
193 | </div> |
194 | |
195 | <div class="slide"> |
196 | <h1>Method Modifiers</h1> |
197 | |
198 | <ul> |
199 | <li>AKA advice</li> |
200 | <li>"<strong>Before</strong> foo(), do this first"</li> |
201 | <li>"Do this <strong>after</strong> foo()</li> |
202 | <li>"Put this code <strong>around</strong> foo()"</li> |
203 | </ul> |
204 | </div> |
205 | |
206 | <div class="slide"> |
207 | <h1>Before & After</h1> |
208 | |
209 | <pre><code>before 'foo' |
210 | => sub { warn 'About to call foo()' }; |
211 | |
212 | after 'foo' |
213 | => sub { warn 'Leaving foo()' };</code></pre> |
214 | |
215 | </div> |
216 | |
217 | <div class="slide"> |
218 | <h1>Around</h1> |
219 | |
220 | <pre><code>around 'foo' => sub { |
221 | my $real_foo = shift; |
222 | my $self = shift; |
223 | |
224 | warn 'Just before foo()'; |
225 | my @return = |
226 | $self->$real_foo( @_, bar => 42 ); |
227 | |
228 | return ( @return, 'modify return values' ); |
229 | };</code></pre> |
230 | </div> |
231 | |
232 | <div class="slide"> |
233 | <h1>Type Constraints</h1> |
234 | |
235 | <ul> |
236 | <li>NOT A FULL-BLOWN TYPE SYSTEM!</li> |
237 | <li>But still darn useful</li> |
238 | <li>Constrain attribute values</li> |
239 | <li>Coerce from other types</li> |
240 | </ul> |
241 | </div> |
242 | |
243 | <div class="slide"> |
244 | <h1>Type Constraint Example</h1> |
245 | |
246 | <pre><code>package Person; |
247 | use Moose; |
248 | |
249 | has 'weight' => ( is => 'ro', <span class="highlight">isa => 'Int'</span> ); |
250 | |
251 | # kaboom |
252 | Person->new( weight => 'fat' );</code></pre> |
253 | </div> |
254 | |
255 | <div class="slide"> |
256 | <h1>Delegation</h1> |
257 | |
258 | <ul> |
259 | <li>Attributes can define delegations</li> |
260 | <li>Lets you hide some implementation details</li> |
261 | <li>Fewer objects to chase around</li> |
262 | </ul> |
263 | </div> |
264 | |
265 | <div class="slide"> |
266 | <h1>Delegation</h1> |
267 | |
268 | <pre><code>package Person; |
269 | use Moose; |
270 | |
271 | has 'blog_uri' => ( |
272 | is => 'rw', |
273 | isa => 'URI', |
274 | <span class="highlight">handles => { 'blog_hostname' => 'host' },</span> |
275 | ); |
276 | |
277 | <span class="highlight">$person->blog_hostname;</span> |
278 | # really calls $person->blog_uri->host |
279 | </div> |
280 | |
281 | <div class="slide"> |
282 | <h1>Constructors</h1> |
283 | |
284 | <ul> |
285 | <li>Moose creates <code>new()</code> for you</li> |
286 | <li>Provide an optional <code>BUILDARGS()</code> and <code>BUILD()</code></li> |
287 | </ul> |
288 | </div> |
289 | |
290 | <div class="slide"> |
291 | <h1>Destructors</h1> |
292 | |
293 | <ul> |
294 | <li>Provide an optional <code>DEMOLISH()</code></li> |
295 | </ul> |
296 | </div> |
297 | |
298 | <div class="slide"> |
299 | <h1>Moose Meta-API</h1> |
300 | |
301 | <ul> |
302 | <li>Answers questions like ... |
303 | <ul> |
304 | <li>What methods does this class have?</li> |
305 | <li>What are its parents?</li> |
306 | <li>What attributes does it have (including inherited attributes)?</li> |
307 | <li>What roles does it do?</li> |
308 | <li>Much, much, more</li> |
309 | </ul> |
310 | </li> |
311 | </ul> |
312 | </div> |
313 | |
314 | <div class="slide"> |
315 | <h1>Moose Meta-API</h1> |
316 | |
317 | <ul> |
318 | <li>Not just for introspection ... |
319 | <ul> |
320 | <li>Add methods, attributes, roles, etc</li> |
321 | <li>Extend and alter core features</li> |
322 | </ul> |
323 | </li> |
324 | </ul> |
325 | </div> |
326 | |
327 | <div class="slide"> |
328 | <h1>Why Moose?</h1> |
329 | |
330 | <ul> |
331 | <li>A quick bit of propoganda ...</li> |
332 | </ul> |
333 | </div> |
334 | |
335 | <div class="slide"> |
336 | <h1>With Moose</h1> |
337 | |
338 | <pre><code>package Person; |
339 | use Moose; |
340 | |
341 | has last_name => ( |
342 | is => 'rw', |
343 | isa => 'Str', |
344 | );</code></pre> |
345 | </div> |
346 | |
347 | <div class="slide"> |
348 | <h1>Without Moose</h1> |
349 | |
350 | <pre class="small"><code>package Person; |
351 | use strict; |
352 | use warnings; |
353 | use Carp 'confess'; |
354 | |
355 | sub new { |
356 | my $class = shift; |
357 | my %args = @_; |
358 | my $self = {}; |
359 | |
360 | if (exists $args{last_name}) { |
361 | confess "Attribute (last_name) does not pass the type constraint because: " |
362 | . "Validation failed for 'Str' with value $args{last_name}" |
363 | if ref($args{last_name}); |
364 | $self->{last_nane} = $args{last_name}; |
365 | } |
366 | |
367 | return bless $self, $class; |
368 | } |
369 | |
370 | sub last_name { |
371 | my $self = shift; |
372 | |
373 | if (@_) { |
374 | my $value = shift; |
375 | confess "Attribute (last_name) does not pass the type constraint because: " |
376 | . "Validation failed for 'Str' with value $value" |
377 | if ref($value); |
378 | $self->{last_name} = $value; |
379 | } |
380 | |
381 | return $self->{last_name}; |
382 | }</code></pre> |
383 | |
384 | </div> |
385 | |
386 | <div class="slide"> |
387 | <h1>Side by side</h1> |
388 | |
389 | <table class="side-by-side"> |
390 | <tr> |
391 | <td> |
392 | <pre><code>package Person; |
393 | use Moose; |
394 | |
395 | has last_name => ( |
396 | is => 'rw', |
397 | isa => 'Str', |
398 | );</code></pre> |
399 | </td> |
400 | <td> |
401 | <pre class="small"><code>package Person; |
402 | use strict; |
403 | use warnings; |
404 | use Carp 'confess'; |
405 | |
406 | sub new { |
407 | my $class = shift; |
408 | my %args = @_; |
409 | my $self = {}; |
410 | |
411 | if (exists $args{last_name}) { |
412 | confess "Attribute (last_name) does not pass the type constraint because: " |
413 | . "Validation failed for 'Str' with value $args{last_name}" |
414 | if ref($args{last_name}); |
415 | $self->{last_nane} = $args{last_name}; |
416 | } |
417 | |
418 | return bless $self, $class; |
419 | } |
420 | |
421 | sub last_name { |
422 | my $self = shift; |
423 | |
424 | if (@_) { |
425 | my $value = shift; |
426 | confess "Attribute (last_name) does not pass the type constraint because: " |
427 | . "Validation failed for 'Str' with value $value" |
428 | if ref($value); |
429 | $self->{last_name} = $value; |
430 | } |
431 | |
432 | return $self->{last_name}; |
433 | }</code></pre> |
434 | </td> |
435 | </tr> |
436 | </table> |
437 | |
438 | </div> |
439 | |
440 | <div class="slide"> |
441 | <h1>Side by side</h1> |
442 | |
443 | <table class="side-by-side"> |
444 | <tr> |
445 | <td> |
446 | <pre><code><span class="match-moose">package Person;</span> |
447 | use Moose; |
448 | |
449 | has last_name => ( |
450 | is => 'rw', |
451 | isa => 'Str', |
452 | );</code></pre> |
453 | </td> |
454 | <td> |
455 | <pre class="small"><code><span class="match-unsweet">package Person;</span> |
456 | use strict; |
457 | use warnings; |
458 | use Carp 'confess'; |
459 | |
460 | sub new { |
461 | my $class = shift; |
462 | my %args = @_; |
463 | my $self = {}; |
464 | |
465 | if (exists $args{last_name}) { |
466 | confess "Attribute (last_name) does not pass the type constraint because: " |
467 | . "Validation failed for 'Str' with value $args{last_name}" |
468 | if ref($args{last_name}); |
469 | $self->{last_nane} = $args{last_name}; |
470 | } |
471 | |
472 | return bless $self, $class; |
473 | } |
474 | |
475 | sub last_name { |
476 | my $self = shift; |
477 | |
478 | if (@_) { |
479 | my $value = shift; |
480 | confess "Attribute (last_name) does not pass the type constraint because: " |
481 | . "Validation failed for 'Str' with value $value" |
482 | if ref($value); |
483 | $self->{last_name} = $value; |
484 | } |
485 | |
486 | return $self->{last_name}; |
487 | }</code></pre> |
488 | </td> |
489 | </tr> |
490 | </table> |
491 | </div> |
492 | |
493 | <div class="slide"> |
494 | <h1>Side by side</h1> |
495 | |
496 | <table class="side-by-side"> |
497 | <tr> |
498 | <td> |
499 | <pre><code>package Person; |
500 | <span class="match-moose">use Moose;</span> |
501 | |
502 | has last_name => ( |
503 | is => 'rw', |
504 | isa => 'Str', |
505 | );</code></pre> |
506 | </td> |
507 | <td> |
508 | <pre class="small"><code>package Person; |
509 | <span class="match-unsweet">use strict; |
510 | use warnings; |
511 | use Carp 'confess'; |
512 | |
513 | sub new { |
514 | my $class = shift; |
515 | my %args = @_; |
516 | my $self = {};</span> |
517 | |
518 | if (exists $args{last_name}) { |
519 | confess "Attribute (last_name) does not pass the type constraint because: " |
520 | . "Validation failed for 'Str' with value $args{last_name}" |
521 | if ref($args{last_name}); |
522 | $self->{last_nane} = $args{last_name}; |
523 | } |
524 | |
525 | <span class="match-unsweet">return bless $self, $class; |
526 | }</span> |
527 | |
528 | sub last_name { |
529 | my $self = shift; |
530 | |
531 | if (@_) { |
532 | my $value = shift; |
533 | confess "Attribute (last_name) does not pass the type constraint because: " |
534 | . "Validation failed for 'Str' with value $value" |
535 | if ref($value); |
536 | $self->{last_name} = $value; |
537 | } |
538 | |
539 | return $self->{last_name}; |
540 | }</code></pre> |
541 | </td> |
542 | </tr> |
543 | </table> |
544 | </div> |
545 | |
546 | <div class="slide"> |
547 | <h1>Side by side</h1> |
548 | |
549 | <table class="side-by-side"> |
550 | <tr> |
551 | <td> |
552 | <pre><code>package Person; |
553 | use Moose; |
554 | |
555 | <span class="match-moose">has last_name => (</span> |
556 | is => 'rw', |
557 | isa => 'Str', |
558 | <span class="match-moose">);</span></code></pre> |
559 | </td> |
560 | <td> |
561 | <pre class="small"><code>package Person; |
562 | use strict; |
563 | use warnings; |
564 | use Carp 'confess'; |
565 | |
566 | sub new { |
567 | my $class = shift; |
568 | my %args = @_; |
569 | my $self = {}; |
570 | |
571 | <span class="match-unsweet">if (exists $args{last_name}) {</span> |
572 | confess "Attribute (last_name) does not pass the type constraint because: " |
573 | . "Validation failed for 'Str' with value $args{last_name}" |
574 | if ref($args{last_name}); |
575 | <span class="match-unsweet">$self->{last_nane} = $args{last_name}; |
576 | }</span> |
577 | |
578 | return bless $self, $class; |
579 | } |
580 | |
581 | sub last_name { |
582 | my $self = shift; |
583 | |
584 | if (@_) { |
585 | my $value = shift; |
586 | confess "Attribute (last_name) does not pass the type constraint because: " |
587 | . "Validation failed for 'Str' with value $value" |
588 | if ref($value); |
589 | $self->{last_name} = $value; |
590 | } |
591 | |
592 | return $self->{last_name}; |
593 | }</code></pre> |
594 | </td> |
595 | </tr> |
596 | </table> |
597 | </div> |
598 | |
599 | <div class="slide"> |
600 | <h1>Side by side</h1> |
601 | |
602 | <table class="side-by-side"> |
603 | <tr> |
604 | <td> |
605 | <pre><code>package Person; |
606 | use Moose; |
607 | |
608 | has last_name => ( |
609 | <span class="match-moose">is => 'rw',</span> |
610 | isa => 'Str', |
611 | );</code></pre> |
612 | </td> |
613 | <td> |
614 | <pre class="small"><code>package Person; |
615 | use strict; |
616 | use warnings; |
617 | use Carp 'confess'; |
618 | |
619 | sub new { |
620 | my $class = shift; |
621 | my %args = @_; |
622 | my $self = {}; |
623 | |
624 | if (exists $args{last_name}) { |
625 | confess "Attribute (last_name) does not pass the type constraint because: " |
626 | . "Validation failed for 'Str' with value $args{last_name}" |
627 | if ref($args{last_name}); |
628 | $self->{last_nane} = $args{last_name}; |
629 | } |
630 | |
631 | return bless $self, $class; |
632 | } |
633 | |
634 | <span class="match-unsweet">sub last_name { |
635 | my $self = shift; |
636 | |
637 | if (@_) { |
638 | my $value = shift;</span> |
639 | confess "Attribute (last_name) does not pass the type constraint because: " |
640 | . "Validation failed for 'Str' with value $value" |
641 | if ref($value); |
642 | <span class="match-unsweet">$self->{last_name} = $value; |
643 | } |
644 | |
645 | return $self->{last_name}; |
646 | }</span></code></pre> |
647 | </td> |
648 | </tr> |
649 | </table> |
650 | </div> |
651 | |
652 | <div class="slide"> |
653 | <h1>Side by side</h1> |
654 | |
655 | <table class="side-by-side"> |
656 | <tr> |
657 | <td> |
658 | <pre><code>package Person; |
659 | use Moose; |
660 | |
661 | has last_name => ( |
662 | is => 'rw', |
663 | <span class="match-moose">isa => 'Str',</span> |
664 | );</code></pre> |
665 | </td> |
666 | <td> |
667 | <pre class="small"><code>package Person; |
668 | use strict; |
669 | use warnings; |
670 | use Carp 'confess'; |
671 | |
672 | sub new { |
673 | my $class = shift; |
674 | my %args = @_; |
675 | my $self = {}; |
676 | |
677 | if (exists $args{last_name}) { |
678 | <span class="match-unsweet">confess "Attribute (last_name) does not pass the type constraint because: " |
679 | . "Validation failed for 'Str' with value $args{last_name}" |
680 | if ref($args{last_name});</span> |
681 | $self->{last_nane} = $args{last_name}; |
682 | } |
683 | |
684 | return bless $self, $class; |
685 | } |
686 | |
687 | sub last_name { |
688 | my $self = shift; |
689 | |
690 | if (@_) { |
691 | my $value = shift; |
692 | <span class="match-unsweet">confess "Attribute (last_name) does not pass the type constraint because: " |
693 | . "Validation failed for 'Str' with value $value" |
694 | if ref($value);</span> |
695 | $self->{last_name} = $value; |
696 | } |
697 | |
698 | return $self->{last_name}; |
699 | }</code></pre> |
700 | </td> |
701 | </tr> |
702 | </table> |
703 | </div> |
704 | |
705 | <div class="slide"> |
706 | <h1>Side by side</h1> |
707 | |
708 | <table class="side-by-side"> |
709 | <tr class="incremental"> |
710 | <td>5 lines</td> |
711 | <td>21 lines</td> |
712 | </tr> |
713 | <tr class="incremental"> |
714 | <td>92 characters</td> |
715 | <td>741 characters</td> |
716 | </tr> |
717 | <tr> |
718 | <td> |
719 | <pre><code>package Person; |
720 | use Moose; |
721 | |
722 | has last_name => ( |
723 | is => 'rw', |
724 | isa => 'Str', |
725 | );</code></pre> |
726 | </td> |
727 | <td> |
728 | <pre class="small"><code>package Person; |
729 | use strict; |
730 | use warnings; |
731 | use Carp 'confess'; |
732 | |
733 | sub new { |
734 | my $class = shift; |
735 | my %args = @_; |
736 | my $self = {}; |
737 | |
738 | if (exists $args{last_name}) { |
739 | confess "Attribute (last_name) does not pass the type constraint because: " |
740 | . "Validation failed for 'Str' with value $args{last_name}" |
741 | if ref($args{last_name}); |
742 | $self->{last_nane} = $args{last_name}; |
743 | } |
744 | |
745 | return bless $self, $class; |
746 | } |
747 | |
748 | sub last_name { |
749 | my $self = shift; |
750 | |
751 | if (@_) { |
752 | my $value = shift; |
753 | confess "Attribute (last_name) does not pass the type constraint because: " |
754 | . "Validation failed for 'Str' with value $value" |
755 | if ref($value); |
756 | $self->{last_name} = $value; |
757 | } |
758 | |
759 | return $self->{last_name}; |
760 | }</code></pre> |
761 | </td> |
762 | </tr> |
763 | </table> |
764 | </div> |
765 | |
766 | <div class="slide"> |
767 | <h1>Typo?</h1> |
768 | |
769 | <pre class="small"><code>sub new { |
770 | my $class = shift; |
771 | my %args = @_; |
772 | my $self = {}; |
773 | |
774 | if (exists $args{last_name}) { |
775 | confess "Attribute (last_name) does not pass the type constraint because: " |
776 | . "Validation failed for 'Str' with value $args{last_name}" |
777 | if ref($args{last_name}); |
778 | $self->{last_nane} = $args{last_name}; |
779 | } |
780 | |
781 | return bless $self, $class; |
782 | }</code></pre> |
783 | </div> |
784 | |
785 | <div class="slide"> |
786 | <h1>Typo?</h1> |
787 | |
788 | <pre class="small"><code>if (exists $args{last_name}) { |
789 | confess "Attribute (last_name) does not pass the type constraint because: " |
790 | . "Validation failed for 'Str' with value $args{last_name}" |
791 | if ref($args{last_name}); |
792 | $self->{last_nane} = $args{last_name}; |
793 | }</code></pre> |
794 | </div> |
795 | |
796 | <div class="slide"> |
797 | <h1>Typo?</h1> |
798 | |
799 | <code>$self->{last_nane} = $args{last_name};</code> |
800 | </div> |
801 | |
802 | <div class="slide"> |
803 | <h1>Typo?</h1> |
804 | <code>$self->{last_na<span class="highlight">n</span>e}</code> |
805 | </div> |
806 | |
807 | <div class="slide"> |
808 | <h1>Why Moose?</h1> |
809 | |
810 | <pre><code>package Person; |
811 | use Moose; |
812 | |
813 | has last_name => ( |
814 | is => 'rw', |
815 | isa => 'Str', |
816 | );</code></pre> |
817 | </div> |
818 | |
819 | <div class="slide fake-slide0"> |
820 | <h1>Moose Classes</h1> |
821 | </div> |
822 | |
823 | <div class="slide"> |
824 | <h1>Moose Classes</h1> |
825 | |
826 | <ul> |
827 | <li>Moose classes are Perl packages which <code>use Moose</code></li> |
828 | </ul> |
829 | </div> |
830 | |
831 | <div class="slide"> |
832 | <h1>Moose.pm and Your Class</h1> |
833 | |
834 | <pre><code>package Person; |
835 | use Moose;</code></pre> |
836 | |
837 | <ul> |
838 | <li><code>Moose.pm</code> provides declarative sugar</li> |
839 | <li>Creates metaclasses for your class: <code>Person->meta</code></li> |
840 | <li>Moose classes automatically inherit from <code>Moose::Object</code></li> |
841 | </ul> |
842 | </div> |
843 | |
844 | <div class="slide"> |
845 | <h1>What <code>Moose::Object</code> Provides</h1> |
846 | |
847 | <ul> |
848 | <li>Constructor - <code>new()</code></li> |
849 | <li>Calls your <code>BUILDARGS()</code> and/or <code>BUILD()</code></li> |
850 | <li>Calls your <code>DEMOLISH</code> during object destruction</li> |
851 | </ul> |
852 | </div> |
853 | |
854 | <div class="slide"> |
855 | <h1>extends</h1> |
856 | |
857 | <ul> |
858 | <li><code>extends</code> is sugar for declaring parent classes</li> |
859 | </ul> |
860 | |
861 | <pre><code>package Employee; |
862 | use Moose; |
863 | <span class="highlight">extends 'Person';</span></code></pre> |
864 | </div> |
865 | |
866 | <div class="slide"> |
867 | <h1>extends</h1> |
868 | |
869 | <ul> |
870 | <li>Each call to <code>extends</code> <strong>resets</strong> your parents</li> |
871 | </ul> |
872 | |
873 | <h2 class="wrong">WRONG</h2> |
874 | |
875 | <pre><code>package BadEmployee; |
876 | use Moose; |
877 | extends 'Person'; |
878 | extends 'Thief';</pre></code> |
879 | |
880 | <h2 class="right">RIGHT</h2> |
881 | |
882 | <pre><code>package BadEmployee; |
883 | use Moose; |
884 | extends 'Person', 'Thief';</pre></code> |
885 | </div> |
886 | |
887 | <div class="slide"> |
888 | <h1>Extending un-Moose-y Parents</h1> |
889 | |
890 | <pre><code>package My::LWP; |
891 | use Moose; |
892 | extends 'LWP';</pre></code> |
893 | |
894 | <ul> |
895 | <li>No <code>Moose::Object</code>, so ... |
896 | <ul> |
897 | <li>No attribute-handling <code>new()</code></li> |
898 | <li>No <code>BUILDARGS()</code> or <code>BUILD()</code></li> |
899 | <li>No <code>DEMOLISH()</code></li> |
900 | </ul> |
901 | </li> |
902 | <li>But see <code>MooseX::NonMoose</code> for a workaround</li> |
903 | </ul> |
904 | </div> |
905 | |
906 | <div class="slide"> |
907 | <h1>Cleaning Up Moose Droppings</h1> |
908 | |
909 | <pre><code>package Person; |
910 | use Moose; |
911 | |
912 | # true |
913 | Person->can('extends');</code></pre> |
914 | |
915 | <ul> |
916 | <li>Not very hygienic</li> |
917 | </ul> |
918 | </div> |
919 | |
920 | <div class="slide"> |
921 | <h1>Cleaning Up Moose Droppings</h1> |
922 | |
923 | <pre><code>package Person; |
924 | use Moose; |
925 | |
926 | ... |
927 | |
928 | no Moose; |
929 | |
930 | # false |
931 | Person->can('extends');</code></pre> |
932 | </div> |
933 | |
934 | <div class="slide"> |
935 | <h1>No Moose</h1> |
936 | |
937 | <ul> |
938 | <li><code>no Moose</code> at the end of a package is a best practice</li> |
939 | <li>Just do it</li> |
940 | </ul> |
941 | </div> |
942 | |
943 | <div class="slide"> |
944 | <h1>Immutability</h1> |
945 | |
946 | <ul> |
947 | <li><span style="font-family: URW Chancery L; font-size: 140%">Stevan's Incantation of Fleet-Footedness</span></li> |
948 | </ul> |
949 | |
950 | <pre><code>package Person; |
951 | use Moose; |
952 | |
953 | <span class="highlight">__PACKAGE__->meta->make_immutable;</span></code></pre> |
954 | </div> |
955 | |
956 | </body> |
957 | </html> |