MooX::Attributes::Shadow If an object contains another object (i.e. the first object's attribute is a reference to the second), it's often useful to access the contained object's attributes as if they were in the container object. 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. This is the preferred approach. The Problem An object in class "A" ($a) has an attribute ("$a->b") which contains a reference to an object in class "B" ($b), which itself has an attribute "$b->attr", which you want to transparently access from $a, e.g. $a->attr => $a->b->attr; One approach might be to use method delegation: package B; has attr => ( is => 'rw' ); package A; has b => ( is => 'ro', default => sub { B->new }, handles => [ 'attr' ] ); $a = A->new; $a->attr( 3 ); # works! But, what if "attr" is a required parameter to "B"'s constructor? The default generator might look something like this: has b => ( is => 'ro', lazy => 1, default => sub { B->new( shift->attr ) }, handles => [ 'attr' ] ); $a = A->new( attr => 3 ); # doesn't work! (Note that "b" now must be lazily created, so that $a is in a deterministic state when asked for the value of "attr"). However, this doesn't work, because $a doesn't have an attribute called "attr"; that's just a method delegated to "$a->b". Oops. If you don't mind explicitly calling "B->new" in "A"'s constructor, this works: sub BUILDARGS { my $args = shift->SUPER::BUILDARGS(@_); $args->{b} //= B->new( attr => delete $args->{attr} ); return $args; } $a = A->new( attr => 3 ); # works! but now "b" can't be lazily constructed. To achieve that requires actually storing "attr" in $a. We can do that with a proxy attribute which masquerades as "attr" in "A"'s constructor: has _attr => ( is => 'ro', init_arg => 'attr' ); has b => ( is => 'ro', lazy => 1, default => sub { B->new( shift->_attr ) }, handles => [ 'attr' ] ); $a = A->new( attr => 3 ); # works! Simple, but what happens if * there's more than one attribute, or * there's more than one instance of "B" to construct, or * "A" has it's own attribute named "attr"? Endless tedium and no laziness, that's what. Hence this module. INSTALLATION This is a Perl module distribution. It should be installed with whichever tool you use to manage your installation of Perl, e.g. any of cpanm . cpan . cpanp -i . Consult http://www.cpan.org/modules/INSTALL.html for further instruction. Should you wish to install this module manually, the procedure is perl Build.PL ./Build ./Build test ./Build install COPYRIGHT AND LICENSE This software is Copyright (c) 2018 by Smithsonian Astrophysical Observatory. This is free software, licensed under: The GNU General Public License, Version 3, June 2007