Alter

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

NAME
    Alter - *Alter Ego* Objects

  Synopsis
      package MyClass;
      use Alter ego => {}; # Alter ego of type hash

      # Put data in it
      my $obj = \ do { my $o };
      ego( $obj)->{a} = 1;
      ego( $obj)->{b} = 2;

      # Retrieve it again
      print ego( $obj)->{ b}, "\n"; # prints 2

      package OtherClass;
      defined( ego $obj) or die; # dies, OtherClass hasn't set an alter ego

      # Direct access to the corona of alter egos
      my $crown = Alter::corona $obj;

  Functions
   Basic Functions
    The functions described here accept a first argument named $obj. Despite
    the name, $obj can be any reference, it doesn't *have* to be blessed
    (though it usually will be). It is a fatal error if it is not a
    reference or if the reference points to a read-only value.

    "ego($obj)"
        Retrieves the class-specific *alter ego* assigned to $obj by
        "alter()" or by autovivification if that is enabled. If neither is
        the case, an undefined value is returned. The class is the package
        into which the call to "ego()" is compiled.

    "alter($obj, $val)"
        Assigns $val to the reference $obj as an *alter ego* for the
        caller's class. The class is the package into which the call to
        "alter" is compiled. Returns $obj (*not* the value assigned).

    "Alter::corona( $obj)"
        Direct access to the *corona* of *alter ego*'s of $obj. The corona
        is a hash keyed by class name in which the alter ego's of an object
        are stored. Unlike "alter()" and "ego()", this function is not
        caller-sensitive. Returns a reference to the corona hash, which is
        created if necessary. This function is not exported, if needed it
        must be called fully qualified.

    "Alter::is_xs"
        Returns a true value if the XS implementation of "Alter" is active,
        false if the pure Perl fallback is in place.

   Autovivification
    You can set one of the types "SCALAR", "ARRAY", "HASH" or "GLOB" for
    autovivification of the alter ego. This is done by specifying the type
    in a "use" statement, as in

        package MyClass;
        use Alter 'ARRAY';

    If the "ego()" function is later called from "MyClass" before an alter
    ego has been specified using "alter()", a new *array reference* will be
    created and returned. Autovivification happens only once per class and
    object. (You would have to delete the class entry from the object's
    corona to make it happen again.)

    The type specification can also be a referece of the appropriate type,
    so "[]" can be used for "ARRAY" and "{}" for "HASH" (globrefs and scalar
    refs can also be used, but are less attractive).

    Type specification can be combined with function imports. Thus

        package MyClass;
        use Alter ego => {};

    imports the "ego()" function and specifies a hash tape for
    autovivification. With autovivification you will usually not need to
    import the "alter" function at all.

    Specifying "NOAUTO" in place of a type specification switches
    autovivification off for the current class. This is also the default.

   Serialization Support
    Serialization is supported for human inspection in "Data::Dumper" style
    and for disk storage and cloning in "Storable" style.

README  view on Meta::CPAN

    of scope. Normally the corona is invisible to the user, but the
    "Alter::corona()" function (not exported) allows direct access if
    needed.

  Example
    The example first shows how a class "Name" is built from two classes
    "First" and "Last" which implement the first and last names separately.
    "First" treats its objects as hashes whereas "Last" uses them as arrays.
    Nevertheless, the code in "Name" that joins the two classes via
    subclassing is straightforward.

    The second part of the example shows that "Alter" classes actually
    support black-box inheritance. Here, we use an object of class
    "IO::File" as the "carrier" object. This must be a globref to work. This
    object can be initialized to the class "Name", which in part sees it as
    a hash, in another part as an array. Methods of both classes now work on
    the object.

        #!/usr/local/bin/perl
        use strict; use warnings; $| = 1;

        # Show that class Name works
        my $prof = Name->new( qw( Albert Einstein));
        print $prof->fname, "\n";
        print $prof->lname, "\n";
        print $prof->name, "\n";


        # Share an object with a foreign class
        {
            package Named::Handle;
            use base 'IO::File';
            push our @ISA, qw( Name);

            sub new {
                my $class = shift;
                my ( $file, $first, $last) = @_;
                $class->IO::File::new( $file)->init( $first, $last);
            }

            sub init {
                my $nh = shift;
                $nh->Name::init( @_);
            }
        }

        my $nh = Named::Handle->new( '/dev/null', 'Bit', 'Bucket');
        print "okay, at eof\n" if $nh->eof; # IO::File methods work
        print $nh->name, "\n";      # ...as do Name methods

        exit;

        #######################################################################

        {
            package First;
            use Alter qw( alter ego);

            sub new {
                my $class = shift;
                bless( \ my $o, $class)->init( @_);
            }

            sub init {
                my $f = shift;
                alter $f, { name => shift };
                $f;
            }

            sub fname {
                my $h = ego shift;
                @_ ? $h->{ name} = shift : $h->{ name};
            }
        }

        {
            package Last;
            use Alter qw( alter ego);

            sub new {
                my $class = shift;
                bless( \ my $o, $class)->init( @_);
            }

            sub init {
                my $l = shift;
                alter $l, [ shift];
                $l;
            }

            sub lname {
                my $l = ego( shift);
                @_ ? $l->[ 0] = shift : $l->[ 0];
            }
        }

        {
            package Name;
            use base 'First';
            use base 'Last';

            sub init {
                my $n = shift;
                $n->First::init( shift);
                $n->Last::init( shift);
            }

            sub name {
                my $n = shift;
                join ' ' => $n->fname, $n->lname;
            }
        }

        __END__

  Thanks
    Thanks to Abigail who invented the inside-out technique, showhing *what*
    the problem is with Perl inheritance and *how* it could be overcome with
    just a little stroke of genius.

    Thanks also to Jerry Hedden for making me aware of the possibilities of
    "ext" magic on which this implementation of "Alter" is built.

Author
    Anno Siegel, <anno4000@zrz.tu-berlin.de>

COPYRIGHT AND LICENSE
    Copyright (C) 2007 by Anno Siegel

    This library is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself, either Perl version 5.8.7 or, at
    your option, any later version of Perl 5 you may have available.



( run in 1.858 second using v1.01-cache-2.11-cpan-39bf76dae61 )