1MakeMethods::Docs::ExamUpsleers(C3o)ntributed Perl DocumMeankteaMteitohnods::Docs::Examples(3)
2
3
4

NAME

6       Class::MakeMethods::Docs::Examples - Sample Declarations and Usage
7

EXAMPLES

9       The following examples indicate some of the capabilities of
10       Class::MakeMethods.
11
12       A Contrived Example
13
14       Object-oriented Perl code is widespread -- you've probably seen code
15       like the below a million times:
16
17         my $obj = MyStruct->new( foo=>"Foozle", bar=>"Bozzle" );
18         if ( $obj->foo() =~ /foo/i ) {
19           $obj->bar("Barbados!");
20         }
21
22       Here's a possible implementation for the class whose interface is shown
23       above:
24
25         package MyStruct;
26
27         sub new {
28           my $callee = shift;
29           my $self = bless { @_ }, (ref $callee ⎪⎪ $callee);
30           return $self;
31         }
32
33         sub foo {
34           my $self = shift;
35           if ( scalar @_ ) {
36             $self->{'foo'} = shift();
37           } else {
38             $self->{'foo'}
39           }
40         }
41
42         sub bar {
43           my $self = shift;
44           if ( scalar @_ ) {
45             $self->{'bar'} = shift();
46           } else {
47             $self->{'bar'}
48           }
49         }
50
51       Class::MakeMethods allows you to simply declare those methods to be of
52       a predefined type, and it generates and installs the necessary methods
53       in your package at compile-time.
54
55       Here's the equivalent declaration for that same basic class:
56
57         package MyStruct;
58         use Class::MakeMethods::Standard::Hash (
59           'new'       => 'new',
60           'scalar'    => 'foo',
61           'scalar'    => 'bar',
62         );
63
64       A Typical Example
65
66       The following example shows a common case of constructing a class with
67       several types of accessor methods
68
69         package MyObject;
70         use Class::MakeMethods::Standard::Hash (
71           new => 'new',
72           scalar => [ 'foo', 'bar' ],
73           array => 'my_list',
74           hash => 'my_index',
75         );
76
77       This class now has a constructor named new, two scalar accessors named
78       foo and bar, and a pair of reference accessors named my_list and
79       my_index. Typical usage of the class might include calls like the fol‐
80       lowing:
81
82         my $obj = MyObject->new( foo => 'Foozle' );
83         print $obj->foo();
84
85         $obj->bar('Barbados');
86         print $obj->bar();
87
88         $obj->my_list(0 => 'Foozle', 1 => 'Bang!');
89         print $obj->my_list(1);
90
91         $obj->my_index('broccoli' => 'Blah!', 'foo' => 'Fiddle');
92         print $obj->my_index('foo');
93
94       Lvalue Accessors
95
96       The Template subclasses support an optional "--lvalue" modifer that
97       causes your accessors method to be marked as returning an lvalue which
98       can be assigned to. (This feature is only available on Perl 5.6 or
99       later.)
100
101         package MyStruct;
102         use Class::MakeMethods::Template::Hash (
103           'new'                   => 'new',
104           'scalar --get --lvalue' => 'foo',
105           'array --get --lvalue'  => 'bar',
106         );
107
108         $obj->foo = "Foozle";
109         print $obj->foo;
110
111         $obj->bar = ( 'baz', 'beep', 'boop' );
112         print $obj->bar->[1]; # beep
113
114       String and Numeric Accessors
115
116       In addition to the "scalar" accessor supported by the "Standard::*"
117       classes, the Template subclasses also provide specialized accessors
118       that can facilitate the use of specific types of data.
119
120       For example, we could declare the following class to hold information
121       about available Perl packages:
122
123         package MyVersionInfo;
124         use Class::MakeMethods::Template::Hash (
125           'new'     => 'new',
126           'string'  => 'package',
127           'number'  => 'version',
128         );
129
130         sub summary {
131           my $self = shift;
132           return $self->package() . " is at version " . $self->version()
133         }
134
135       You could use this class as follows:
136
137         package main;
138         use MyVersionInfo;
139
140         my $obj = MyVersionInfo->new( package=>"Class::MakeMethods");
141         $obj->version( 2.0 );
142         print $obj->summary();
143
144       These accessors will provide a bit of diagnostic type checking; an
145       attempt to call "$obj->version("foo")" will cause your program to
146       croak.
147
148       String Concatenation Interface
149
150       The following defines a get_concat method "i", and specifies a string
151       to use when joining additional values when this method is called.
152
153         use Class::MakeMethods::Template::Hash
154           'string' => [ '--get_concat', 'i', { join => ' - ' } ];
155
156       (See Class::MakeMethods::Template::Generic for information about the
157       "string" "get_concat" interface.)
158
159       Access Control Example
160
161       The following defines a secret_password method, which will croak if it
162       is called from outside of the declaring package.
163
164         use Class::MakeMethods::Composite::Hash
165           'scalar' => [ 'secret_password' => { permit => 'pp' } ];
166
167       (See Class::MakeMethods::Composite for information about the "permit"
168       modifier.)
169
170       For template classes, the same thing is accomplished with '--private':
171
172         use Class::MakeMethods::Template::Hash
173           'scalar' => [ '--private', 'secret_password' ];
174
175       (See Class::MakeMethods::Template::Universal for information about the
176       "private" modifier.)
177
178       Lazy-Init Interface
179
180       Templapte scalar accessors declared with the "init_and_get" interface
181       can be used for "memoization" or lazy-evaluation for object attributes.
182       If the current accessor value is undefined, they will first call a
183       user-provided init_* method and save its value.
184
185         package MyWidget;
186         use Class::MakeMethods::Template::Hash (
187           'new --with_values' => [ 'new' ],
188           'scalar --init_and_get' => [ 'foo', 'count', 'result' ],
189         );
190
191         sub init_foo {
192           return 'foofle';
193         }
194
195         sub init_count {
196           return '3';
197         }
198
199         sub init_result {
200           my $self = shift;
201           return $self->foo x $self->count;
202         }
203         ...
204
205         my $widget = MyWidget->new();
206         print $widget->result; # output: fooflefooflefoofle
207
208         # if values are predefined, the init methods are not used
209         my $other_widget = MyWidget->new( foo => 'bar', count => 2 );
210         print $widget->result; # output: barbar
211
212       (See Class::MakeMethods::Template::Generic for more information about
213       "init_and_get". This interface is also supported by all of Generic's
214       subclasses, so you can add lazy-init methods for global data, class
215       data, array objects, etc. Unfortunately, to date it is only supported
216       for scalar-value accessors...)
217
218       Helper Methods
219
220       Template methods often include similarly-named "helper" methods. For
221       example, specifying the "--with_clear" interface for Template::*:scalar
222       methods creates an extra method for each accessor x named clear_x.
223
224         package MyClass;
225         use Class::MakeMethods::Template::Hash('scalar --with_clear' => 'foo');
226
227         my $obj = MyClass->new;
228         $obj->foo(23);
229         $obj->clear_foo;
230         print $obj->foo();
231
232       Reference Accessor and Helper Methods
233
234       For references to arrays and hashes, the Template subclasses provide
235       accessors with extra "helper methods" to facilitate method-based inter‐
236       action.
237
238       Here's a class whose instances each store a string and an array refer‐
239       ence, along with a method to search the directories:
240
241         package MySearchPath;
242         use Class::MakeMethods::Template::Hash (
243           'new'     => 'new',
244           'string'  => 'name',
245           'array'   => 'directories',
246         );
247
248         sub search {
249           my $self = shift;
250           my $target = shift;
251           foreach my $dir ( $self->directories ) {
252             my $candidate = $dir . '/' . $target;
253             return $candidate if ( -e $candidate );
254           }
255           return;
256         }
257
258       Note that the directories accessor returns the contents of the array
259       when called in a list context, making it easier to loop over.
260
261       And here's a sample usage:
262
263         package main;
264         use MySearchPath;
265
266         my $libs = MySearchPath->new( name=>"libs", directories=>['/usr/lib'] );
267         $libs->push_directories( '/usr/local/lib' );
268
269         print "Searching in " . $libs->count_directories() . "directories.\n";
270         foreach ( 'libtiff', 'libjpeg' ) {
271           my $file = $libs->search("$_.so");
272           print "Checking $_: " . ( $file ⎪⎪ 'not found' ) . "\n";
273         }
274
275       Note the use of the push_* and count_* "helper" accessor methods, which
276       are defined by default for all 'Template::*:array' declarations.
277
278       Consult Class::MakeMethods::Template::Generic for more information
279       about the available types of reference accessors, and the various meth‐
280       ods they define.
281
282       Object Accessors
283
284       There's also a specialized accessor for object references:
285
286         package MyStruct;
287         use Class::MakeMethods::Template::Hash (
288           'new'    => 'new',
289           'object' => [ 'widget' => {class=>'MyWidgetClass', delegate=>"twiddle"} ],
290         );
291
292       (Note that the "class" and "delegate" values specified above are method
293       parameters, which provide additional information about the "widget"
294       declaration; see "Standard Declaration Syntax" for more information.)
295
296       The above declaration creates methods equivalent to the following:
297
298         package MyStruct;
299
300         sub widget {
301           my $self = shift;
302           if ( scalar @_ ) {
303             if (ref $_[0] and UNIVERSAL::isa($_[0], 'MyWidgetClass')) {
304               $self->{widget} = shift;
305             } else {
306               $self->{widget} = MyWidgetClass->new(@_);
307             }
308           } else {
309             return $self->{widget};
310           }
311         }
312
313         sub clear_widget {
314           my $self = shift;
315           $self->{widget} = undef;
316         }
317
318         sub twiddle {
319           my $self = shift;
320           my $obj = $self->widget()
321             or Carp::croak("Can't forward twiddle because widget is empty");
322           $obj->twiddle(@_)
323         }
324
325       Mixing Object and Global Methods
326
327       Here's a package declaration using two of the included subclasses,
328       "Standard::Hash", for creating and accessing hash-based objects, and
329       "Basic::Global", for simple global-value accessors:
330
331         package MyQueueItem;
332
333         use Class::MakeMethods::Standard::Hash (
334           new => { name => 'new', defaults=>{ foo => 'Foozle' } },
335           scalar => [ 'foo', 'bar' ],
336           hash => 'history'
337         );
338
339         use Class::MakeMethods::Basic::Global (
340           scalar => 'Debug',
341           array  => 'InQueue',
342         );
343
344         sub AddQueueItem {
345           my $class = shift;
346           my $instance = shift;
347           $instance->history('AddQueueItem' => time());
348           $class->InQueue([0, 0], $instance);
349         }
350
351         sub GetQueueItem {
352           my $class = shift;
353           $class->InQueue([0, 1], []) or $class->new
354         }
355
356       Adding Custom Initialization to Constructors
357
358       Frequently you'll want to provide some custom code to initialize new
359       objects of your class. Most of the *:new constructor methods provides a
360       way to ensure that this code is consistently called every time a new
361       instance is created.
362
363       Composite::Hash:new { post_rules => [] }
364           The Composite classes allow you to add pre- and post-operations to
365           any method, so you can pass in a code-ref to be executed after the
366           new() method.
367
368             package MyClass;
369
370             sub new_post_init {
371               my $self = ${(pop)->{result}}; # get result of original new()
372               length($self->foo) or $self->foo('FooBar');   # default value
373               warn "Initialized new object '$self'";
374             }
375
376             use Class::MakeMethods (
377               'Composite::Hash:new' => [
378                   'new' => { post_rules=>[ \&new_post_init ] }
379               ],
380               'Composite::Hash:scalar' => 'foo;,
381             );
382             ...
383             package main;
384             my $self = MyClass->new( foo => 'Foozle' )
385
386       Template::Hash:new --and_then_init
387           Use 'Template::Hash:new --and_then_init', which will first create
388           the object and initialize it with the provided values, and then
389           call an init() method on the new object before returning it.
390
391             package MyClass;
392             use Class::MakeMethods::Template::Hash (
393               'new --and_then_init' => 'new'
394               'string'  => 'foo'
395             );
396             sub init {
397               my $self = shift;
398               length($self->foo) or $self->foo('FooBar');   # default value
399               warn "Initialized new object '$self'";
400             }
401             ...
402             package main;
403             my $self = MyClass->new( foo => 'Foozle' )
404
405       Template::Hash:new --with_init
406           If you don't want your constructor to use the default hash-of-
407           method-names style of initialization, use 'Template::Hash:new
408           --with_init', which will create an empty object, pass its arguments
409           to the init() method on the new object, and then return it.
410
411             package MyClass;
412             use Class::MakeMethods::Template::Hash (
413               'new --with_init' => 'new'
414               'string'  => 'foo'
415             );
416             sub init {
417               my $self = shift;
418               $self->foo( shift ⎪⎪ 'FooBar' ); # init with arg or default
419               warn "Initialized new object '$self'";
420             }
421             ...
422             package main;
423             my $self = MyClass->new( 'Foozle' )
424
425       Some additional notes about these constructors:
426
427       ·   The "Template::*:new" methods allow you to specify a name for your
428           method other than "init" by passing the "init_method" parameter:
429
430             use Class::MakeMethods::Template::Hash (
431               'new --and_then_init' => [
432                   'new' => { init_method =>  'my_init' }
433               ],
434             );
435
436       ·   If you know that you're not going to have a complex class hierar‐
437           chy, you can reduce resource consumption a bit by changing the
438           above declarations from "*::Hash" to "*::Array" so your objects end
439           up as blessed arrays rather than blessed hashes.
440
441       Changing Method Names
442
443       The Template subclasses allow you to control the names assigned to the
444       methods you generate by selecting from several naming interfaces.
445
446       For example, the accessors declared above use a default, Perl-ish style
447       interface, in which a single method can be called without an argument
448       to retrieve the value, or with an argument to set it.  However, you can
449       also select a more Java-like syntax, with separate get* and set* meth‐
450       ods, by including the '--java' template specification:
451
452         package MyStruct;
453         use Class::MakeMethods::Template::Hash (
454           'new'     => 'new',
455           'scalar'  => '--java Foo',
456         );
457
458       (Note that the declaration of Foo could also have been written as
459       'scalar --java' => 'Foo' or "'scalar' => ['--java', 'Foo']", or
460       "'scalar' => [ 'foo' =" { 'interface'=>'java' } ], all of which are
461       interpreted identically; see the Class::MakeMethods section on "Argu‐
462       ment Normalization" for details.)
463
464       Usage of this accessor would then be as follows:
465
466         package main;
467         use MyStruct;
468
469         my $obj = MyStruct->new( setFoo => "Foozle" );
470         print $obj->getFoo();
471         $obj->setFoo("Bozzle");
472
473       Selecting Specific Helper Methods
474
475       You can use the ability to specify interfaces to select specific helper
476       methods rather than getting the default collection.
477
478       For example, let's say you wanted to use a Template::Hash:array, but
479       you only wanted two methods to be installed in your class, a foo()
480       accessor and a shift_foo() mutator. Any of the below combinations of
481       syntax should do the trick:
482
483         use Class::MakeMethods::Template::Hash
484           'array' => [
485             'foo' => { interface=>{'foo'=>'get_set', 'shift_foo'=>'shift'} },
486           ];
487
488       If you're going to have a lot of methods with the same interface, you
489       could pre-declare a named interface once and use it repeatedly:
490
491         BEGIN {
492           require Class::MakeMethods::Template::Hash;
493           Class::MakeMethods::Template::Hash->named_method('array')->
494               {'interface'}->{'my_get_set_shift'} =
495                   { '*'=>'get_set', 'shift_*'=>'shift' };
496         }
497
498         use Class::MakeMethods::Template::Hash
499           'array --my_get_set_shift' => [ 'foo', 'bar' ];
500
501       Tree Structure Example
502
503       In this example we will create a pair of classes with references to
504       other objects.
505
506       The first class is a single-value data object implemented as a refer‐
507       ence to a scalar.
508
509         package MyTreeData;
510         use Class::MakeMethods::Template::Scalar (
511           'new'     => 'new',
512           'string'  => 'value',
513         );
514
515       The second class defines a node in a tree, with a constructor, an
516       accessor for a data object from the class above, and accessors for a
517       list of child nodes.
518
519         package MyTreeNode;
520         use Class::MakeMethods::Template::Hash (
521           'new'     => 'new',
522           'object -class MyTreeData'  => 'data',
523           'array_of_objects -class MyTreeNode' => 'children',
524         );
525
526         sub depth_first_data {
527           my $self = shift;
528           return $self->data, map { $_->depth_first_data() } $self->children;
529         }
530
531       Here's a sample of how the above classes could be used in a program.
532
533         package main;
534         use MyTreeData;
535         use MyTreeNode;
536
537         my $node = MyTreeNode->new(
538             data => { value=>'data1' },
539             children => [ { value=>'data3' } ]
540         );
541         $node->push_children( MyTreeNode->new( data => { value=>'data2' } ) );
542
543         foreach my $data ( $node->depth_first_data ) {
544           print $data->value();
545         }
546

SEE ALSO

548       See Class::MakeMethods for general information about this distribution.
549
550       Annotated Tutorials
551
552       Ron Savage has posted a pair of annotated examples, linked to below.
553       Each demonstrates building a class with MakeMethods, and each includes
554       scads of comments that walk you through the logic and demonstrate how
555       the various methods work together.
556
557         http://savage.net.au/Perl-tutorials.html
558         http://savage.net.au/Perl-tutorials/tut-33.tgz
559         http://savage.net.au/Perl-tutorials/tut-34.tgz
560
561
562
563perl v5.8.8                       2004-09-06    MakeMethods::Docs::Examples(3)
Impressum