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 | |
ba1c9923 |
63 | <div class="slide fake-slide0"> |
64 | <h1>Part 0: Moose Concepts</h1> |
65 | </div> |
66 | |
b751d33f |
67 | <div class="slide"> |
ba1c9923 |
68 | <h1>Moose background</h1> |
b751d33f |
69 | |
70 | <ul> |
71 | <li>Moose builds on Perl 5's native OO</li> |
72 | <li>Borrows ideas from other languages, notably Perl 6</li> |
73 | <li>Provides semantics for common operations</li> |
74 | </ul> |
75 | </div> |
76 | |
77 | <div class="slide"> |
78 | <h1>Classes</h1> |
79 | |
80 | <ul> |
81 | <li> |
82 | Classes have ... |
83 | <ul> |
84 | <li>Attributes</li> |
85 | <li>Methods</li> |
86 | <li>Superclasses</li> |
87 | <li>Method modifiers</li> |
88 | <li>Constructor and destructor</li> |
89 | <li>One metaclass object</li> |
90 | </ul> |
91 | </li> |
92 | <li>Classes do roles</li> |
93 | </ul> |
94 | </div> |
95 | |
96 | <div class="slide"> |
97 | <h1>Class Example</h1> |
98 | |
99 | <pre><code>package Person; |
100 | <span class="highlight">use Moose;</span></code></pre> |
101 | |
102 | <ul> |
103 | <li>Poof, a Moose-based class!</li> |
104 | </ul> |
105 | </div> |
106 | |
107 | <div class="slide"> |
108 | <h1>Attributes</h1> |
109 | |
110 | <ul> |
111 | <li>Aka property, slot, field, member variable</li> |
112 | <li>A piece of data owned by an object</li> |
113 | </ul> |
114 | </div> |
115 | |
116 | <div class="slide"> |
117 | <h1>Attributes</h1> |
118 | |
119 | <ul> |
120 | <li> |
121 | Attributes have ... |
122 | <ul> |
123 | <li>Access-control (read-only vs read-write)</li> |
124 | <li>An optional type</li> |
125 | <li>Accessor methods</li> |
126 | <li>Delegation methods</li> |
127 | <li>Optional default value</li> |
128 | <li>Many more features</li> |
129 | </ul> |
130 | </li> |
131 | <li>Stored in the object, but don't worry about that</li> |
132 | </ul> |
133 | </div> |
134 | |
135 | <div class="slide"> |
136 | <h1>Attribute Example</h1> |
137 | |
138 | <pre><code>package Person; |
139 | use Moose; |
140 | |
141 | <span class="highlight">has 'first_name' => ( is => 'rw' );</span></code></pre> |
142 | |
143 | </div> |
144 | |
145 | <div class="slide"> |
146 | <h1>Methods</h1> |
147 | |
148 | <ul> |
149 | <li>Nothing fancy here, just Perl subroutines</li> |
150 | </ul> |
151 | |
152 | <pre><code>package Person; |
153 | use Moose; |
154 | |
155 | <span class="highlight">sub greet { ... }</span></code></pre> |
156 | </div> |
157 | |
158 | <div class="slide"> |
159 | <h1>Roles</h1> |
160 | |
161 | <ul> |
162 | <li>Classes <strong>do</strong> (or consume) roles</li> |
163 | <li>Similar to mixins and Java interfaces</li> |
164 | </ul> |
165 | </div> |
166 | |
167 | <div class="slide"> |
168 | <h1>Roles</h1> |
169 | |
170 | <ul> |
171 | <li>Like classes, can have attributes, methods, do roles</li> |
172 | <li>Roles can require methods</li> |
173 | <li>Roles are composed (flattened) into classes</li> |
174 | </ul> |
175 | </div> |
176 | |
177 | <div class="slide"> |
178 | <h1>Role Example</h1> |
179 | |
180 | <pre><code>package HasPermissions; |
181 | <span class="highlight">use Moose::Role;</span> |
182 | |
183 | has is_admin => ( is => 'rw' );</code></pre> |
184 | </div> |
185 | |
186 | <div class="slide"> |
187 | <h1>Role Example</h1> |
188 | |
189 | <p> |
190 | And then ... |
191 | </p> |
192 | |
193 | <pre><code>package Person; |
194 | use Moose; |
195 | |
196 | <span class="highlight">with 'HasPermissions';</span></code></pre> |
197 | </div> |
198 | |
199 | <div class="slide"> |
200 | <h1>Method Modifiers</h1> |
201 | |
202 | <ul> |
203 | <li>AKA advice</li> |
204 | <li>"<strong>Before</strong> foo(), do this first"</li> |
205 | <li>"Do this <strong>after</strong> foo()</li> |
206 | <li>"Put this code <strong>around</strong> foo()"</li> |
207 | </ul> |
208 | </div> |
209 | |
210 | <div class="slide"> |
211 | <h1>Before & After</h1> |
212 | |
213 | <pre><code>before 'foo' |
214 | => sub { warn 'About to call foo()' }; |
215 | |
216 | after 'foo' |
217 | => sub { warn 'Leaving foo()' };</code></pre> |
218 | |
219 | </div> |
220 | |
221 | <div class="slide"> |
222 | <h1>Around</h1> |
223 | |
224 | <pre><code>around 'foo' => sub { |
225 | my $real_foo = shift; |
226 | my $self = shift; |
227 | |
228 | warn 'Just before foo()'; |
229 | my @return = |
230 | $self->$real_foo( @_, bar => 42 ); |
231 | |
232 | return ( @return, 'modify return values' ); |
233 | };</code></pre> |
234 | </div> |
235 | |
236 | <div class="slide"> |
237 | <h1>Type Constraints</h1> |
238 | |
239 | <ul> |
240 | <li>NOT A FULL-BLOWN TYPE SYSTEM!</li> |
241 | <li>But still darn useful</li> |
242 | <li>Constrain attribute values</li> |
243 | <li>Coerce from other types</li> |
244 | </ul> |
245 | </div> |
246 | |
247 | <div class="slide"> |
248 | <h1>Type Constraint Example</h1> |
249 | |
250 | <pre><code>package Person; |
251 | use Moose; |
252 | |
253 | has 'weight' => ( is => 'ro', <span class="highlight">isa => 'Int'</span> ); |
254 | |
255 | # kaboom |
256 | Person->new( weight => 'fat' );</code></pre> |
257 | </div> |
258 | |
259 | <div class="slide"> |
260 | <h1>Delegation</h1> |
261 | |
262 | <ul> |
263 | <li>Attributes can define delegations</li> |
264 | <li>Lets you hide some implementation details</li> |
265 | <li>Fewer objects to chase around</li> |
266 | </ul> |
267 | </div> |
268 | |
269 | <div class="slide"> |
270 | <h1>Delegation</h1> |
271 | |
272 | <pre><code>package Person; |
273 | use Moose; |
274 | |
275 | has 'blog_uri' => ( |
276 | is => 'rw', |
277 | isa => 'URI', |
278 | <span class="highlight">handles => { 'blog_hostname' => 'host' },</span> |
279 | ); |
280 | |
281 | <span class="highlight">$person->blog_hostname;</span> |
282 | # really calls $person->blog_uri->host |
283 | </div> |
284 | |
285 | <div class="slide"> |
286 | <h1>Constructors</h1> |
287 | |
288 | <ul> |
289 | <li>Moose creates <code>new()</code> for you</li> |
290 | <li>Provide an optional <code>BUILDARGS()</code> and <code>BUILD()</code></li> |
291 | </ul> |
292 | </div> |
293 | |
294 | <div class="slide"> |
295 | <h1>Destructors</h1> |
296 | |
297 | <ul> |
298 | <li>Provide an optional <code>DEMOLISH()</code></li> |
299 | </ul> |
300 | </div> |
301 | |
302 | <div class="slide"> |
303 | <h1>Moose Meta-API</h1> |
304 | |
305 | <ul> |
306 | <li>Answers questions like ... |
307 | <ul> |
308 | <li>What methods does this class have?</li> |
309 | <li>What are its parents?</li> |
310 | <li>What attributes does it have (including inherited attributes)?</li> |
311 | <li>What roles does it do?</li> |
312 | <li>Much, much, more</li> |
313 | </ul> |
314 | </li> |
315 | </ul> |
316 | </div> |
317 | |
318 | <div class="slide"> |
319 | <h1>Moose Meta-API</h1> |
320 | |
321 | <ul> |
322 | <li>Not just for introspection ... |
323 | <ul> |
324 | <li>Add methods, attributes, roles, etc</li> |
325 | <li>Extend and alter core features</li> |
326 | </ul> |
327 | </li> |
328 | </ul> |
329 | </div> |
330 | |
331 | <div class="slide"> |
332 | <h1>Why Moose?</h1> |
333 | |
334 | <ul> |
335 | <li>A quick bit of propoganda ...</li> |
336 | </ul> |
337 | </div> |
338 | |
339 | <div class="slide"> |
340 | <h1>With Moose</h1> |
341 | |
342 | <pre><code>package Person; |
343 | use Moose; |
344 | |
345 | has last_name => ( |
346 | is => 'rw', |
347 | isa => 'Str', |
348 | );</code></pre> |
349 | </div> |
350 | |
351 | <div class="slide"> |
352 | <h1>Without Moose</h1> |
353 | |
354 | <pre class="small"><code>package Person; |
355 | use strict; |
356 | use warnings; |
357 | use Carp 'confess'; |
358 | |
359 | sub new { |
360 | my $class = shift; |
361 | my %args = @_; |
362 | my $self = {}; |
363 | |
364 | if (exists $args{last_name}) { |
365 | confess "Attribute (last_name) does not pass the type constraint because: " |
366 | . "Validation failed for 'Str' with value $args{last_name}" |
367 | if ref($args{last_name}); |
368 | $self->{last_nane} = $args{last_name}; |
369 | } |
370 | |
371 | return bless $self, $class; |
372 | } |
373 | |
374 | sub last_name { |
375 | my $self = shift; |
376 | |
377 | if (@_) { |
378 | my $value = shift; |
379 | confess "Attribute (last_name) does not pass the type constraint because: " |
380 | . "Validation failed for 'Str' with value $value" |
381 | if ref($value); |
382 | $self->{last_name} = $value; |
383 | } |
384 | |
385 | return $self->{last_name}; |
386 | }</code></pre> |
387 | |
388 | </div> |
389 | |
390 | <div class="slide"> |
391 | <h1>Side by side</h1> |
392 | |
393 | <table class="side-by-side"> |
394 | <tr> |
395 | <td> |
396 | <pre><code>package Person; |
397 | use Moose; |
398 | |
399 | has last_name => ( |
400 | is => 'rw', |
401 | isa => 'Str', |
402 | );</code></pre> |
403 | </td> |
404 | <td> |
405 | <pre class="small"><code>package Person; |
406 | use strict; |
407 | use warnings; |
408 | use Carp 'confess'; |
409 | |
410 | sub new { |
411 | my $class = shift; |
412 | my %args = @_; |
413 | my $self = {}; |
414 | |
415 | if (exists $args{last_name}) { |
416 | confess "Attribute (last_name) does not pass the type constraint because: " |
417 | . "Validation failed for 'Str' with value $args{last_name}" |
418 | if ref($args{last_name}); |
419 | $self->{last_nane} = $args{last_name}; |
420 | } |
421 | |
422 | return bless $self, $class; |
423 | } |
424 | |
425 | sub last_name { |
426 | my $self = shift; |
427 | |
428 | if (@_) { |
429 | my $value = shift; |
430 | confess "Attribute (last_name) does not pass the type constraint because: " |
431 | . "Validation failed for 'Str' with value $value" |
432 | if ref($value); |
433 | $self->{last_name} = $value; |
434 | } |
435 | |
436 | return $self->{last_name}; |
437 | }</code></pre> |
438 | </td> |
439 | </tr> |
440 | </table> |
441 | |
442 | </div> |
443 | |
444 | <div class="slide"> |
445 | <h1>Side by side</h1> |
446 | |
447 | <table class="side-by-side"> |
448 | <tr> |
449 | <td> |
450 | <pre><code><span class="match-moose">package Person;</span> |
451 | use Moose; |
452 | |
453 | has last_name => ( |
454 | is => 'rw', |
455 | isa => 'Str', |
456 | );</code></pre> |
457 | </td> |
458 | <td> |
459 | <pre class="small"><code><span class="match-unsweet">package Person;</span> |
460 | use strict; |
461 | use warnings; |
462 | use Carp 'confess'; |
463 | |
464 | sub new { |
465 | my $class = shift; |
466 | my %args = @_; |
467 | my $self = {}; |
468 | |
469 | if (exists $args{last_name}) { |
470 | confess "Attribute (last_name) does not pass the type constraint because: " |
471 | . "Validation failed for 'Str' with value $args{last_name}" |
472 | if ref($args{last_name}); |
473 | $self->{last_nane} = $args{last_name}; |
474 | } |
475 | |
476 | return bless $self, $class; |
477 | } |
478 | |
479 | sub last_name { |
480 | my $self = shift; |
481 | |
482 | if (@_) { |
483 | my $value = shift; |
484 | confess "Attribute (last_name) does not pass the type constraint because: " |
485 | . "Validation failed for 'Str' with value $value" |
486 | if ref($value); |
487 | $self->{last_name} = $value; |
488 | } |
489 | |
490 | return $self->{last_name}; |
491 | }</code></pre> |
492 | </td> |
493 | </tr> |
494 | </table> |
495 | </div> |
496 | |
497 | <div class="slide"> |
498 | <h1>Side by side</h1> |
499 | |
500 | <table class="side-by-side"> |
501 | <tr> |
502 | <td> |
503 | <pre><code>package Person; |
504 | <span class="match-moose">use Moose;</span> |
505 | |
506 | has last_name => ( |
507 | is => 'rw', |
508 | isa => 'Str', |
509 | );</code></pre> |
510 | </td> |
511 | <td> |
512 | <pre class="small"><code>package Person; |
513 | <span class="match-unsweet">use strict; |
514 | use warnings; |
515 | use Carp 'confess'; |
516 | |
517 | sub new { |
518 | my $class = shift; |
519 | my %args = @_; |
520 | my $self = {};</span> |
521 | |
522 | if (exists $args{last_name}) { |
523 | confess "Attribute (last_name) does not pass the type constraint because: " |
524 | . "Validation failed for 'Str' with value $args{last_name}" |
525 | if ref($args{last_name}); |
526 | $self->{last_nane} = $args{last_name}; |
527 | } |
528 | |
529 | <span class="match-unsweet">return bless $self, $class; |
530 | }</span> |
531 | |
532 | sub last_name { |
533 | my $self = shift; |
534 | |
535 | if (@_) { |
536 | my $value = shift; |
537 | confess "Attribute (last_name) does not pass the type constraint because: " |
538 | . "Validation failed for 'Str' with value $value" |
539 | if ref($value); |
540 | $self->{last_name} = $value; |
541 | } |
542 | |
543 | return $self->{last_name}; |
544 | }</code></pre> |
545 | </td> |
546 | </tr> |
547 | </table> |
548 | </div> |
549 | |
550 | <div class="slide"> |
551 | <h1>Side by side</h1> |
552 | |
553 | <table class="side-by-side"> |
554 | <tr> |
555 | <td> |
556 | <pre><code>package Person; |
557 | use Moose; |
558 | |
559 | <span class="match-moose">has last_name => (</span> |
560 | is => 'rw', |
561 | isa => 'Str', |
562 | <span class="match-moose">);</span></code></pre> |
563 | </td> |
564 | <td> |
565 | <pre class="small"><code>package Person; |
566 | use strict; |
567 | use warnings; |
568 | use Carp 'confess'; |
569 | |
570 | sub new { |
571 | my $class = shift; |
572 | my %args = @_; |
573 | my $self = {}; |
574 | |
575 | <span class="match-unsweet">if (exists $args{last_name}) {</span> |
576 | confess "Attribute (last_name) does not pass the type constraint because: " |
577 | . "Validation failed for 'Str' with value $args{last_name}" |
578 | if ref($args{last_name}); |
579 | <span class="match-unsweet">$self->{last_nane} = $args{last_name}; |
580 | }</span> |
581 | |
582 | return bless $self, $class; |
583 | } |
584 | |
585 | sub last_name { |
586 | my $self = shift; |
587 | |
588 | if (@_) { |
589 | my $value = shift; |
590 | confess "Attribute (last_name) does not pass the type constraint because: " |
591 | . "Validation failed for 'Str' with value $value" |
592 | if ref($value); |
593 | $self->{last_name} = $value; |
594 | } |
595 | |
596 | return $self->{last_name}; |
597 | }</code></pre> |
598 | </td> |
599 | </tr> |
600 | </table> |
601 | </div> |
602 | |
603 | <div class="slide"> |
604 | <h1>Side by side</h1> |
605 | |
606 | <table class="side-by-side"> |
607 | <tr> |
608 | <td> |
609 | <pre><code>package Person; |
610 | use Moose; |
611 | |
612 | has last_name => ( |
613 | <span class="match-moose">is => 'rw',</span> |
614 | isa => 'Str', |
615 | );</code></pre> |
616 | </td> |
617 | <td> |
618 | <pre class="small"><code>package Person; |
619 | use strict; |
620 | use warnings; |
621 | use Carp 'confess'; |
622 | |
623 | sub new { |
624 | my $class = shift; |
625 | my %args = @_; |
626 | my $self = {}; |
627 | |
628 | if (exists $args{last_name}) { |
629 | confess "Attribute (last_name) does not pass the type constraint because: " |
630 | . "Validation failed for 'Str' with value $args{last_name}" |
631 | if ref($args{last_name}); |
632 | $self->{last_nane} = $args{last_name}; |
633 | } |
634 | |
635 | return bless $self, $class; |
636 | } |
637 | |
638 | <span class="match-unsweet">sub last_name { |
639 | my $self = shift; |
640 | |
641 | if (@_) { |
642 | my $value = shift;</span> |
643 | confess "Attribute (last_name) does not pass the type constraint because: " |
644 | . "Validation failed for 'Str' with value $value" |
645 | if ref($value); |
646 | <span class="match-unsweet">$self->{last_name} = $value; |
647 | } |
648 | |
649 | return $self->{last_name}; |
650 | }</span></code></pre> |
651 | </td> |
652 | </tr> |
653 | </table> |
654 | </div> |
655 | |
656 | <div class="slide"> |
657 | <h1>Side by side</h1> |
658 | |
659 | <table class="side-by-side"> |
660 | <tr> |
661 | <td> |
662 | <pre><code>package Person; |
663 | use Moose; |
664 | |
665 | has last_name => ( |
666 | is => 'rw', |
667 | <span class="match-moose">isa => 'Str',</span> |
668 | );</code></pre> |
669 | </td> |
670 | <td> |
671 | <pre class="small"><code>package Person; |
672 | use strict; |
673 | use warnings; |
674 | use Carp 'confess'; |
675 | |
676 | sub new { |
677 | my $class = shift; |
678 | my %args = @_; |
679 | my $self = {}; |
680 | |
681 | if (exists $args{last_name}) { |
682 | <span class="match-unsweet">confess "Attribute (last_name) does not pass the type constraint because: " |
683 | . "Validation failed for 'Str' with value $args{last_name}" |
684 | if ref($args{last_name});</span> |
685 | $self->{last_nane} = $args{last_name}; |
686 | } |
687 | |
688 | return bless $self, $class; |
689 | } |
690 | |
691 | sub last_name { |
692 | my $self = shift; |
693 | |
694 | if (@_) { |
695 | my $value = shift; |
696 | <span class="match-unsweet">confess "Attribute (last_name) does not pass the type constraint because: " |
697 | . "Validation failed for 'Str' with value $value" |
698 | if ref($value);</span> |
699 | $self->{last_name} = $value; |
700 | } |
701 | |
702 | return $self->{last_name}; |
703 | }</code></pre> |
704 | </td> |
705 | </tr> |
706 | </table> |
707 | </div> |
708 | |
709 | <div class="slide"> |
710 | <h1>Side by side</h1> |
711 | |
712 | <table class="side-by-side"> |
713 | <tr class="incremental"> |
714 | <td>5 lines</td> |
715 | <td>21 lines</td> |
716 | </tr> |
717 | <tr class="incremental"> |
718 | <td>92 characters</td> |
719 | <td>741 characters</td> |
720 | </tr> |
721 | <tr> |
722 | <td> |
723 | <pre><code>package Person; |
724 | use Moose; |
725 | |
726 | has last_name => ( |
727 | is => 'rw', |
728 | isa => 'Str', |
729 | );</code></pre> |
730 | </td> |
731 | <td> |
732 | <pre class="small"><code>package Person; |
733 | use strict; |
734 | use warnings; |
735 | use Carp 'confess'; |
736 | |
737 | sub new { |
738 | my $class = shift; |
739 | my %args = @_; |
740 | my $self = {}; |
741 | |
742 | if (exists $args{last_name}) { |
743 | confess "Attribute (last_name) does not pass the type constraint because: " |
744 | . "Validation failed for 'Str' with value $args{last_name}" |
745 | if ref($args{last_name}); |
746 | $self->{last_nane} = $args{last_name}; |
747 | } |
748 | |
749 | return bless $self, $class; |
750 | } |
751 | |
752 | sub last_name { |
753 | my $self = shift; |
754 | |
755 | if (@_) { |
756 | my $value = shift; |
757 | confess "Attribute (last_name) does not pass the type constraint because: " |
758 | . "Validation failed for 'Str' with value $value" |
759 | if ref($value); |
760 | $self->{last_name} = $value; |
761 | } |
762 | |
763 | return $self->{last_name}; |
764 | }</code></pre> |
765 | </td> |
766 | </tr> |
767 | </table> |
768 | </div> |
769 | |
770 | <div class="slide"> |
771 | <h1>Typo?</h1> |
772 | |
773 | <pre class="small"><code>sub new { |
774 | my $class = shift; |
775 | my %args = @_; |
776 | my $self = {}; |
777 | |
778 | if (exists $args{last_name}) { |
779 | confess "Attribute (last_name) does not pass the type constraint because: " |
780 | . "Validation failed for 'Str' with value $args{last_name}" |
781 | if ref($args{last_name}); |
782 | $self->{last_nane} = $args{last_name}; |
783 | } |
784 | |
785 | return bless $self, $class; |
786 | }</code></pre> |
787 | </div> |
788 | |
789 | <div class="slide"> |
790 | <h1>Typo?</h1> |
791 | |
792 | <pre class="small"><code>if (exists $args{last_name}) { |
793 | confess "Attribute (last_name) does not pass the type constraint because: " |
794 | . "Validation failed for 'Str' with value $args{last_name}" |
795 | if ref($args{last_name}); |
796 | $self->{last_nane} = $args{last_name}; |
797 | }</code></pre> |
798 | </div> |
799 | |
800 | <div class="slide"> |
801 | <h1>Typo?</h1> |
802 | |
803 | <code>$self->{last_nane} = $args{last_name};</code> |
804 | </div> |
805 | |
806 | <div class="slide"> |
807 | <h1>Typo?</h1> |
808 | <code>$self->{last_na<span class="highlight">n</span>e}</code> |
809 | </div> |
810 | |
811 | <div class="slide"> |
812 | <h1>Why Moose?</h1> |
813 | |
814 | <pre><code>package Person; |
815 | use Moose; |
816 | |
817 | has last_name => ( |
818 | is => 'rw', |
819 | isa => 'Str', |
820 | );</code></pre> |
821 | </div> |
822 | |
823 | <div class="slide fake-slide0"> |
ba1c9923 |
824 | <h1>Part 1: Moose Classes</h1> |
b751d33f |
825 | </div> |
826 | |
827 | <div class="slide"> |
828 | <h1>Moose Classes</h1> |
829 | |
830 | <ul> |
831 | <li>Moose classes are Perl packages which <code>use Moose</code></li> |
832 | </ul> |
833 | </div> |
834 | |
835 | <div class="slide"> |
836 | <h1>Moose.pm and Your Class</h1> |
837 | |
838 | <pre><code>package Person; |
839 | use Moose;</code></pre> |
840 | |
841 | <ul> |
842 | <li><code>Moose.pm</code> provides declarative sugar</li> |
9b195048 |
843 | <li>Turns on <code>strict</code> and <code>warnings</code></li> |
b751d33f |
844 | <li>Creates metaclasses for your class: <code>Person->meta</code></li> |
845 | <li>Moose classes automatically inherit from <code>Moose::Object</code></li> |
846 | </ul> |
847 | </div> |
848 | |
849 | <div class="slide"> |
850 | <h1>What <code>Moose::Object</code> Provides</h1> |
851 | |
852 | <ul> |
853 | <li>Constructor - <code>new()</code></li> |
854 | <li>Calls your <code>BUILDARGS()</code> and/or <code>BUILD()</code></li> |
855 | <li>Calls your <code>DEMOLISH</code> during object destruction</li> |
856 | </ul> |
857 | </div> |
858 | |
859 | <div class="slide"> |
860 | <h1>extends</h1> |
861 | |
862 | <ul> |
863 | <li><code>extends</code> is sugar for declaring parent classes</li> |
864 | </ul> |
865 | |
866 | <pre><code>package Employee; |
867 | use Moose; |
868 | <span class="highlight">extends 'Person';</span></code></pre> |
869 | </div> |
870 | |
871 | <div class="slide"> |
872 | <h1>extends</h1> |
873 | |
874 | <ul> |
875 | <li>Each call to <code>extends</code> <strong>resets</strong> your parents</li> |
876 | </ul> |
877 | |
878 | <h2 class="wrong">WRONG</h2> |
879 | |
9b195048 |
880 | <pre><code>package EvilEmployee; |
b751d33f |
881 | use Moose; |
882 | extends 'Person'; |
883 | extends 'Thief';</pre></code> |
884 | |
885 | <h2 class="right">RIGHT</h2> |
886 | |
9b195048 |
887 | <pre><code>package EvilEmployee; |
b751d33f |
888 | use Moose; |
889 | extends 'Person', 'Thief';</pre></code> |
890 | </div> |
891 | |
892 | <div class="slide"> |
893 | <h1>Extending un-Moose-y Parents</h1> |
894 | |
895 | <pre><code>package My::LWP; |
896 | use Moose; |
897 | extends 'LWP';</pre></code> |
898 | |
899 | <ul> |
900 | <li>No <code>Moose::Object</code>, so ... |
901 | <ul> |
902 | <li>No attribute-handling <code>new()</code></li> |
903 | <li>No <code>BUILDARGS()</code> or <code>BUILD()</code></li> |
904 | <li>No <code>DEMOLISH()</code></li> |
905 | </ul> |
906 | </li> |
907 | <li>But see <code>MooseX::NonMoose</code> for a workaround</li> |
908 | </ul> |
909 | </div> |
910 | |
911 | <div class="slide"> |
9b195048 |
912 | <h1><code>overrides</code> and <code>super</code></h1> |
913 | |
914 | <ul> |
915 | <li><code>overrides</code> is another method modifier</li> |
916 | <li>An alternative to Perl's <code>SUPER::</code></li> |
917 | </ul> |
918 | </div> |
919 | |
920 | <div class="slide"> |
921 | <h1><code>overrides</code> and <code>super</code></h1> |
922 | |
923 | <pre><code>package Employee; |
924 | use Moose; |
925 | |
926 | <span class="incremental current">extends 'Person';</span> |
927 | |
928 | <span class="incremental">overrides</span> work => sub { |
929 | my $self = shift; |
930 | |
931 | die "Pay me first" unless $self->got_paid; |
932 | <span class="incremental">super();</span> |
933 | }<span class="incremental">;</span></code></pre> |
934 | |
935 | <div class="slide"> |
936 | <h1>Caveat <code>super</code></h1> |
937 | |
938 | <ul> |
939 | <li>Mostly like <code>$self->SUPER::work(@_)</code></li> |
940 | <li><strong>But</strong> cannot change <code>@_</code>!</li> |
941 | <li>Binds the parent's method at compile time</li> |
942 | </ul> |
943 | </div> |
944 | |
945 | <div class="slide"> |
946 | <h1>Attributes (Part 1)</h1> |
947 | |
948 | <ul> |
949 | <li><code>has 'foo'</code></li> |
950 | <li>Use <code>is => 'ro'</code> or <code>is => 'rw'</code></li> |
951 | <li>Attributes without "is" have no accessors</li> |
952 | </ul> |
953 | </div> |
954 | |
955 | <div class="slide"> |
956 | <h1>Read-write attributes</h1> |
957 | |
958 | <pre><code>package Person; |
959 | use Moose; |
960 | |
961 | has 'first_name' => ( <span class="highlight">is => 'rw'</span> ); |
962 | |
963 | my $person = |
964 | Person->new( first_name => 'Dave' ); |
965 | |
966 | $person->first_name('Stevan'); |
967 | print $person->first_name; # Stevan</code></pre> |
968 | |
969 | </div> |
970 | |
971 | <div class="slide"> |
972 | <h1>Read-only attributes</h1> |
973 | |
974 | <pre><code>package Person; |
975 | use Moose; |
976 | |
977 | has 'first_name' => ( <span class="highlight">is => 'ro'</span> ); |
978 | |
979 | my $person = |
980 | Person->new( first_name => 'Dave' ); |
981 | |
982 | $person->first_name('Stevan'); |
983 | print $person->first_name; # Dave</code></pre> |
984 | |
985 | </div> |
986 | |
987 | <div class="slide"> |
988 | <h1>There is More to Come</h1> |
989 | |
990 | <ul> |
991 | <li>Attributes have a <em>lot</em> of features</li> |
992 | </ul> |
993 | </div> |
994 | |
995 | <div class="slide"> |
b751d33f |
996 | <h1>Cleaning Up Moose Droppings</h1> |
997 | |
998 | <pre><code>package Person; |
999 | use Moose; |
1000 | |
1001 | # true |
1002 | Person->can('extends');</code></pre> |
1003 | |
1004 | <ul> |
1005 | <li>Not very hygienic</li> |
1006 | </ul> |
1007 | </div> |
1008 | |
1009 | <div class="slide"> |
1010 | <h1>Cleaning Up Moose Droppings</h1> |
1011 | |
1012 | <pre><code>package Person; |
1013 | use Moose; |
1014 | |
1015 | ... |
1016 | |
1017 | no Moose; |
1018 | |
1019 | # false |
1020 | Person->can('extends');</code></pre> |
1021 | </div> |
1022 | |
1023 | <div class="slide"> |
1024 | <h1>No Moose</h1> |
1025 | |
1026 | <ul> |
1027 | <li><code>no Moose</code> at the end of a package is a best practice</li> |
1028 | <li>Just do it</li> |
1029 | </ul> |
1030 | </div> |
1031 | |
1032 | <div class="slide"> |
1033 | <h1>Immutability</h1> |
1034 | |
1035 | <ul> |
1036 | <li><span style="font-family: URW Chancery L; font-size: 140%">Stevan's Incantation of Fleet-Footedness</span></li> |
1037 | </ul> |
1038 | |
1039 | <pre><code>package Person; |
1040 | use Moose; |
1041 | |
1042 | <span class="highlight">__PACKAGE__->meta->make_immutable;</span></code></pre> |
1043 | </div> |
1044 | |
9b195048 |
1045 | <div class="slide"> |
1046 | <h1>What <code>make_immutable</code> does</h1> |
1047 | |
1048 | <ul> |
1049 | <li>Magic</li> |
1050 | <li>Uses <code>eval</code> to "inline" a constructor</li> |
1051 | <li>Memoizes a lot of meta-information</li> |
1052 | <li>Makes loading your class slower</li> |
1053 | <li>Makes object creation <em>much</em> faster</li> |
1054 | </ul> |
1055 | </div> |
1056 | |
1057 | <div class="slide"> |
1058 | <h1>When to Immutabilize?</h1> |
1059 | |
1060 | <ul> |
1061 | <li><em>Almost</em> always</li> |
1062 | <li>Startup time vs execution time</li> |
1063 | </ul> |
1064 | </div> |
1065 | |
ddd87d75 |
1066 | <div class="slide"> |
ba1c9923 |
1067 | <h1>Exercises</h1> |
ddd87d75 |
1068 | |
1069 | <pre>$ cd exercises |
ba1c9923 |
1070 | $ perl bin/prove -lv t/00-prereq.t |
ddd87d75 |
1071 | |
1072 | Missing anything? Install it. (see tarballs/) |
1073 | |
ba1c9923 |
1074 | # perl bin/prove -lv t/01-classes.t |
1075 | |
1076 | Iterate til this passes all its tests |
ddd87d75 |
1077 | |
b751d33f |
1078 | </body> |
1079 | </html> |