1Class::Container(3)   User Contributed Perl Documentation  Class::Container(3)
2
3
4

NAME

6       Class::Container - Glues object frameworks together transparently
7

SYNOPSIS

9        package Car;
10        use Class::Container;
11        @ISA = qw(Class::Container);
12
13        __PACKAGE__->valid_params
14          (
15           paint  => {default => 'burgundy'},
16           style  => {default => 'coupe'},
17           windshield => {isa => 'Glass'},
18           radio  => {isa => 'Audio::Device'},
19          );
20
21        __PACKAGE__->contained_objects
22          (
23           windshield => 'Glass::Shatterproof',
24           wheel      => { class => 'Vehicle::Wheel',
25                           delayed => 1 },
26           radio      => 'Audio::MP3',
27          );
28
29        sub new {
30          my $package = shift;
31
32          # 'windshield' and 'radio' objects are created automatically by
33          # SUPER::new()
34          my $self = $package->SUPER::new(@_);
35
36          $self->{right_wheel} = $self->create_delayed_object('wheel');
37          ... do any more initialization here ...
38          return $self;
39        }
40

DESCRIPTION

42       This class facilitates building frameworks of several classes that
43       inter-operate.  It was first designed and built for "HTML::Mason", in
44       which the Compiler, Lexer, Interpreter, Resolver, Component, Buffer,
45       and several other objects must create each other transparently, passing
46       the appropriate parameters to the right class, possibly substituting
47       other subclasses for any of these objects.
48
49       The main features of "Class::Container" are:
50
51       ·   Explicit declaration of containment relationships (aggregation,
52           factory creation, etc.)
53
54       ·   Declaration of constructor parameters accepted by each member in a
55           class framework
56
57       ·   Transparent passing of constructor parameters to the class that
58           needs them
59
60       ·   Ability to create one (automatic) or many (manual) contained
61           objects automatically and transparently
62
63       Scenario
64
65       Suppose you've got a class called "Parent", which contains an object of
66       the class "Child", which in turn contains an object of the class
67       "GrandChild".  Each class creates the object that it contains.  Each
68       class also accepts a set of named parameters in its "new()" method.
69       Without using "Class::Container", "Parent" will have to know all the
70       parameters that "Child" takes, and "Child" will have to know all the
71       parameters that "GrandChild" takes.  And some of the parameters
72       accepted by "Parent" will really control aspects of "Child" or "Grand‐
73       Child".  Likewise, some of the parameters accepted by "Child" will
74       really control aspects of "GrandChild".  So, what happens when you
75       decide you want to use a "GrandDaughter" class instead of the generic
76       "GrandChild"?  "Parent" and "Child" must be modified accordingly, so
77       that any additional parameters taken by "GrandDaughter" can be accommo‐
78       dated.  This is a pain - the kind of pain that object-oriented program‐
79       ming was supposed to shield us from.
80
81       Now, how can "Class::Container" help?  Using "Class::Container", each
82       class ("Parent", "Child", and "GrandChild") will declare what arguments
83       they take, and declare their relationships to the other classes ("Par‐
84       ent" creates/contains a "Child", and "Child" creates/contains a "Grand‐
85       Child").  Then, when you create a "Parent" object, you can pass "Par‐
86       ent->new()" all the parameters for all three classes, and they will
87       trickle down to the right places.  Furthermore, "Parent" and "Child"
88       won't have to know anything about the parameters of its contained
89       objects.  And finally, if you replace "GrandChild" with "GrandDaugh‐
90       ter", no changes to "Parent" or "Child" will likely be necessary.
91

METHODS

93       new()
94
95       Any class that inherits from "Class::Container" should also inherit its
96       "new()" method.  You can do this simply by omitting it in your class,
97       or by calling "SUPER::new(@_)" as indicated in the SYNOPSIS.  The
98       "new()" method ensures that the proper parameters and objects are
99       passed to the proper constructor methods.
100
101       At the moment, the only possible constructor method is "new()".  If you
102       need to create other constructor methods, they should call "new()"
103       internally.
104
105       __PACKAGE__->contained_objects()
106
107       This class method is used to register what other objects, if any, a
108       given class creates.  It is called with a hash whose keys are the
109       parameter names that the contained class's constructor accepts, and
110       whose values are the default class to create an object of.
111
112       For example, consider the "HTML::Mason::Compiler" class, which uses the
113       following code:
114
115         __PACKAGE__->contained_objects( lexer => 'HTML::Mason::Lexer' );
116
117       This defines the relationship between the "HTML::Mason::Compiler" class
118       and the class it creates to go in its "lexer" slot.  The
119       "HTML::Mason::Compiler" class "has a" "lexer".  The "HTML::Mason::Com‐
120       piler->new()" method will accept a "lexer" parameter and, if no such
121       parameter is given, an object of the "HTML::Mason::Lexer" class should
122       be constructed.
123
124       We implement a bit of magic here, so that if "HTML::Mason::Com‐
125       piler->new()" is called with a "lexer_class" parameter, it will load
126       the indicated class (presumably a subclass of "HTML::Mason::Lexer"),
127       instantiate a new object of that class, and use it for the Compiler's
128       "lexer" object.  We're also smart enough to notice if parameters given
129       to "HTML::Mason::Compiler->new()" actually should go to the "lexer"
130       contained object, and it will make sure that they get passed along.
131
132       Furthermore, an object may be declared as "delayed", which means that
133       an object won't be created when its containing class is constructed.
134       Instead, these objects will be created "on demand", potentially more
135       than once.  The constructors will still enjoy the automatic passing of
136       parameters to the correct class.  See the "create_delayed_object()" for
137       more.
138
139       To declare an object as "delayed", call this method like this:
140
141         __PACKAGE__->contained_objects( train => { class => 'Big::Train',
142                                                    delayed => 1 } );
143
144       __PACKAGE__->valid_params(...)
145
146       Specifies the parameters accepted by this class's "new()" method as a
147       set of key/value pairs.  Any parameters accepted by a superclass/sub‐
148       class will also be accepted, as well as any parameters accepted by con‐
149       tained objects.  This method is a get/set accessor method, so it
150       returns a reference to a hash of these key/value pairs.  As a special
151       case, if you wish to set the valid params to an empty set and you pre‐
152       viously set it to a non-empty set, you may call "__PACK‐
153       AGE__->valid_params(undef)".
154
155       "valid_params()" is called with a hash that contains parameter names as
156       its keys and validation specifications as values.  This validation
157       specification is largely the same as that used by the "Params::Vali‐
158       date" module, because we use "Params::Validate" internally.
159
160       As an example, consider the following situation:
161
162         use Class::Container;
163         use Params::Validate qw(:types);
164         __PACKAGE__->valid_params
165             (
166              allow_globals        => { type => ARRAYREF, parse => 'list',   default => [] },
167              default_escape_flags => { type => SCALAR,   parse => 'string', default => '' },
168              lexer                => { isa => 'HTML::Mason::Lexer' },
169              preprocess           => { type => CODEREF,  parse => 'code',   optional => 1 },
170              postprocess_perl     => { type => CODEREF,  parse => 'code',   optional => 1 },
171              postprocess_text     => { type => CODEREF,  parse => 'code',   optional => 1 },
172             );
173
174         __PACKAGE__->contained_objects( lexer => 'HTML::Mason::Lexer' );
175
176       The "type", "default", and "optional" parameters are part of the vali‐
177       dation specification used by "Params::Validate".  The various constants
178       used, "ARRAYREF", "SCALAR", etc. are all exported by "Params::Vali‐
179       date".  This means that any of these six parameter names, plus the
180       "lexer_class" parameter (because of the "contained_objects()" specifi‐
181       cation given earlier), are valid arguments to the Compiler's "new()"
182       method.
183
184       Note that there are also some "parse" attributes declared.  These have
185       nothing to do with "Class::Container" or "Params::Validate" - any extra
186       entries like this are simply ignored, so you are free to put extra
187       information in the specifications as long as it doesn't overlap with
188       what "Class::Container" or "Params::Validate" are looking for.
189
190       $self->create_delayed_object()
191
192       If a contained object was declared with "delayed => 1", use this method
193       to create an instance of the object.  Note that this is an object
194       method, not a class method:
195
196          my $foo =       $self->create_delayed_object('foo', ...); # YES!
197          my $foo = __PACKAGE__->create_delayed_object('foo', ...); # NO!
198
199       The first argument should be a key passed to the "contained_objects()"
200       method.  Any additional arguments will be passed to the "new()" method
201       of the object being created, overriding any parameters previously
202       passed to the container class constructor.  (Could I possibly be more
203       alliterative?  Veni, vedi, vici.)
204
205       $self->delayed_object_params($name, [params])
206
207       Allows you to adjust the parameters that will be used to create any
208       delayed objects in the future.  The first argument specifies the "name"
209       of the object, and any additional arguments are key-value pairs that
210       will become parameters to the delayed object.
211
212       When called with only a $name argument and no list of parameters to
213       set, returns a hash reference containing the parameters that will be
214       passed when creating objects of this type.
215
216       $self->delayed_object_class($name)
217
218       Returns the class that will be used when creating delayed objects of
219       the given name.  Use this sparingly - in most situations you shouldn't
220       care what the class is.
221
222       __PACKAGE__->decorates()
223
224       Version 0.09 of Class::Container added [as yet experimental] support
225       for so-called "decorator" relationships, using the term as defined in
226       Design Patterns by Gamma, et al. (the Gang of Four book).  To declare a
227       class as a decorator of another class, simply set @ISA to the class
228       which will be decorated, and call the decorator class's "decorates()"
229       method.
230
231       Internally, this will ensure that objects are instantiated as decora‐
232       tors.  This means that you can mix & match extra add-on functionality
233       classes much more easily.
234
235       In the current implementation, if only a single decoration is used on
236       an object, it will be instantiated as a simple subclass, thus avoiding
237       a layer of indirection.
238
239       $self->validation_spec()
240
241       Returns a hash reference suitable for passing to the "Params::Validate"
242       "validate" function.  Does not include any arguments that can be passed
243       to contained objects.
244
245       $class->allowed_params(\%args)
246
247       Returns a hash reference of every parameter this class will accept,
248       including parameters it will pass on to its own contained objects.  The
249       keys are the parameter names, and the values are their corresponding
250       specifications from their "valid_params()" definitions.  If a parameter
251       is used by both the current object and one of its contained objects,
252       the specification returned will be from the container class, not the
253       contained.
254
255       Because the parameters accepted by "new()" can vary based on the param‐
256       eters passed to "new()", you can pass any parameters to the
257       "allowed_params()" method too, ensuring that the hash you get back is
258       accurate.
259
260       $self->container()
261
262       Returns the object that created you.  This is remembered by storing a
263       reference to that object, so we use the "Scalar::Utils" "weakref()"
264       function to avoid persistent circular references that would cause mem‐
265       ory leaks.  If you don't have "Scalar::Utils" installed, we don't make
266       these references in the first place, and calling "container()" will
267       result in a fatal error.
268
269       If you weren't created by another object via "Class::Container", "con‐
270       tainer()" returns "undef".
271
272       In most cases you shouldn't care what object created you, so use this
273       method sparingly.
274
275       $object->show_containers
276
277       $package->show_containers
278
279       This method returns a string meant to describe the containment rela‐
280       tionships among classes.  You should not depend on the specific format‐
281       ting of the string, because I may change things in a future release to
282       make it prettier.
283
284       For example, the HTML::Mason code returns the following when you do
285       "$interp->show_containers":
286
287        HTML::Mason::Interp=HASH(0x238944)
288          resolver -> HTML::Mason::Resolver::File
289          compiler -> HTML::Mason::Compiler::ToObject
290            lexer -> HTML::Mason::Lexer
291          request -> HTML::Mason::Request (delayed)
292            buffer -> HTML::Mason::Buffer (delayed)
293
294       Currently, containment is shown by indentation, so the Interp object
295       contains a resolver and a compiler, and a delayed request (or several
296       delayed requests).  The compiler contains a lexer, and each request
297       contains a delayed buffer (or several delayed buffers).
298
299       $object->dump_parameters
300
301       Returns a hash reference containing a set of parameters that should be
302       sufficient to re-create the given object using its class's "new()"
303       method.  This is done by fetching the current value for each declared
304       parameter (i.e. looking in $object for hash entries of the same name),
305       then recursing through all contained objects and doing the same.
306
307       A few words of caution here.  First, the dumped parameters represent
308       the current state of the object, not the state when it was originally
309       created.
310
311       Second, a class's declared parameters may not correspond exactly to its
312       data members, so it might not be possible to recover the former from
313       the latter.  If it's possible but requires some manual fudging, you can
314       override this method in your class, something like so:
315
316        sub dump_parameters {
317          my $self = shift;
318          my $dump = $self->SUPER::dump_parameters();
319
320          # Perform fudgery
321          $dump->{incoming} = $self->{_private};
322          delete $dump->{superfluous};
323          return $dump;
324        }
325

SEE ALSO

327       Params::Validate
328

AUTHOR

330       Originally by Ken Williams <ken@mathforum.org> and Dave Rolsky
331       <autarch@urth.org> for the HTML::Mason project.  Important feedback
332       contributed by Jonathan Swartz <swartz@pobox.com>.  Extended by Ken
333       Williams for the AI::Categorizer project.
334
335       Currently maintained by Ken Williams.
336
338       This program is free software; you can redistribute it and/or modify it
339       under the same terms as Perl itself.
340
341
342
343perl v5.8.8                       2005-01-23               Class::Container(3)
Impressum