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

SEE ALSO

533       See Class::MakeMethods for general information about this distribution.
534
535   Annotated Tutorials
536       Ron Savage has posted a pair of annotated examples, linked to below.
537       Each demonstrates building a class with MakeMethods, and each includes
538       scads of comments that walk you through the logic and demonstrate how
539       the various methods work together.
540
541         http://savage.net.au/Perl-tutorials.html
542         http://savage.net.au/Perl-tutorials/tut-33.tgz
543         http://savage.net.au/Perl-tutorials/tut-34.tgz
544
545
546
547perl v5.36.0                      2023-01-20    MakeMethods::Docs::Examples(3)
Impressum