home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / Fuxor.pm < prev    next >
Encoding:
Perl POD Document  |  2003-02-01  |  7.0 KB  |  287 lines

  1. package Class::Fields::Fuxor;
  2.  
  3. use strict;
  4. no strict 'refs';
  5. use vars qw(@ISA @EXPORT $VERSION);
  6.  
  7. use Carp::Assert;
  8.  
  9. $VERSION = '0.06';
  10.  
  11. require Exporter;
  12. @ISA = qw(Exporter);
  13.  
  14. @EXPORT = qw(add_fields 
  15.              add_field_set
  16.              has_fields 
  17.              get_fields 
  18.              get_attr 
  19.              has_attr
  20.             );
  21.  
  22.  
  23. use constant TRUE       => (1==1);
  24. use constant FALSE      => !TRUE;
  25. use constant SUCCESS    => TRUE;
  26. use constant FAILURE    => !SUCCESS;
  27.  
  28. use Class::Fields::Attribs;
  29.  
  30. =pod
  31.  
  32. =head1 NAME
  33.  
  34.   Class::Fields::Fuxor - Low level manipuation of object data members
  35.  
  36. =head1 SYNOPSIS
  37.  
  38.   # As functions.
  39.   use Class::Fields::Fuxor;
  40.   add_fields($class, $attrib, @fields);
  41.   add_field_set($class, \@fields, \@attribs);
  42.   has_fields($class);
  43.   $fields = get_fields($class);
  44.   $fattr  = get_attr($class);
  45.  
  46.  
  47.   # As methods.
  48.   package Foo;
  49.   use base qw( Class::Fields::Fuxor );
  50.  
  51.   Foo->add_fields($attrib, @fields);
  52.   Foo->has_fields;
  53.   $fields   = Foo->get_fields;
  54.   $fattr    = Foo->get_attr;
  55.   
  56.  
  57. =head1 DESCRIPTION
  58.  
  59. This is a module for low level manipuation of the %FIELDS hash and its
  60. accompying %fields::attr hash without actually touching them.  Modules
  61. like fields.pm, base.pm and public.pm make use of this module.
  62.  
  63. %FIELDS and %fields::attr are currently used to store information
  64. about the data members of classes.  Since the current data inheritance
  65. system, built around pseudo-hashes, is considered a bit twitchy, it is
  66. wise to encapsulate and rope it off in the expectation that it will be
  67. replaced with something better.
  68.  
  69. Typically one does not want to mess with this stuff and instead uses
  70. fields.pm and friends or perhaps Class::Fields.
  71.  
  72. =cut
  73.  
  74.  
  75. # The %attr hash holds the attributes of the currently assigned fields
  76. # per class.  The hash is indexed by class names and the hash value is
  77. # an array reference.  The array is indexed with the field numbers
  78. # (minus one) and the values are integer bit masks (or undef).  The
  79. # size of the array also indicates the next field index to assign for
  80. # additional fields in this class.
  81. #
  82. # BTW %attr is part of fields for legacy reasons.  We alias it here to make
  83. # life easier.
  84. use vars qw(%attr);
  85. *attr = \%fields::attr;
  86.  
  87. =pod
  88.  
  89. =over 4
  90.  
  91. =item B<add_fields>
  92.  
  93.   add_fields($class, $attrib, @fields);
  94.  
  95. Adds a bunch of @fields to the given $class using the given $attrib.
  96. For example:
  97.  
  98.     # Add the public fields 'this' and 'that' to the class Foo.
  99.     use Class::Fields::Attribs;
  100.     add_fields('Foo', PUBLIC, qw(this that));
  101.  
  102. $attrib is built from the constants in Class::Fields::Attribs
  103.  
  104. =cut
  105.  
  106. sub add_fields {
  107.     my($proto, $attrib, @fields) = @_;
  108.     add_field_set($proto, \@fields, [($attrib) x @fields]);
  109. }
  110.  
  111. =pod
  112.  
  113. =item B<add_field_set>
  114.  
  115.   add_field_set($class, \@fields, \@attribs);
  116.  
  117. Functionally similar to add_fields(), excepting that it can add a
  118. group of fields with different attributes all at once.  This is
  119. necessary for the proper functioning of fields.pm.
  120.  
  121. Each element in @fields matches up with one in @attribs.  Obviously,
  122. the two arrays must be the same size.
  123.  
  124. =cut
  125.  
  126. sub add_field_set {
  127.     # Read the first two parameters.  The rest are field names.
  128.     my($proto, $new_fields, $new_attribs) = @_;
  129.  
  130.     assert(@$new_fields == @$new_attribs) if DEBUG;
  131.  
  132.     # Quick bail out if nothing is to be added.
  133.     return SUCCESS unless @$new_fields;
  134.  
  135.     my($class) = ref $proto || $proto;
  136.         
  137.     my $fields = get_fields($class);
  138.     my $fattr  = get_attr($class);
  139.     my $next_fno = @$fattr;
  140.  
  141.  
  142.     # Check for existing fields not belonging to base classes.
  143.     # Indicates a possible module reload.
  144.     if ($next_fno > $fattr->[0]
  145.     and ($fields->{$new_fields->[0]} || 0) >= $fattr->[0])
  146.     {
  147.         # Reset the next pointer to let the reload work.
  148.     $next_fno = $fattr->[0];
  149.     }
  150.  
  151.     # Go through the fields and attach attributes.
  152.     foreach my $idx (0..$#{$new_fields}) {
  153.         my $f      = $new_fields->[$idx];
  154.         my $attrib = $new_attribs->[$idx];
  155.         my $fno = $fields->{$f};
  156.  
  157.         # Allow the module to be reloaded so long as field positions
  158.         # have not changed.
  159.         if ($fno and $fno != $next_fno) {
  160.             require Carp;
  161.             if ($fno < $fattr->[0]) {
  162.                 Carp::carp("Hides field '$f' in base class") if $^W;
  163.             } else {
  164.                 Carp::croak("Field name '$f' already in use");
  165.             }
  166.         }
  167.         $fields->{$f} = $next_fno;
  168.         $fattr->[$next_fno] = $attrib;
  169.         $next_fno++;
  170.     }
  171. }
  172.  
  173.  
  174. =item B<has_fields>
  175.  
  176.   has_fields($class);
  177.  
  178. A simple check to see if the given $class has a %FIELDS hash defined.
  179. A simple test like (defined %{"$class\::FIELDS"}) will sometimes
  180. produce typo warnings because it would create the hash if it was not
  181. present before.
  182.  
  183. =cut
  184.  
  185. sub has_fields {
  186.     my($proto) = shift;
  187.     my($class) = ref $proto || $proto;
  188.     my $fglob;
  189.     return ($fglob = ${"$class\::"}{"FIELDS"} and *$fglob{HASH}) ? TRUE
  190.                                                                  : FALSE;
  191. }
  192.  
  193. =item B<has_attr>
  194.  
  195.   has_attr($class);
  196.  
  197. A simple check to see if the given $class has attributes.
  198.  
  199. =cut
  200.  
  201. sub has_attr {
  202.     my($proto) = shift;
  203.     my($class) = ref $proto || $proto;
  204.     return exists $attr{$class};
  205. }
  206.  
  207. =item B<get_attr>
  208.  
  209.   $fattr = get_attr($class);
  210.  
  211. Get's the field attribute array for the given $class.  This is roughly
  212. equivalent to $fields::attr{$class} but we put a nice wrapper around
  213. it for compatibility and readability.
  214.  
  215. $fattr is an array reference containing the attributes of the fields
  216. in the given $class.  Each entry in $fattr corresponds to the position
  217. indicated by the $class's %FIELDS has.  For example:
  218.  
  219.     package Foo;
  220.     use fields qw(this _that);
  221.  
  222.     $fattr = get_attr('Foo');
  223.  
  224.     # Get the attributes for '_that' in the class 'Foo'.
  225.     $that_attribs = print $fattr->[$Foo::FIELDS->{_that}];
  226.  
  227. When possible, one should avoid using this function since it exposes
  228. more implementation detail than I'd like.  Class::Fields
  229. should provide most of the functionality you'll need.
  230.  
  231. =cut
  232.  
  233. sub get_attr {
  234.     my($proto) = shift;
  235.     my($class) = ref $proto || $proto;
  236.     unless ( defined $attr{$class} ) {
  237.         $attr{$class} = [1];
  238.     }
  239.     return $attr{$class};
  240. }
  241.  
  242. =pod
  243.  
  244. =item B<get_fields>
  245.  
  246.   $fields = get_fields($class);
  247.  
  248. Gets a reference to the %FIELDS hash for the given $class.  It will
  249. autogenerate a %FIELDS hash if one doesn't already exist.  If you
  250. don't want this behavior, be sure to check beforehand with
  251. has_fields().
  252.  
  253. When possible, one should avoid using this function since it exposes
  254. more implementation detail than I'd like.  Class::Fields
  255. should provide most of the functionality you'll need.
  256.  
  257. =cut
  258.  
  259. sub get_fields {
  260.     my($proto) = shift;
  261.     my($class) = ref $proto || $proto;
  262.  
  263.     # Shut up a possible typo warning.
  264.     () = \%{$class.'::FIELDS'};
  265.  
  266.     return \%{$class.'::FIELDS'};
  267. }
  268.  
  269. =pod
  270.  
  271. =back
  272.  
  273. =head1 AUTHOR
  274.  
  275. Michael G Schwern <schwern@pobox.com> based heavily on code liberated
  276. from the original fields.pm and base.pm.
  277.  
  278.  
  279. =head1 SEE ALSO
  280.  
  281. L<fields>, L<base>, L<public>, L<private>, L<protected>,
  282. L<Class::Fields>, L<Class::Fields::Attribs>
  283.  
  284. =cut
  285.  
  286. return 'Maybe we should have stopped with Smalltalk.';
  287.