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)

LICENSE AND COPYRIGHT

       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)