oracular (3) Class::EHierarchy.3pm.gz

Provided by: libclass-ehierarchy-perl_2.01-3_all bug

NAME

       Class::EHierarchy - Base class for hierarchally ordered objects

VERSION

       $Id: lib/Class/EHierarchy.pm, 2.01 2019/05/23 07:29:49 acorliss Exp $

SYNOPSIS

           package TelDirectory;

           use Class::EHierarchy qw(:all);
           use vars qw(@ISA @_properties @_methods);

           @ISA = qw(Class::EHierarchy);
           @_properties = (
               [ CEH_PRIV | CEH_SCALAR, 'counter',  0 ],
               [ CEH_PUB | CEH_SCALAR,  'first',   '' ],
               [ CEH_PUB | CEH_SCALAR,  'last',    '' ],
               [ CEH_PUB | CEH_ARRAY,   'telephone'   ]
               );
           @_methods = (
               [ CEH_PRIV,    '_incrCounter' ],
               [ CEH_PUB,     'addTel'       ]
               );

           sub _initalize {
               my $obj     = CORE::shift;
               my %args    = @_;
               my $rv      = 1;

               # Statically defined properties and methods are
               # defined above.  Dynamically generated
               # properties and methods can be done here.

               return $rv;
           }

           ...

           package main;

           use TelDirectory;

           my $entry = new TelDirectory;

           $entry->set('first', 'John');
           $entry->set('last',  'Doe');
           $entry->push('telephone', '555-111-2222', '555-555'5555');

DESCRIPTION

       Class::EHierarchy is intended for use as a base class for objects that need support for class or object
       hierarchies.  Additional features are also provided which can be useful for general property
       implementation and manipulation.

   OBJECT HIERARCHIES
       Object relationships are often implemented in application code, as well as the necessary reference
       storage to keep dependent objects in scope.  This class attempts to relive the programmer of that
       necessity.  To that end, the concept of an object hierarchy is implemented in this class.

       An OOP concept for RDBMS data, for instance, could be modeled as a collection of objects in the paradigm
       of a family tree.  The root object could be your DBI connection handle, while all of the internal data
       structures as child objects:

         DBH connection
           +-> views
           |     +-> view1
           +-> tables
                 +-> table1
                       +-> rows
                       |     +-> row1
                       +-> columns

       Each type of object in the RDBMS is necessarily defined in context of the parent object.

       This class simplifies the formalization of these relationships, which can have a couple of benefits.
       Consider a row object that was retrieved, for example.  If each of the columns was implemented as a
       property in the object one could allow in-memory modification of data with a delayed commit.  When the
       connection goes out of scope you could code your application to flush those in-memory modifications back
       to the database prior to garbage collection.

       This is because garbage collection of an object causes a top-down destruction of the object tree (or, in
       the depiction above, bottom-up), with the farthest removed children reaped first.

       Another benefit of defined object hierarchies is that you are no longer required to keep track of and
       maintain references to every object in the tree.  Only the root reference needs to be tracked since the
       root can also act as an object container.  All children references can be retrieved at any time via
       method calls.

       An alias system is also implemented to make children retrieval even more convenient.  Each table, for
       instance, could be aliased by their table name.  That allows you to retrieve a table object by name,
       then, instead of iterating over the collection of tables until you find one with the attributes you're
       seeking.

   CLASS HIERARCHIES
       Class hierarchies are another concept meant to allieviate some of the tedium of coding subclasses.
       Traditionally, if you subclassed a class that required any significant initialization, particularly if it
       relied on internal data structures, you would be reduced to executing superclass constructors, then
       possibly executing code paths again to account for a few changed properties.

       This class explicitly separates assignment of properties from initialization, allowing you to execute
       those code paths only once.  OOP implementations of mathematical constructs, for instance, could
       significantly alter the values derived from objects simply by subclassing and overriding some property
       values.  The original class' initializer will be run once, but using the new property values.

       In addition to that this class provides both property and method compartmentalization so that the
       original class author can limit the invasiveness of subclasses.  Both methods and properties can be
       scoped to restrict access to both.  You can restrict access to use by only the implementation class, to
       subclasses, or keep everything publically available.

   ADDITIONAL FEATURES
       The class hierarchal features necessarily make objects derived from this class opaque objects.  Objects
       aren't blessed hashes, they are scalar references with all properties stored in class data structures.

       The property implementation was made to be flexible to accommodate most needs.  A property can be a
       scalar value, but it also can be an array, hash, or a number of specific types of references.

       To make non-scalar properties almost as convenient as the raw data structures many core functions have
       been implemented as methods.  This is not just a semantic convenience, it also has the benefit of working
       directly on the raw data stored in the class storage.  Data structures aren't copied, altered, and
       stored, they are altered in place for performance.

CONSTANTS

       Functions and constants are provided strictly for use by derived classes within their defined methods.
       To avoid any confusion all of our exportable symbols are *not* exported by default.  You have to
       specifically import the all tag set.  Because these functions should not be used outside of the subclass
       they are all preceded by an underscore, like any other private function.

       The following constants are provided for use in defining your properties and methods.

           Scope
           ---------------------------------------------------------
           CEH_PRIV        private scope
           CEH_RESTR       restricted scope
           CEH_PUB         public scope

           Type
           ---------------------------------------------------------
           CEH_SCALAR      scalar value or reference
           CEH_ARRAY       array
           CEH_HASH        hash
           CEH_CODE        code reference
           CEH_GLOB        glob reference
           CEH_REF         object reference

           Flag
           ---------------------------------------------------------
           CEH_NO_UNDEF    No undef values are allowed to be
                           assigned to the property

       You'll note that both @_properties and @_methods are arrays of arrays, which each subarray containing the
       elements for each property or method.  The first element is always the attributes and the second the name
       of the property or method.  In the case of the former a third argument is also allowed:  a default value
       for the property:

         @_properties = (
               [ CEH_PUB | CEH_SCALAR, 'first',     'John' ],
               [ CEH_PUB | CEH_SCALAR, 'last',      'Doe' ],
               [ CEH_PUB | CEH_ARRAY,  'telephone',
                   [ qw(555-555-1212 555-555-5555) ] ],
           );

       Properties lacking a data type attribute default to CEH_SCALAR.  Likewise, scope defaults to CEH_PUB.
       Public methods can be omitted from @_methods since they will be assumed to be public.

       Methods only support scoping for attributes. Data types and flags are not applicable to them.

SUBROUTINES/METHODS

   new
           $obj = new MyClass;

       All of the hierarchal features require bootstrapping in order to work.  For that reason a constructor is
       provided which performs that work.  If you wish to provide additional initialization you can place a
       _initialize method in your class which will be called after the core bootstrapping is complete.

   _initialize
           $rv = $obj->_initialize(@args);

       The use of this method is optional, but if present it will be called during the execution of the
       constructor.  The boolean return value will determine if the constructor is successful or not.  All
       superclasses with such a method will be called prior to the final subclass' method, allowing you to layer
       multiple levels of initialization.

       Initialization is performed after the assignment of default values to properties.  If your code is
       dependent on those values this allows you the opportunity to override certain defaults -- assuming they
       are visible to the subclass -- simply by setting those new defaults in the subclass.

       As shown, this method is called with all of the arguments passed to the constructor, and it expects a
       boolean return value.

   conceive
           $child = MyClass->conceive($parent, @args);

       conceive is an alternate constructor that's intended for those subclasses with are dependent on
       relationships to parent objects during initialization.

   DESTROY
           $obj->DESTROY;

       Object hierarchal features require orderly destruction of children.  For that purpose a DESTROY method is
       provided which performs those tasks.  If you have specific tasks you need performed prior to the final
       destruction of an object you can place a _deconstruct method in your subclass.

   _deconstruct
           $rv = $obj->_desconstruct;

       _deconstruct is an optional method which, if present, will be called during the object's DESTROY phase.
       It will be called after all children have completed their DESTROY phase.  In keeping with the class
       hierarchal features all superclasses will have their _deconstruct methods called after your subclass'
       method is called, but prior to finishing the DESTROY phase.

   isStale
           $rv = $obj->isStale;

       It is possible that you might have stored a reference to a child object in a tree.  If you were to kick
       off destruction of the tne entire object tree by letting the root object's reference go out of scope the
       entire tree will be effectively destroyed.  Your stored child reference will not prevent that from
       happening.  At that point you effectively have a stale reference to a non-functioning object.  This
       method allows you to detect that scenario.

       The primary use for this method is as part of your safety checks in your methods:

           sub my_method {
               my $obj  = shift;
               my @args = @_;
               my $rv   = !$obj->isStale;

               if ($rv) {

                   # Do method work here, update $rv, etc.

               } else {
                   carp "called my_method on a stale object!";
               }

               return $rv;
           }

       It is important to note that this method is used in every public method provided by this base class.  All
       method calls will therefore safely fail if called on a stale object.

   _declProp
           $rv = _declProp($obj, CEH_PUB | CEH_SCALAR | CEH_NO_UNDEF, @propNames);

       This function is used to dynamically create named properties while declaring their access scope and type.

       Constants describing property attributes are OR'ed together, and only one scope and one type from each
       list should be used at a time.  Using multiple types or scopes to describe any particular property will
       make it essentially inaccessible.

       NOTE:  CEH_NO_UNDEF only applies to psuedo-scalar types like proper scalars, references, etc.  This has
       no effect on array members or hash values.

   _declMethod
           $rv = _declMethod(CEH_RESTR, @methods);

       This function is is used to create wrappers for those functions whose access you want to restrict.  It
       works along the same lines as properties and uses the same scoping constants for the attribute.

       Only methods defined within the subclass can have scoping declared.  You cannot call this method for
       inherited methods.

       NOTE: Since scoping is applied to the class symbol table (not on a per object basis) any given method can
       only be scoped once.  That means you can't do crazy things like make public methods private, or vice-
       versa.

   adopt
           $rv = $obj->adopt($cobj1, $cobj2);

       This method attempts to adopt the passed objects as children.  It returns a boolean value which is true
       only if all objects were successfully adopted.  Only subclasses for Class::EHierarchy can be adopted.
       Any object that isn't based on this class will cause this method to return a false value.

   disown
           $rv = $obj->disown($cobj1, $cobj2);

       This method attempts to disown all the passed objects as children.  It returns a boolean value based on
       its success in doing so.  Asking it to disown an object it had never adopted in the first place will be
       silently ignored and still return true.

       Disowning objects is a prerequisite for Perl's garbage collection to work and release those objects
       completely from memory.  The DESTROY method provided by this class automatically does this for parent
       objects going out of scope.  You may still need to do this explicitly if your parent object manages
       objects which may need to be released well prior to any garbage collection on the parent.

   parent
           $parent = $obj->parent;

       This method returns a reference to this object's parent object, or undef if it has no parent.

   children
           @crefs = $obj->children;

       This method returns an array of object references to every object that was adopted by the current object.

   descendents
           @descendents = $obj->descendents;

       This method returns an array of object references to every object descended from the current object.

   siblings
           @crefs = $obj->siblings;

       This method returns an array of object references to every object that shares the same parent as the
       current object.

   root
           $root = $obj->root;

       This method returns a reference to the root object in this object's ancestral tree.  In other words, the
       senior most parent in the current hierarchy.

   alias
           $rv = $obj->alias($new_alias);

       This method sets the alias for the object, returning a boolean value.  This can be false if the proposed
       alias is already in use by another object in its hierarchy.

   getByAlias
           $ref = $obj->getByAlias($name);

       This method returns an object reference from within the object's current object hierarchy by name.  It
       will return undef if the alias is not in use.

   set
           $rv  = $obj->set('FooScalar', 'random text or reference');
           $rv  = $obj->set('FooArray', @foo);
           $rv  = $obj->set('FooHash',  %foo);

       This method provides a generic property write accessor that abides by the scoping attributes given by
       _declProp or @_properties.  This means that basic reference types are checked for during assignment, as
       well as flags like CEH_NO_UNDEF.

   get
           $val = $obj->get('FooScalar');
           @val = $obj->get('FooArray');
           %val = $obj->get('FooHash');

       This method provides a generic property read accessor.  This will return an undef for nonexistent
       properties.

   properties
           @properties = $obj->properties;

       This method returns a list of all registered properties for the current object.  Property names will be
       filtered appropriately by the caller's context.

   push
           $rv = $obj->push($prop, @values);

       This method pushes additional elements onto the specified array property.  It returns the return value
       from the push function, or undef on non-existent properties or invalid types.

   pop
           $rv = $obj->pop($prop);

       This method pops an element off of the specified array property.  It returns the return value from the
       pop function, or undef on non-existent properties or invalid types.

   unshift
           $rv = $obj->unshift($prop, @values);

       This method unshifts additional elements onto the specified array property.  It returns the return value
       from the unshift function, or undef on non-existent properties or invalid types.

   shift
           $rv = $obj->shift($prop);

       This method shifts an element off of the specified array property.  It returns the return value from the
       shift function, or undef on non-existent properties or invalid types.

   exists
           $rv = $obj->exists($prop, $key);

       This method checks for the existence of the specified key in the hash property.  It returns the return
       value from the exists function, or undef on non-existent properties or invalid types.

   keys
           @keys = $obj->keys($prop);

       This method returns a list of keys from the specified hash property.  It returns the return value from
       the keys function, or undef on non-existent properties or invalid types.

   merge
           $obj->merge($prop, foo => bar);
           $obj->merge($prop, 4 => foo, 5 => bar);

       This method is a unified method for storing elements in both hashes and arrays.  Hashes elements are
       simply key/value pairs, while array elements are provided as ordinal index/value pairs.  It returns a
       boolean value.

   subset
           @values = $obj->subset($hash, qw(foo bar) );
           @values = $obj->subset($array, 3 .. 5 );

       This method is a unified method for retrieving specific element(s) from both hashes and arrays.  Hash
       values are retrieved in the order of the specified keys, while array elements are retrieved in the order
       of the specified ordinal indexes.

   remove
           $obj->remove($prop, @keys);
           $obj->remove($prop, 5, 8 .. 10);

       This method is a unified method for removing specific elements from both hashes and arrays.  A list of
       keys is needed for hash elements, a list of ordinal indexes is needed for arrays.

       NOTE: In the case of arrays please note that an element removed in the middle of an array does cause the
       following elements to be shifted accordingly.  This method is really only useful for removing a few
       elements at a time from an array.  Using it for large swaths of elements will likely prove it to be
       poorly performing.  You're better of retrieving the entire array yourself via the property method,
       splicing what you need, and calling property again to set the new array contents.

   empty
           $rv = $obj->empty($name);

       This is a unified method for emptying both array and hash properties.  This returns a boolean value.

DEPENDENCIES

       None.

BUGS AND LIMITATIONS

CREDIT

       The notion and portions of the implementation of opaque objects were lifted from Damian Conway's
       Class::Std(3) module.  Conway has a multitude of great ideas, and I'm grateful that he shares so much
       with the community.

AUTHOR

       Arthur Corliss (corliss@digitalmages.com)

       This software is licensed under the same terms as Perl, itself.  Please see http://dev.perl.org/licenses/
       for more information.

       (c) 2017, Arthur Corliss (corliss@digitalmages.com)