Commit | Line | Data |
b98e5148 |
1 | <?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="chrome://global/skin/" type="text/css"?><?xml-stylesheet href="takahashi.css" type="text/css"?><page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="presentation" xmlns:html="http:/www.w3.org/1999/xhtml" orient="vertical" onkeypress="Presentation.onKeyPress(event);"> |
2 | <html:textarea id="builtinCode" style="visibility: collapse"><![CDATA[ |
3 | Moose |
4 | ---- |
5 | A Postmodern |
6 | Object System |
7 | for Perl 5 |
8 | ---- |
9 | Stevan Little |
10 | stevan@cpan.org |
11 | http://moose.perl.org/ |
12 | ---- |
13 | What is |
14 | Moose? |
15 | ---- |
16 | What is |
17 | Class::MOP? |
18 | ---- |
19 | What is |
20 | a MOP?? |
21 | ---- |
22 | Meta |
23 | Object |
24 | Protocol |
25 | ---- |
26 | CLOS |
27 | ---- |
28 | 20 year old |
29 | LISP |
30 | technology |
31 | ---- |
32 | Formalization |
33 | of the |
34 | object system |
35 | ---- |
36 | How |
37 | classes |
38 | work |
39 | ---- |
40 | How |
41 | methods |
42 | work |
43 | ---- |
44 | How objects |
45 | are created |
46 | ... etc. |
47 | ---- |
48 | Class::MOP |
49 | is CLOS for |
50 | Perl 5 |
51 | ---- |
52 | Class::MOP |
53 | is a |
54 | formalization |
55 | of Perl 5 OO |
56 | ---- |
57 | Clarity & |
58 | Structure |
59 | ---- |
60 | Class::MOP is |
61 | a platform for |
62 | ---- |
63 | Moose |
64 | ---- |
65 | package Person; |
66 | use Moose; |
67 | |
68 | has name => (is => 'rw'); |
69 | has age => (is => 'rw'); |
70 | |
71 | 1; |
72 | ---- |
73 | turns on |
74 | strict & |
75 | warnings |
76 | ---- |
77 | Moose::Object |
78 | in the @ISA |
79 | ---- |
80 | `has` creates |
81 | accessor |
82 | called 'name' |
83 | ---- |
84 | `has` creates |
85 | accessor |
86 | called 'age' |
87 | ---- |
88 | *lots* |
89 | of class |
90 | metadata |
91 | ---- |
92 | package Person; |
93 | use Moose; |
94 | |
95 | has name => (is => 'rw'); |
96 | has age => (is => 'rw'); |
97 | |
98 | 1; |
99 | ---- |
100 | Types |
101 | ---- |
102 | has name => ( |
103 | is => 'rw', |
104 | isa => 'Str', |
105 | required => 1 |
106 | ); |
107 | ---- |
108 | has age => ( |
109 | is => 'rw', |
110 | isa => 'DateTime::Duration', |
111 | lazy => 1, |
112 | default => sub { |
113 | DateTime::Duration->new |
114 | } |
115 | ); |
116 | ---- |
117 | Custom |
118 | Types |
119 | ---- |
120 | use Moose::Util::TypeConstraints; |
121 | ---- |
122 | subtype 'NonEmptyStr' |
123 | => as 'Str' |
124 | => where { length $_ > 0 }; |
125 | ---- |
126 | has name => ( |
127 | is => 'rw', |
128 | isa => 'NonEmptyStr', |
129 | required => 1 |
130 | ); |
131 | ---- |
132 | my $me = Person->new( |
133 | name => 'Stevan', |
134 | age => DateTime::Duration->new( |
135 | years => 35 |
136 | ) |
137 | ); |
138 | ---- |
139 | my $me = Person->new; # BOOM! name is required |
140 | ---- |
141 | my $me = Person->new( |
142 | name => 'Stevan', |
143 | age => 35 |
144 | ); # BOOM! age should be DateTime::Duration |
145 | ---- |
146 | Coercions |
147 | ---- |
148 | class_type 'DateTime::Duration'; |
149 | coerce 'DateTime::Duration' |
150 | => from 'Int' |
151 | => via { |
152 | DateTime::Duration->new( |
153 | years => $_ |
154 | ) |
155 | }; |
156 | ---- |
157 | has age => ( |
158 | is => 'rw', |
159 | isa => 'DateTime::Duration', |
160 | coerce => 1, |
161 | lazy => 1, |
162 | default => sub { |
163 | DateTime::Duration->new |
164 | } |
165 | ); |
166 | ---- |
167 | my $me = Person->new( |
168 | name => 'Stevan', |
169 | age => 35 |
170 | ); |
171 | ---- |
172 | coerce 'DateTime::Duration' |
173 | => from 'Int' |
174 | => via { |
175 | DateTime::Duration->new( |
176 | years => $_ |
177 | ) |
178 | } |
179 | => from 'HashRef' |
180 | => via { |
181 | DateTime::Duration->new(%$_) |
182 | }; |
183 | ---- |
184 | my $me = Person->new( |
185 | name => 'Stevan', |
186 | age => { years => 35, months => 2 } |
187 | ); |
188 | ---- |
189 | my $me = Person->new( |
190 | name => 'Stevan', |
191 | age => { years => 35, months => 2 } |
192 | ); |
193 | |
194 | $me->name # 'Stevan' |
195 | $me->age # DateTime::Duration object |
196 | ---- |
197 | my $xoe = Person->new(name => 'Xoe'); |
198 | |
199 | $xoe->age(11); |
200 | |
201 | $xoe->age({ years => 11, months => 10 }); |
202 | |
203 | $xoe->age(DateTime::Duration->new({ |
204 | years => 11, |
205 | months => 10 |
206 | })); |
207 | ---- |
208 | Delegation |
209 | ---- |
210 | has age => ( |
211 | is => 'rw', |
212 | isa => 'DateTime::Duration', |
213 | coerce => 1, |
214 | lazy => 1, |
215 | default => sub { |
216 | DateTime::Duration->new |
217 | }, |
218 | handles => { |
219 | 'years_old' => 'years' |
220 | } |
221 | ); |
222 | ---- |
223 | $me->years_old # 35 |
224 | ---- |
225 | Unconventional |
226 | Delegation |
227 | ---- |
228 | package Conference; |
229 | use Moose; |
230 | use MooseX::AttributeHelpers; |
231 | |
232 | has attendees => ( |
233 | metaclass => 'Collection::Array', |
234 | is => 'rw', |
235 | isa => 'ArrayRef[Person]', |
236 | provides => { |
237 | push => 'add_attendee', |
238 | count => 'number_of_attendees', |
239 | }, |
240 | ); |
241 | ---- |
242 | my $ppw = Conference->new( |
243 | attendees => [ $me, @all_you_guys ] |
244 | ); |
245 | |
246 | $ppw->number_of_attendees; # lots of people |
247 | $ppw->add_attendee($some_slacker); # add a late comer |
248 | ---- |
249 | Method Modifiers |
250 | ---- |
251 | before 'add_attendee' => sub { |
252 | my ($self, $attendee) = @_; |
253 | $self->setup_more_chairs(1); |
254 | }; |
255 | ---- |
256 | after 'add_attendee' => sub { |
257 | my ($self, $attendee) = @_; |
258 | $self->log("Attendee " . $attendee->name . " added"); |
259 | }; |
260 | ---- |
261 | around 'add_attendee' => sub { |
262 | my ($next, $self, @args) = @_; |
263 | ... |
264 | my @return = $self->$next(@args); |
265 | ... |
266 | return @return; |
267 | }; |
268 | ---- |
269 | Roles |
270 | ---- |
271 | ≠|
272 | ---- |
273 | Classes |
274 | ---- |
275 | Roles |
276 | do /not/ |
277 | inherit. |
278 | ---- |
279 | Inheritance is |
280 | ↕ |
281 | vertical reuse. |
282 | ---- |
283 | Roles |
284 | compose. |
285 | ---- |
286 | Composition is |
287 | ↔ |
288 | horizontal reuse. |
289 | ---- |
290 | ... |
291 | ---- |
292 | When |
293 | to use |
294 | Roles |
295 | ---- |
296 | My general rule |
297 | of thumb is ... |
298 | ---- |
299 | s/MI/Roles/g |
300 | ---- |
301 | When |
302 | to /not/ use |
303 | Roles |
304 | ---- |
305 | When a class |
306 | just makes |
307 | more sense. |
308 | ---- |
309 | Roles are /not/ a |
310 | replacement for |
311 | inheritance. |
312 | ---- |
313 | How Roles |
314 | Work |
315 | ---- |
316 | Roles are |
317 | orphans. |
318 | ---- |
319 | Roles are |
320 | composed. |
321 | ---- |
322 | Local class |
323 | overrides role. |
324 | ---- |
325 | Role overrides |
326 | inherited class. |
327 | ---- |
328 | Roles can |
329 | conflict. |
330 | ---- |
331 | Method conflicts |
332 | must be |
333 | disambiguated. |
334 | ---- |
335 | Attribute conflicts |
336 | cannot be |
337 | disambiguated. |
338 | ---- |
339 | package Age; |
340 | use Moose::Role; |
341 | |
342 | # ... all that type stuff |
343 | |
344 | has age => ( |
345 | is => 'rw', |
346 | isa => 'DateTime::Duration', |
347 | coerce => 1, |
348 | lazy => 1, |
349 | default => sub { |
350 | DateTime::Duration->new |
351 | }, |
352 | handles => { |
353 | 'years_old' => 'years' |
354 | } |
355 | ); |
356 | |
357 | 1; |
358 | ---- |
359 | package Person; |
360 | use Moose; |
361 | |
362 | with 'Age'; |
363 | |
364 | # ... |
365 | ---- |
366 | Conclusion |
367 | ---- |
368 | Moose code is shorter |
369 | ---- |
370 | less code == less bugs |
371 | ---- |
372 | Less testing |
373 | needed |
374 | ---- |
375 | Moose/Class::MOP |
376 | have +5400 |
377 | tests and growing |
378 | ---- |
379 | Why test, when |
380 | Moose already does. |
381 | ---- |
382 | More Readable |
383 | ---- |
384 | Declarative code |
385 | Descriptive code |
386 | ---- |
387 | The End |
388 | ---- |
389 | Questions? |
390 | ---- |
391 | ]]></html:textarea> |
392 | |
393 | <deck flex="1" id="deck"> |
394 | |
395 | <vbox flex="1" |
396 | onmousemove="Presentation.onMouseMoveOnCanvas(event);"> |
397 | <toolbox id="canvasToolbar"> |
398 | <toolbar> |
399 | <toolbarbutton oncommand="Presentation.home()" label="|<<" |
400 | observes="canBack"/> |
401 | <toolbarbutton oncommand="Presentation.back()" label="<" |
402 | observes="canBack"/> |
403 | <toolbarbutton oncommand="Presentation.forward()" label=">" |
404 | observes="canForward"/> |
405 | <toolbarbutton oncommand="Presentation.end()" label=">>|" |
406 | observes="canForward"/> |
407 | <toolbarseparator/> |
408 | <hbox align="center"> |
409 | <textbox id="current_page" size="4" |
410 | oninput="if (this.value) Presentation.showPage(parseInt(this.value)-1);"/> |
411 | <description value="/"/> |
412 | <description id="max_page"/> |
413 | </hbox> |
414 | <toolbarseparator/> |
415 | <vbox flex="2"> |
416 | <spacer flex="1"/> |
417 | <scrollbar id="scroller" |
418 | align="center" orient="horizontal" |
419 | oncommand="Presentation.showPage(parseInt(event.target.getAttribute('curpos')));" |
420 | onclick="Presentation.showPage(parseInt(event.target.getAttribute('curpos')));" |
421 | onmousedown="Presentation.onScrollerDragStart();" |
422 | onmousemove="Presentation.onScrollerDragMove();" |
423 | onmouseup="Presentation.onScrollerDragDrop();"/> |
424 | <spacer flex="1"/> |
425 | </vbox> |
426 | <toolbarseparator/> |
427 | <spacer flex="1"/> |
428 | <toolbarseparator/> |
429 | <toolbarbutton id="toggleEva" label="Eva" |
430 | type="checkbox" |
431 | autoCheck="false" |
432 | oncommand="Presentation.toggleEvaMode();"/> |
433 | <toolbarseparator/> |
434 | <toolbarbutton label="Edit" |
435 | oncommand="Presentation.toggleEditMode();"/> |
436 | <toolbarbutton oncommand="Presentation.reload();" label="Reload"/> |
437 | </toolbar> |
438 | </toolbox> |
439 | <vbox flex="1" id="canvas" |
440 | onclick="Presentation.onPresentationClick(event);"> |
441 | <spacer flex="1"/> |
442 | <hbox flex="1"> |
443 | <spacer flex="1"/> |
444 | <vbox id="content"/> |
445 | <spacer flex="1"/> |
446 | </hbox> |
447 | <spacer flex="1"/> |
448 | </vbox> |
449 | </vbox> |
450 | |
451 | |
452 | <vbox flex="1" id="edit"> |
453 | <toolbox> |
454 | <toolbar> |
455 | <toolbarbutton label="New Page" |
456 | oncommand="Presentation.addPage()"/> |
457 | <spacer flex="1"/> |
458 | <toolbarseparator/> |
459 | <toolbarbutton label="View" |
460 | oncommand="Presentation.toggleEditMode();"/> |
461 | <toolbarbutton oncommand="Presentation.reload();" label="Reload"/> |
462 | </toolbar> |
463 | </toolbox> |
464 | <textbox id="textField" flex="1" multiline="true" |
465 | oninput="Presentation.onEdit()"/> |
466 | <hbox collapsed="true"> |
467 | <iframe id="dataLoader" onload="if (window.Presentation) Presentation.onDataLoad();"/> |
468 | </hbox> |
469 | </vbox> |
470 | |
471 | </deck> |
472 | |
473 | |
474 | <broadcasterset> |
475 | <broadcaster id="canBack"/> |
476 | <broadcaster id="canForward"/> |
477 | </broadcasterset> |
478 | |
479 | <commandset> |
480 | <command id="cmd_forward" |
481 | oncommand="if (Presentation.isPresentationMode) Presentation.forward();"/> |
482 | <command id="cmd_back" |
483 | oncommand="if (Presentation.isPresentationMode) Presentation.back();"/> |
484 | <command id="cmd_home" |
485 | oncommand="if (Presentation.isPresentationMode) Presentation.home();"/> |
486 | <command id="cmd_end" |
487 | oncommand="if (Presentation.isPresentationMode) Presentation.end();"/> |
488 | </commandset> |
489 | <keyset> |
490 | <key keycode="VK_ENTER" command="cmd_forward"/> |
491 | <key keycode="VK_RETURN" command="cmd_forward"/> |
492 | <key keycode="VK_PAGE_DOWN" command="cmd_forward"/> |
493 | <key keycode="VK_RIGHT" command="cmd_forward"/> |
494 | <key keycode="VK_DOWN" command="cmd_forward"/> |
495 | <!-- key keycode="VK_BACK_SPACE" command="cmd_back"/--> |
496 | <key keycode="VK_PAGE_UP" command="cmd_back"/> |
497 | <!-- <key keycode="VK_BACK_UP" command="cmd_back"/>--> |
498 | <!-- <key keycode="VK_BACK_LEFT" command="cmd_back"/>--> |
499 | <key keycode="VK_HOME" command="cmd_home"/> |
500 | <key keycode="VK_END" command="cmd_end"/> |
501 | <key key="n" modifiers="accel" oncommand="Presentation.addPage();"/> |
502 | <key key="r" modifiers="accel" oncommand="window.location.reload();"/> |
503 | <key key="e" modifiers="accel" oncommand="Presentation.toggleEditMode();"/> |
504 | <key key="a" modifiers="accel" oncommand="Presentation.toggleEvaMode();"/> |
505 | </keyset> |
506 | |
507 | |
508 | <script src="takahashi.js" type="application/x-javascript" /> |
509 | </page> |
510 | <!-- ***** BEGIN LICENSE BLOCK ***** |
511 | - Version: MPL 1.1 |
512 | - |
513 | - The contents of this file are subject to the Mozilla Public License Version |
514 | - 1.1 (the "License"); you may not use this file except in compliance with |
515 | - the License. You may obtain a copy of the License at |
516 | - http://www.mozilla.org/MPL/ |
517 | - |
518 | - Software distributed under the License is distributed on an "AS IS" basis, |
519 | - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
520 | - for the specific language governing rights and limitations under the |
521 | - License. |
522 | - |
523 | - The Original Code is the Takahashi-Method-based Presentation Tool in XUL. |
524 | - |
525 | - The Initial Developer of the Original Code is SHIMODA Hiroshi. |
526 | - Portions created by the Initial Developer are Copyright (C) 2005 |
527 | - the Initial Developer. All Rights Reserved. |
528 | - |
529 | - Contributor(s): SHIMODA Hiroshi <piro@p.club.ne.jp> |
530 | - |
531 | - ***** END LICENSE BLOCK ***** --> |
532 | |
533 | |