File Coverage

blib/lib/Class/Fields.pm
Criterion Covered Total %
statement 55 79 69.6
branch 13 22 59.0
condition 6 21 28.5
subroutine 13 14 92.8
pod 5 5 100.0
total 92 141 65.2


line stmt bran cond sub pod time code
1             # $Id$
2              
3             package Class::Fields;
4              
5 3     3   37901 use strict;
  3         7  
  3         124  
6 3     3   16 no strict 'refs';
  3         8  
  3         89  
7              
8 3     3   17 use vars qw(@ISA @EXPORT $VERSION);
  3         6  
  3         373  
9             require Exporter;
10             @ISA = qw(Exporter);
11              
12             # is_* will push themselves onto @EXPORT
13             @EXPORT = qw( field_attrib_mask
14             field_attribs
15             dump_all_attribs
16             show_fields
17             is_public
18             is_private
19             is_protected
20             is_inherited
21             is_field
22             );
23              
24             $VERSION = '0.204';
25              
26 3     3   492 use Class::Fields::Fuxor;
  3         7  
  3         252  
27 3     3   16 use Class::Fields::Attribs;
  3         6  
  3         172  
28              
29             # Mapping of attribute names to their internal values.
30 3     3   15 use vars qw(%NAMED_ATTRIBS);
  3         7  
  3         260  
31             BEGIN {
32 3     3   440 %NAMED_ATTRIBS = (
33             Public => PUBLIC,
34             Private => PRIVATE,
35             Inherited => INHERITED,
36             Protected => PROTECTED,
37             );
38             }
39              
40             =pod
41              
42             =head1 NAME
43              
44             Class::Fields - Inspect the fields of a class.
45              
46              
47             =head1 SYNOPSIS
48              
49             use Class::Fields;
50              
51             is_field ($class, $field);
52             is_public ($class, $field);
53             is_private ($class, $field);
54             is_protected($class, $field);
55             is_inherited($class, $field);
56              
57             @fields = show_fields($class, @attribs);
58              
59             $attrib = field_attrib_mask($class, $field);
60             @attribs = field_attribs($class, $field);
61              
62             dump_all_attribs(@classes);
63              
64              
65             # All functions also work as methods.
66             package Foo;
67             use base qw( Class::Fields );
68              
69             Foo->is_public($field);
70             @fields = Foo->show_fields(@attribs);
71             # ...etc...
72              
73              
74             =head1 DESCRIPTION
75              
76             B This module, and the fields system, is largely obsolete.
77             Please consider using one of the many accessor generating modules, or
78             just skip directly to a complete object oriented system like L
79             or L.
80              
81             A collection of utility functions/methods for examining the data
82             members of a class. It provides a nice, high-level interface that
83             should stand the test of time and Perl upgrades nicely.
84              
85             The functions in this module also serve double-duty as methods and can
86             be used that way by having your module inherit from it. For example:
87              
88             package Foo;
89             use base qw( Class::Fields );
90             use fields qw( this that _whatever );
91              
92             print "'_whatever' is a private data member of 'Foo'" if
93             Foo->is_private('_whatever');
94              
95             # Let's assume we have a new() method defined for Foo, okay?
96             $obj = Foo->new;
97             print "'this' is a public data member of 'Foo'" if
98             $obj->is_public('this');
99              
100             =over 4
101              
102             =item B
103              
104             is_field($class, $field);
105             $class->is_field($field);
106              
107             Simply asks if a given $class has the given $field defined in it.
108              
109             =cut
110              
111             sub is_field {
112 2     2 1 11 my($proto, $field) = @_;
113              
114 2   33     9 my($class) = ref $proto || $proto;
115 2 100       4 return defined field_attrib_mask($class, $field) ? 1 : 0;
116             }
117              
118             =pod
119              
120             =item B
121              
122             =item B
123              
124             =item B
125              
126             =item B
127              
128             is_public($class, $field);
129             is_private($class, $field);
130             ...etc...
131             or
132             $obj->is_public($field);
133             or
134             Class->is_public($field);
135              
136             A bunch of functions to quickly check if a given $field in a given $class
137             is of a given type. For example...
138              
139             package Foo;
140             use public qw( Ford );
141             use private qw( _Nixon );
142              
143             package Bar;
144             use base qw(Foo);
145              
146             # This will print only 'Ford is public' because Ford is a public
147             # field of the class Bar. _Nixon is a private field of the class
148             # Foo, but it is not inherited.
149             print 'Ford is public' if is_public('Bar', 'Ford');
150             print '_Nixon is inherited' if is_inherited('Foo', '_Nixon');
151              
152              
153             =cut
154              
155             # Generate is_public, etc... from %NAMED_ATTRIBS For each attribute we
156             # generate a simple named closure. Seemed the laziest way to do it,
157             # lets us update %NAMED_ATTRIBS without having to make a new function.
158             while ( my($attrib, $attr_val) = each %NAMED_ATTRIBS ) {
159 3     3   16 no strict 'refs';
  3         7  
  3         3346  
160             my $fname = 'is_'.lc $attrib;
161             *{$fname} = sub {
162 13     13   14828 my($proto, $field) = @_;
163            
164             # So we can be called either as a function or a method from
165             # a class name or an object.
166 13   66     60 my($class) = ref $proto || $proto;
167 13         24 my $fattrib = field_attrib_mask($class, $field);
168            
169 13 100       81 return unless defined $fattrib;
170            
171 11         48 return $fattrib & $attr_val;
172             };
173            
174             push @EXPORT, $fname;
175             }
176              
177              
178             =pod
179              
180             =item B
181              
182             @all_fields = show_fields($class);
183             @fields = show_fields($class, @attribs);
184             or
185             @all_fields = $obj->show_fields;
186             @fields = $obj->show_fields(@attribs);
187             or
188             @all_fields = Class->show_fields;
189             @fields = Class->show_fields(@attribs);
190              
191             This will list all fields in a given $class that have the given set of
192             @attribs. If @attribs is not given it will simply list all fields.
193              
194             The currently available attributes are:
195             Public, Private, Protected and Inherited
196              
197             For example:
198              
199             package Foo;
200             use fields qw(this that meme);
201              
202             package Bar;
203             use Class::Fields;
204             use base qw(Foo);
205             use fields qw(salmon);
206              
207             # @fields contains 'this', 'that' and 'meme' since they are Public and
208             # Inherited. It doesn't contain 'salmon' since while it is
209             # Public it is not Inherited.
210             @fields = show_fields('Bar', qw(Public Inherited));
211              
212             =cut
213              
214             sub show_fields {
215 9     9 1 1191 my($proto, @attribs) = @_;
216              
217             # Allow its tri-nature.
218 9   33     70 my($class) = ref $proto || $proto;
219              
220 9 100       29 return unless has_fields($class);
221              
222 8         28 my $fields = get_fields($class);
223              
224             # Shortcut: Return all fields if they don't specify a set of
225             # attributes.
226 8 100       32 return keys %$fields unless @attribs;
227            
228             # Figure out the bitmask for the attribute set they'd like.
229 7         12 my $want_attr = 0;
230 7         20 foreach my $attrib (@attribs) {
231 9 50       25 unless( defined $NAMED_ATTRIBS{$attrib} ) {
232 0         0 require Carp;
233 0         0 Carp::croak("'$attrib' is not a valid field attribute");
234             }
235 9         25 $want_attr |= $NAMED_ATTRIBS{$attrib};
236             }
237              
238             # Return all fields with the requested bitmask.
239 7         22 my $fattr = get_attr($class);
240 7         23 return grep { ($fattr->[$fields->{$_}] & $want_attr) == $want_attr}
  50         172  
241             keys %$fields;
242             }
243              
244             =pod
245              
246             =item B
247              
248             $attrib = field_attrib_mask($class, $field);
249             or
250             $attrib = $obj->field_attrib_mask($field);
251             or
252             $attrib = Class->field_attrib_mask($field);
253              
254             It will tell you the numeric attribute for the given $field in the
255             given $class. $attrib is a bitmask which must be interpreted with
256             the PUBLIC, PRIVATE, etc... constants from Class::Fields::Attrib.
257              
258             field_attribs() is probably easier to work with in general.
259              
260             =cut
261              
262             sub field_attrib_mask {
263 17     17 1 24 my($proto, $field) = @_;
264 17   33     62 my($class) = ref $proto || $proto;
265 17         53 my $fields = get_fields($class);
266 17         41 my $fattr = get_attr($class);
267 17 100       54 return unless defined $fields->{$field};
268 14         38 return $fattr->[$fields->{$field}];
269             }
270              
271             =pod
272              
273             =item B
274              
275             @attribs = field_attribs($class, $field);
276             or
277             @attribs = $obj->field_attribs($field);
278             or
279             @attribs = Class->field_attribs($field);
280              
281             Exactly the same as field_attrib_mask(), except that instead of
282             returning a bitmask it returns a somewhat friendlier list of
283             attributes which are applied to this field. For example...
284              
285             package Foo;
286             use fields qw( yarrow );
287              
288             package Bar;
289             use base qw(Foo);
290              
291             # @attribs will contain 'Public' and 'Inherited'
292             @attribs = field_attribs('Bar', 'yarrow');
293              
294             The attributes returned are the same as those taken by show_fields().
295              
296             =cut
297              
298             sub field_attribs {
299 1     1 1 4 my($proto, $field) = @_;
300 1   33     8 my($class) = ref $proto || $proto;
301              
302 1         2 my @attribs = ();
303 1         3 my $attr_mask = field_attrib_mask($class, $field);
304            
305 1         5 while( my($attr_name, $attr_val) = each %NAMED_ATTRIBS ) {
306 4 100       14 push @attribs, $attr_name if $attr_mask & $attr_val;
307             }
308              
309 1         7 return @attribs;
310             }
311              
312             =pod
313              
314             =item B
315              
316             dump_all_attribs;
317             dump_all_attribs(@classes);
318             or
319             Class->dump_all_attribs;
320             or
321             $obj->dump_all_attribs;
322              
323             A debugging tool which simply prints to STDERR everything it can about
324             a given set of @classes in a relatively formated manner.
325              
326             Alas, this function works slightly differently if used as a function
327             as opposed to a method:
328              
329             When called as a function it will print out attribute information
330             about all @classes given. If no @classes are given it will print out
331             the attributes of -every- class it can find that has attributes.
332              
333             When uses as a method, it will print out attribute information for the
334             class or object which uses the method. No arguments are accepted.
335              
336             I'm not entirely happy about this split and I might change it in the
337             future.
338              
339             =cut
340              
341             # Backwards compatiblity.
342             *_dump = \&dump_all_attribs;
343              
344             #'#
345             sub dump_all_attribs {
346 0     0 1   my @classes = @_;
347              
348             # Everything goes to STDERR.
349 0           my $old_fh = select(STDERR);
350              
351             # Disallow $obj->dump_all_attribs(@classes); Too ambiguous to live.
352             # Alas, I can't check for Class->dump_all_attribs(@classes).
353 0 0 0       if ( @classes > 1 and ref $classes[0] ) {
354 0           require Carp;
355 0           Carp::croak('$obj->dump_all_attribs(@classes) is too ambiguous.'.
356             'Use only as $obj->dump_all_attribs()');
357             }
358              
359             # Allow $obj->dump_all_attribs; to work.
360 0 0 0       $classes[0] = ref $classes[0] || $classes[0] if @classes == 1;
361              
362             # Have to do a little encapsulation breaking here. Oh well, at least
363             # its keeping it in the family.
364 0 0         @classes = sort keys %fields::attr unless @classes;
365              
366 0           for my $class (@classes) {
367 0           print "\n$class";
368 0 0         if (@{"$class\::ISA"}) {
  0            
369 0           print " (", join(", ", @{"$class\::ISA"}), ")";
  0            
370             }
371 0           print "\n";
372 0           my $fields = get_fields($class);
373 0           for my $f (sort {$fields->{$a} <=> $fields->{$b}} keys %$fields) {
  0            
374 0           my $no = $fields->{$f};
375 0           print " $no: $f";
376 0           print "\t(", join(", ", field_attribs($class, $f)), ")";
377 0           print "\n";
378             }
379             }
380            
381 0           select($old_fh);
382             }
383              
384             =pod
385              
386             =head1 EXAMPLES
387              
388             Neat tricks that can be done with this module:
389              
390             =over 4
391              
392             =item An integrity check for your object.
393              
394             Upon destruction, check to make sure no strange keys were added to
395             your object hash. This is a nice check against typos and other
396             modules sticking their dirty little fingers where they shouldn't be
397             if you're not using a pseudo-hash.
398              
399             sub DESTROY {
400             my($self) = @_;
401             my($class) = ref $self;
402              
403             my %fields = map { ($_,1) } $self->show_fields;
404             foreach my $key ( keys %$self ) {
405             warn "Strange key '$key' found in object '$self' ".
406             "of class '$class'" unless
407             exists $fields{$key};
408             }
409             }
410              
411             =item Autoloaded accessors for public data members.
412              
413             Proper OO dogma tells you to do all public data access through
414             accessors (methods who's sole purpose is to get and set data in your
415             object). This can be a royal pain in the ass to write and can also
416             get rapidly unmaintainable since you wind up with a series of nearly
417             identical methods.
418              
419             *Perfect* for an autoloader!
420              
421             package Test::Autoload::Example;
422             use base qw(Class::Fields);
423             use public qw(this that up down);
424             use private qw(_left _right);
425              
426             sub AUTOLOAD {
427             my $self = $_[0];
428             my $class = ref $self;
429              
430             my($field) = $AUTOLOAD =~ /::([^:]+)$/;
431              
432             return if $field eq 'DESTROY';
433              
434             # If its a public field, set up a named closure as its
435             # data accessor.
436             if ( $self->is_public($field) ) {
437             *{$class."::$field"} = sub {
438             my($self) = shift;
439             if (@_) {
440             $self->{$field} = shift;
441             }
442             return $self->{$field};
443             };
444             goto &{$class."::$field"};
445             } else {
446             die "'$field' is not a public data member of '$class'";
447             }
448             }
449              
450             L for a much simpler version of this same
451             technique.
452              
453             =back
454              
455             =head1 COPYRIGHT AND LICENSE
456              
457             Copyright 2001-2011 by Michael G Schwern Eschwern@pobox.comE.
458              
459             This program is free software; you can redistribute it and/or
460             modify it under the same terms as Perl itself.
461              
462             See L
463              
464              
465             =head1 AUTHOR
466              
467             Michael G Schwern with much code liberated from the
468             original fields.pm.
469              
470              
471             =head1 THANKS
472              
473             Thanks to Tels for his big feature request/bug report.
474              
475              
476             =head1 SEE ALSO
477              
478             This module and the L system are obsolete.
479             L, L, L are better alternatives.
480              
481             L, L, L, L
482              
483             Modules with similar effects... L
484              
485             =cut
486              
487             return q|I'll get you next time, Gadget!|;