1NAME
2 Class::InsideOut - a safe, simple inside-out object construction kit
3
4VERSION
5 version 1.14
6
7SYNOPSIS
8 package My::Class;
9
10 use Class::InsideOut qw( public readonly private register id );
11
12 public name => my %name; # accessor: name()
13 readonly ssn => my %ssn; # read-only accessor: ssn()
14 private age => my %age; # no accessor
15
16 sub new { register( shift ) }
17
18 sub greeting {
19 my $self = shift;
20 return "Hello, my name is $name{ id $self }";
21 }
22
23DESCRIPTION
24 This is a simple, safe and streamlined toolkit for building inside-out
25 objects. Unlike most other inside-out object building modules already on
26 CPAN, this module aims for minimalism and robustness:
27
28 * Does not require derived classes to subclass it
29
30 * Uses no source filters, attributes or "CHECK" blocks
31
32 * Supports any underlying object type including black-box inheritance
33
34 * Does not leak memory on object destruction
35
36 * Overloading-safe
37
38 * Thread-safe for Perl 5.8.5 or better
39
40 * "mod_perl" compatible
41
42 * Makes no assumption about inheritance or initializer needs
43
44 It provides the minimal support necessary for creating safe inside-out
45 objects and generating flexible accessors.
46
47 Additional documentation
48 * Class::InsideOut::Manual::About -- Guide to the inside-out
49 technique, the "Class::InsideOut" philosophy, and other inside-out
50 implementations
51
52 * Class::InsideOut::Manual::Advanced -- Advanced topics including
53 customizing accessors, black-box inheritance, serialization and
54 thread safety
55
56USAGE
57 Importing "Class::InsideOut"
58 "Class::InsideOut" automatically imports several critical methods into
59 the calling package, including "DESTROY" and support methods for
60 serializing objects with "Storable". These methods are intimately tied
61 to correct functioning of inside-out objects and will always be imported
62 regardless of whether additional functions are requested.
63
64 Additional functions may be imported as usual by including them as
65 arguments to "use". For example:
66
67 use Class::InsideOut qw( register public );
68
69 public name => my %name;
70
71 sub new { register( shift ) }
72
73 As a shortcut, "Class::InsideOut" supports two tags for importing sets
74 of functions:
75
76 * ":std" provides "id", "private", "public", "readonly" and "register"
77
78 * ":all" imports all functions (including an optional constructor)
79
80 Note: Automatic imports can be bypassed via "require" or by passing an
81 empty list to "use Class::InsideOut". There is almost no circumstance in
82 which this is a good idea.
83
84 Object properties and accessors
85 Object properties are declared with the "public", "readonly" and
86 "private" functions. They must be passed a label and the lexical hash
87 that will be used to store object properties:
88
89 public name => my %name;
90 readonly ssn => my %ssn;
91 private age => my %age;
92
93 Properties for an object are accessed through an index into the lexical
94 hash based on the memory address of the object. This memory address
95 *must* be obtained via "Scalar::Util::refaddr". The alias "id" may be
96 imported for brevity.
97
98 $name{ refaddr $self } = "James";
99 $ssn { id $self } = 123456789;
100 $age { id $self } = 32;
101
102 Tip: since "refaddr" and "id" are function calls, it may be efficient to
103 store the value once at the beginning of a method, particularly if it is
104 being called repeatedly, e.g. within a loop.
105
106 Object properties declared with "public" will have an accessor created
107 with the same name as the label. If the accessor is passed an argument,
108 the property will be set to the argument. The accessor always returns
109 the value of the property.
110
111 # Outside the class
112 $person = My::Class->new;
113 $person->name( "Larry" );
114
115 Object properties declared with "readonly" will have a read-only
116 accessor created. The accessor will die if passed an argument to set the
117 property value. The property may be set directly in the hash from within
118 the class package as usual.
119
120 # Inside the class
121 $ssn { id $person } = 987654321;
122
123 # Inside or outside the class
124 $person->ssn( 123456789 ); # dies
125
126 Property accessors may also be hand-written by declaring the property
127 "private" and writing whatever style of accessor is desired. For
128 example:
129
130 sub age { $age{ id $_[0] } }
131 sub set_age { $age{ id $_[0] } = $_[1] }
132
133 Hand-written accessors will be very slightly faster as generated
134 accessors hold a reference to the property hash rather than accessing
135 the property hash directly.
136
137 It is also possible to use a package hash instead of a lexical hash to
138 store object properties:
139
140 public name => our %name;
141
142 However, this makes private object data accessable outside the class and
143 incurs a slight performance penalty when accessing the property hash
144 directly; it is not recommended to do this unless you really need it for
145 some specialized reason.
146
147 Object construction
148 "Class::InsideOut" provides no default constructor method as there are
149 many possible ways of constructing an inside-out object. This avoids
150 constraining users to any particular object initialization or superclass
151 initialization methodology.
152
153 By using the memory address of the object as the index for properties,
154 *any* type of reference may be used as the basis for an inside-out
155 object with "Class::InsideOut".
156
157 sub new {
158 my $class = shift;
159
160 my $self = \( my $scalar ); # anonymous scalar
161 # my $self = {}; # anonymous hash
162 # my $self = []; # anonymous array
163 # open my $self, "<", $filename; # filehandle reference
164
165 bless $self, $class;
166 register( $self );
167 }
168
169 However, to ensure that the inside-out object is thread-safe, the
170 "register" function *must* be called on the newly created object. The
171 "register" function may also be called with just the class name for the
172 common case of blessing an anonymous scalar.
173
174 register( $class ); # same as register( bless \(my $s), $class )
175
176 As a convenience, "Class::InsideOut" provides an optional "new"
177 constructor for simple objects. This constructor automatically
178 initializes the object from key/value pairs passed to the constructor
179 for all keys matching the name of a property (including otherwise
180 "private" or "readonly" properties).
181
182 A more advanced technique for object construction uses another object,
183 usually a superclass object, as the object reference. See "black-box
184 inheritance" in Class::InsideOut::Manual::Advanced.
185
186 Object destruction
187 "Class::InsideOut" automatically exports a special "DESTROY" function.
188 This function cleans up object property memory for all declared
189 properties the class and for all "Class::InsideOut" based classes in the
190 @ISA array to avoid memory leaks or data collision.
191
192 Additionally, if a user-supplied "DEMOLISH" function is available in the
193 same package, it will be called with the object being destroyed as its
194 argument. "DEMOLISH" can be used for custom destruction behavior such as
195 updating class properties, closing sockets or closing database
196 connections. Object properties will not be deleted until after
197 "DEMOLISH" returns.
198
199 # Sample DEMOLISH: Count objects demolished (for whatever reason)
200
201 my $objects_destroyed;
202
203 sub DEMOLISH {
204 $objects_destroyed++;
205 }
206
207 "DEMOLISH" will only be called if it exists for an object's actual
208 class. "DEMOLISH" will not be inherited and "DEMOLISH" will not be
209 called automatically for any superclasses.
210
211 "DEMOLISH" should manage any necessary calls to superclass "DEMOLISH"
212 methods. As with "new", implementation details are left to the user
213 based on the user's approach to object inheritance. Depending on how the
214 inheritance chain is constructed and how "DEMOLISH" is being used, users
215 may wish to entirely override superclass "DEMOLISH" methods, rely upon
216 "SUPER::DEMOLISH", or may prefer to walk the entire @ISA tree:
217
218 use Class::ISA;
219
220 sub DEMOLISH {
221 my $self = shift;
222 # class specific demolish actions
223
224 # DEMOLISH for all parent classes, but only once
225 my @parents = Class::ISA::super_path( __PACKAGE__ );
226 my %called;
227 for my $p ( @parents ) {
228 my $demolish = $p->can('DEMOLISH');
229 $demolish->($self) if not $called{ $demolish }++;
230 }
231 }
232
233FUNCTIONS
234 "id"
235 $name{ id $object } = "Larry";
236
237 This is a shorter, mnemonic alias for "Scalar::Util::refaddr". It
238 returns the memory address of an object (just like "refaddr") as the
239 index to access the properties of an inside-out object.
240
241 "new"
242 My::Class->new( name => "Larry", age => 42 );
243
244 This simplistic constructor is provided as a convenience and is only
245 exported on request. When called as a class method, it returns a blessed
246 anonymous scalar. Arguments will be used to initialize all matching
247 inside-out class properties in the @ISA tree. The argument may be a hash
248 or hash reference.
249
250 Note: Properties are set directly, not via accessors. This means
251 "set_hook" functions will not be called. For more robust argument
252 checking, you will need to implement your own constructor.
253
254 "options"
255 Class::InsideOut::options( \%new_options );
256 %current_options = Class::InsideOut::options();
257
258 The "options" function sets default options for use with all subsequent
259 property definitions for the calling package. If called without
260 arguments, this function will return the options currently in effect.
261 When called with a hash reference of options, these will be joined with
262 the existing defaults, overriding any options of the same name.
263
264 "private"
265 private weight => my %weight;
266 private haircolor => my %hair_color, { %options };
267
268 This is an alias to "property" that also sets the privacy option to
269 'private'. It will override default options or options passed as an
270 argument.
271
272 "property"
273 property name => my %name;
274 property rank => my %rank, { %options };
275
276 Declares an inside-out property. Two arguments are required and a third
277 is optional. The first is a label for the property; this label will be
278 used for introspection and generating accessors and thus must be a valid
279 perl identifier. The second argument must be the lexical hash that will
280 be used to store data for that property. Note that the "my" keyword can
281 be included as part of the argument rather than as a separate statement.
282 The property will be tracked for memory cleanup during object
283 destruction and for proper thread-safety.
284
285 If a third, optional argument is provided, it must be a reference to a
286 hash of options that will be applied to the property and will override
287 any default options that have been set.
288
289 "public"
290 public height => my %height;
291 public age => my %age, { %options };
292
293 This is an alias to "property" that also sets the privacy option to
294 'public'. It will override default options or options passed as an
295 argument.
296
297 "readonly"
298 readonly ssn => my %ssn;
299 readonly fingerprint => my %fingerprint, { %options };
300
301 This is an alias to "property" that sets the privacy option to 'public'
302 and adds a "set_hook" option that dies if an attempt is made to use the
303 accessor to change the property. It will override default options or
304 options passed as an argument.
305
306 "register"
307 register( bless( $object, $class ) ); # register the object
308 register( $reference, $class ); # automatic bless
309 register( $class ); # automatic blessed scalar
310
311 Registers objects for thread-safety. This should be called as part of a
312 constructor on a object blessed into the current package. Returns the
313 resulting object. When called with only a class name, "register" will
314 bless an anonymous scalar reference into the given class. When called
315 with both a reference and a class name, "register" will bless the
316 reference into the class.
317
318OPTIONS
319 Options customize how properties are generated. Options may be set as a
320 default with the "options" function or passed as a hash reference to
321 "public", "private" or "property".
322
323 Valid options include:
324
325 "privacy"
326 property rank => my %rank, { privacy => 'public' };
327 property serial => my %serial, { privacy => 'private' };
328
329 If the *privacy* option is set to *public*, an accessor will be created
330 with the same name as the label. If the accessor is passed an argument,
331 the property will be set to the argument. The accessor always returns
332 the value of the property.
333
334 "get_hook"
335 public list => my %list, {
336 get_hook => sub { @$_ }
337 };
338
339 Defines an accessor hook for when values are retrieved. $_ is locally
340 aliased to the property value for the object. *The return value of the
341 hook is passed through as the return value of the accessor.* See
342 "Customizing Accessors" in Class::InsideOut::Manual::Advanced for
343 details.
344
345 The hook must be a coderef, including blessed coderefs and overloaded
346 objects.
347
348 "set_hook"
349 public age => my %age, {
350 set_hook => sub { /^\d+$/ or die "must be an integer" }
351 };
352
353 Defines an accessor hook for when values are set. The hook subroutine
354 receives the entire argument list. $_ is locally aliased to the first
355 argument for convenience. The property receives the value of $_. See
356 "Customizing Accessors" in Class::InsideOut::Manual::Advanced for
357 details.
358
359 The hook must be a coderef, including blessed coderefs and overloaded
360 objects.
361
362SEE ALSO
363 Programmers seeking a more full-featured approach to inside-out objects
364 are encouraged to explore Object::InsideOut. Other implementations are
365 also noted in Class::InsideOut::Manual::About.
366
367KNOWN LIMITATIONS
368 Requires weak reference support (Perl >= 5.6) and Scalar::Util::weaken()
369 to avoid memory leaks and to provide thread-safety.
370
371ROADMAP
372 Features slated for after the 1.0 release include:
373
374 * Adding support for Data::Dump::Streamer serialization hooks
375
376 * Adding additional accessor styles (e.g. get_name()/set_name())
377
378 * Further documentation revisions and clarification
379
380SUPPORT
381 Bugs / Feature Requests
382 Please report any bugs or feature requests through the issue tracker at
383 <https://github.com/dagolden/class-insideout/issues>. You will be
384 notified automatically of any progress on your issue.
385
386 Source Code
387 This is open source software. The code repository is available for
388 public review and contribution under the terms of the license.
389
390 <https://github.com/dagolden/class-insideout>
391
392 git clone https://github.com/dagolden/class-insideout.git
393
394AUTHOR
395 David Golden <dagolden@cpan.org>
396
397CONTRIBUTORS
398 * Karen Etheridge <ether@cpan.org>
399
400 * Toby Inkster <tonyink@cpan.org>
401
402COPYRIGHT AND LICENSE
403 This software is Copyright (c) 2006 by David A. Golden.
404
405 This is free software, licensed under:
406
407 The Apache License, Version 2.0, January 2004
408
409