Alter
view release on metacpan or search on metacpan
0.02 Sat Jul 7 21:17:28 CEST 2007
- Released on CPAN
0.03 Tue Jul 10 21:14:00 CEST 2007
- Bad test report (bleadperl under linux)
Dodged by re-writing is_xs() in Perl
(The trivial is_xs() is strangely hard to make portable)
Minor pod fixes
0.04 Sun Jul 15 12:02:42 CEST 2007
- better check for Storable's attach-awareness
0.05 Mon Jul 16 21:01:53 CEST 2007
- Another tester-FAIL with Storable's attach (grr)
Version number corrected, diag added in fail case
0.07 Di Okt 9 23:29:14 CEST 2007
- changed ego() to accept (but ignore) more arguments than one
when prototype is overridden.
class name) holds the actual body of the object. Formatting- and other
options of "Data::Dumper" will change the appearance of the dump string,
with the exception of $Data::Dumper::Purity, which will always be 1.
"Dumper" can also be imported from "Alter" directly.
Note that "eval()"-ing a dump string will *not* restore the object, but
rather create a hash as described. Re-creation of an object is only
available through "Storable".
For "Storable" support the class "Alter::Storable" is provided with the
methods "STORABLE_freeze", "STORABLE_thaw" and "STORABLE_attach". The
three functions are also exported by "Alter" Their interaction with
"Storable" is described there.
Inheriting these methods allows "Storable"'s own functions "freeze()"
and "thaw()" to save and restore an object's *alter ego*s along with the
actual object body. Other "Storable" functions, like "store", "nstore",
"retrieve", etc. also become Alter-aware. There is one exception.
"Storable::dclone" cannot be used on "Alter"-based objects. To clone an
"Alter"-based object, "Storable::thaw(Storable::freeze($obj)" must be
called explicitly.
Per default, both "Alter::Dumper" and "Alter::Storable" are made base
classes of the current class (if necessary) by "use Alter". If the
function "Dumper" is imported, or if "-dumper" is specified,
"Alter::Dumper" is not made a base class. If any of the functions
"STORABLE_freeze", "STORABLE_thaw" or "STORABLE_attach" is imported, or
if "-storable" is specified, "Alter::Storable" is not made a base class.
Fallback Perl Implementation
"Alter" is properly an XS module and a suitable C compiler is required
to build it. If compilation isn't possible, the XS part is replaced with
a *pure Perl* implementation "Alter::AlterXS_in_perl". That happens
automatically at load time when loading the XS part fails. The boolean
function "Alter::is_xs" tells (in the obvious way) which implementation
is active. If, for some reason, you want to run the Perl fallback when
the XS version is available, set the environment variable
compilation has problems, it should allow you to run test cases to help
decide if it's worth trying. To make sure that production code doesn't
inadvertently run with the Perl implementation
Alter::is_xs or die "XS implementation of Alter required";
can be used.
Exports
None by default, "alter()" and "ego()" upon request. Further available
are "STORABLE_freeze", "STORABLE_thaw" and "STORABLE_attach" as well as
"Dumper". ":all" imports all these functions.
Environment
The environment variable "PERL_ALTER_NO_XS" is inspected once at load
time to decide whether to load the XS version of "Alter" or the pure
Perl fallback. At run time it has no effect.
Description
The "Alter" module is meant to facilitate the creation of classes that
support *black-box inheritance*, which is to say that an "Alter" based
lib/Alter.pm view on Meta::CPAN
package Alter;
use 5.008000;
use strict; use warnings;
our $VERSION = '0.07';
our %EXPORT_TAGS = (
all => [ qw(
alter ego
STORABLE_freeze STORABLE_attach STORABLE_thaw
Dumper
) ],
);
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
# for re-exportation
*STORABLE_freeze = \ &Alter::Storable::STORABLE_freeze;
*STORABLE_thaw = \ &Alter::Storable::STORABLE_thaw;
*STORABLE_attach = \ &Alter::Storable::STORABLE_attach;
*Dumper= \ &Alter::Dumper::Dumper;
eval {
die "Pure Perl requested" if $ENV{ PERL_ALTER_NO_XS}; # fake load failure
no warnings 'redefine';
require XSLoader;
XSLoader::load('Alter', $VERSION);
*is_xs = sub { 1 };
};
if ( $@ ) {
lib/Alter.pm view on Meta::CPAN
sub STORABLE_freeze {
my ( $obj, $cloning) = @_;
return if $cloning;
return unless $running = !$running; # return if $running was true
# $running now true, preventing recursion
Storable::freeze( $obj->Alter::image);
}
# recognized (and preferred) by Storable 2.15+, (Perl v5.8.8)
# ignored by earlier versions
sub STORABLE_attach {
my ( $class, $cloning, $ser) = @_;
++ our $attaching; # used by t/*.t, not needed for anything else
$class->Alter::reify( Storable::thaw( $ser));
}
# recognized by all versions of Storable
# incidentally, the code is equivalent to STORABLE_attach
sub STORABLE_thaw {
my ( $obj, $cloning, $ser) = @_;
++ our $thawing; # used by t/*.t, not needed for anything else
$obj->Alter::reify( Storable::thaw( $ser));
}
}
1;
__END__
lib/Alter.pm view on Meta::CPAN
the dump string, with the exception of C<$Data::Dumper::Purity>,
which will always be 1. C<Dumper> can also be imported from
C<Alter> directly.
Note that C<eval()>-ing a dump string will I<not> restore the
object, but rather create a hash as described. Re-creation of
an object is only available through C<Storable>.
For C<Storable> support the class C<Alter::Storable> is provided
with the methods C<STORABLE_freeze>, C<STORABLE_thaw> and
C<STORABLE_attach>. The three functions are also exported by C<Alter>
Their interaction with C<Storable> is described there.
Inheriting these methods allows C<Storable>'s own functions C<freeze()>
and C<thaw()> to save and restore an object's I<alter ego>s along with
the actual object body. Other C<Storable> functions, like C<store>,
C<nstore>, C<retrieve>, etc. also become Alter-aware. There is one
exception. C<Storable::dclone> cannot be used on C<Alter>-based
objects. To clone an C<Alter>-based object,
C<Storable::thaw(Storable::freeze($obj)> must be called explicitly.
Per default, both C<Alter::Dumper> and C<Alter::Storable> are made
base classes of the current class (if necessary) by C<use Alter>.
If the function C<Dumper> is imported, or if C<-dumper> is specified,
C<Alter::Dumper> is not made a base class. If any of the functions
C<STORABLE_freeze>, C<STORABLE_thaw> or C<STORABLE_attach> is imported,
or if C<-storable> is specified, C<Alter::Storable> is not made a base class.
=head3 Fallback Perl Implementation
C<Alter> is properly an XS module and a suitable C compiler is
required to build it. If compilation isn't possible, the XS part
is replaced with a I<pure Perl> implementation C<Alter::AlterXS_in_perl>.
That happens automatically at load time when loading the XS part
fails. The boolean function C<Alter::is_xs> tells (in the obvious
way) which implementation is active. If, for some reason, you want
lib/Alter.pm view on Meta::CPAN
doesn't inadvertently run with the Perl implementation
Alter::is_xs or die "XS implementation of Alter required";
can be used.
=head2 Exports
None by default, C<alter()> and C<ego()> upon request.
Further available are C<STORABLE_freeze>, C<STORABLE_thaw> and
C<STORABLE_attach> as well as C<Dumper>. C<:all> imports all these
functions.
=head2 Environment
The environment variable C<PERL_ALTER_NO_XS> is inspected once at
load time to decide whether to load the XS version of C<Alter> or
the pure Perl fallback. At run time it has no effect.
=head2 Description
t/03_class.t view on Meta::CPAN
# repeat basic tests after thread has run
is $cc->one_A, $one_A, "After thread: Class_C field 'one_A'";
is $cc->two_A, $two_A, "After thread: Class_C field 'two_A'";
is $cc->one_B, $one_B, "After thread: Class_C field 'one_B'";
is $cc->two_B, $two_B, "After thread: Class_C field 'two_B'";
} # end of SKIP block
BEGIN { $n_tests += 4 + 5 + 4 }
}
### Storable with STORABLE_attach
# ... if available, otherwise STORABLE_thaw is tested (and again below)
{
use Storable;
use constant HAS_ATTACH => 2.14; # first Storable version with attach
my ( $one_A, $two_A) = ( 'haha', []);
my ( $one_B, $two_B) = ( 'hihi', $two_A);
my $cc = Class_C->init( $one_A, $two_A, $one_B, $two_B);
$Alter::Storable::attaching = 0;
$Alter::Storable::thawing = 0;
my $clone = Storable::thaw( Storable::freeze( $cc));
my $attach_ok;
if ( $Storable::VERSION < HAS_ATTACH ) {
# Storable only recogizese STORABLE_thaw
ok $Alter::Storable::thawing, "STORABLE_thaw being used";
ok !$Alter::Storable::attaching, "STORABLE_attach not used";
$attach_ok = $Alter::Storable::thawing && !$Alter::Storable::attaching;
} else {
# Storable knows about STORABLE_attach
ok $Alter::Storable::attaching, "STORABLE_attach being used";
ok !$Alter::Storable::thawing, "STORABLE_thaw not used";
$attach_ok = !$Alter::Storable::thawing && $Alter::Storable::attaching;
}
diag "Storable $Storable::VERSION" unless $attach_ok;
is $clone->one_A, $one_A, "Cloned one_A (attach)";
is $clone->one_B, $one_B, "Cloned one_B (attach)";
isnt $clone->two_A, $two_A, "Cloned ref different (attach)";
is ref $clone->two_A, 'ARRAY', "Cloned ref type (attach)";
is $clone->two_B, $clone->two_A, "Cloned ref identity (attach)";
BEGIN { $n_tests += 7 }
}
### Storable with STORABLE_thaw
{ # reconfig Class_B to use STORABLE_thaw
package Class_B;
use Alter qw(STORABLE_thaw STORABLE_freeze);
our @ISA;
@ISA = grep !/Storable/ => @ISA; # this makes the difference
}
{
use Storable;
my ( $one_A, $two_A) = ( 'haha', []);
my ( $one_B, $two_B) = ( 'hihi', $two_A);
my $cc = Class_C->init( $one_A, $two_A, $one_B, $two_B);
$Alter::Storable::attaching = 0;
$Alter::Storable::thawing = 0;
my $clone = Storable::thaw( Storable::freeze( $cc));
ok $Alter::Storable::thawing, "STORABLE_thaw being used";
ok !$Alter::Storable::attaching, "STORABLE_attach not used";
is $clone->one_A, $one_A, "Cloned one_A (thaw)";
is $clone->one_B, $one_B, "Cloned one_B (thaw)";
isnt $clone->two_A, $two_A, "Cloned ref different (thaw)";
is ref $clone->two_A, 'ARRAY', "Cloned ref type (thaw)";
is $clone->two_B, $clone->two_A, "Cloned ref identity (thaw)";
BEGIN { $n_tests += 7 }
}
### Dumper
( run in 0.752 second using v1.01-cache-2.11-cpan-e1769b4cff6 )