MooX::Attributes::Shadow - shadow attributes of contained objects
# shadow Foo's attributes in Bar package Bar; use Moo; use Foo; use MooX::Attributes::Shadow ':all'; # create attributes shadowing class Foo's a and b attributes, with a # prefix to avoid collisions. shadow_attrs( Foo => attrs => [ qw( a b ) ], fmt => sub { 'pfx_' . shift }, ); # create an attribute which holds the contained oject, and # delegate the shadowed accessors to it. has foo => ( is => 'ro', lazy => 1, default => sub { Foo->new( xtract_attrs( Foo => shift ) ) }, handles => shadowed_attrs( Foo => __PACKAGE__ ), );
Classes which contain other objects at times need to reflect the contained objects' attributes in their own attributes.
In most cases, simple method delegation will suffice:
package ContainsFoo; has foo => ( is => 'ro', isa => sub { die unless eval { shift->isa('Foo') } }, handles => [ 'a' ], );
However, method delegation does not kick in when attributes are specified during instantiation of the container class. For example, in
ContainsFoo->new( a => 1 );
the delegated method for a is not called, and a is simply dropped.
a
One way of dealing with this is to establish proxy attributes which shadow Foo's attributes, and delay passing them on until after the container object has been instantiated:
Foo
has _a => ( is => 'ro', init_arg => 'a' ); sub BUILD { my $self = shift; $self->foo->a( $self->_a ); }
This requires that Foo's a attribute be of type rw. If the foo attribute can be constructed on the fly,
rw
foo
has foo => ( is => 'ro', handles => [ 'a' ], lazy => 1, sub default { my $self = shift, Foo->new( a => $self->_a ) } )
Then Foo's attribute can be of type ro.
ro
This is tedious when more than one attribute is propagated. If the container has its own a attribute, then one must do more work to avoid name space collisions.
MooX::Attributes::Shadow provides a means of registering the attributes to be shadowed, automatically creating proxy attributes in the container class, and easily extracting the shadowed attributes and values from the container class for use in the contained class's constructor.
A contained class can use MooX::Attributes::Shadow::Role to simplify things even further, so that container classes using it need not know the names of the attributes to shadow.
shadow_attrs( $contained_class, attrs => \@attrs, %options );
Create read-only attributes for the attributes in @attrs and associate them with $contained_class. There is no means of specifying additional attribute options.
@attrs
$contained_class
It takes the following options:
This is a reference to a subroutine which should return a modified attribute name (e.g. to prevent attribute collisions). It is passed the attribute name as its first parameter.
In the case where more than one instance of an object is contained, this (string) is used to identify an individual instance.
If true, the actual attribute name is mangled; the attribute initialization name is left untouched (see the init_arg option to the Moo has subroutine). This defaults to true.
init_arg
has
$attrs = shadowed_attrs( $contained, [ $container,] \%options );
Return a hash of attributes shadowed from $contained into $container. $contained and $container may either be a class name or an object. If $container is not specified, the package name of the calling routine is used.
$contained
$container
The keys in the returned hash are the attribute initialization names (not the mangled ones) in the container class; the hash values are the attribute names in the contained class. This makes it easy to delegate accessors to the contained class:
has foo => ( is => 'ro', lazy => 1, default => sub { Foo->new( xtract_attrs( Foo => shift ) ) }, handles => shadowed_attrs( 'Foo' ), );
%attrs = xtract_attrs( $contained, $container_obj, \%options );
After the container class is instantiated, xtract_attrs is used to extract attributes for the contained object from the container object. $contained may be either a class name or an object in the contained class.
Copyright 2012 Smithsonian Astrophysical Observatory
This software is released under the GNU General Public License. You may find a copy at
http://www.fsf.org/copyleft/gpl.html
Diab Jerius <djerius@cfa.harvard.edu>
To install MooX::Attributes::Shadow, copy and paste the appropriate command in to your terminal.
cpanm
cpanm MooX::Attributes::Shadow
CPAN shell
perl -MCPAN -e shell install MooX::Attributes::Shadow
For more information on module installation, please visit the detailed CPAN module installation guide.