Re: Issue with HashRef attritubes
[email protected] (Faelin McCaley Landy) Tue, 25 Jun 2013 17:54:42 -0400
| Newsgroups | perl.moose |
|---|---|
| Message-ID | <CALciv9Eddf=PXaTs3gXyOiH1zW9pqzGwMBC5Y0PKeiGfA6Fn2w@mail.gmail.com> |
Here's a sample of the code in question (assume the appropriate pragmas for
type constraints):
has 'locations' => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef[Location]',
handles => {
add_loc => 'set',
del_loc => 'delete',
get_loc => 'get',
loc_keys => 'keys',
loc_vals => 'values',
no_locs => 'is_empty',
loc_count => 'count',
loc_pairs => 'kv',
},
);
has 'regions' => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef[Region]',
handles => {
add_region => 'set',
del_region => 'delete',
get_region => 'get',
region_keys => 'keys',
region_vals => 'values',
no_regions => 'is_empty',
region_count => 'count',
region_pairs => 'kv',
},
);
When I attempt to access the locations hashref or its handles from within
this class, I only get an error saying that it could not find the requested
hash/function. However, when I attempt to access the regions hashref/handles,
it has no problems.
Side note, I'm using namespace::sweep if that makes a difference.
On Mon, Jun 24, 2013 at 11:46 PM, Chris Weyl <[email protected]> wrote:
> On Mon, 24 Jun 2013, Faelin McCaley Landy wrote:
>
> Moose, you do confound me so! Any ideas, guys?
>>
>
> Not without seeing some of the code in question :)
>
> -Chris
>
>
Namespace.pm
(application/octet-stream, 9 KB)
package Namespace;
use namespace::sweep;
use Moose;
use Carp;
use feature 'switch';
use experimental qw(smartmatch);
use overload
'""' => '_to_string',
fallback => 1;
use Location;
use Pool;
use Region;
use Flow;
use Timeline;
use Event;
$Carp::Internal{$_}++ for qw{
Class::MOP
Class::MOP::Attribute
Class::MOP::Class
Class::MOP::Method::Wrapped
Wrapper
Container
};
sub _to_string {
my $self = shift;
return $self->name;
}
# debug output to confirm creation
sub BUILD {
my $self = shift;
DEBUG_OUTPUT: {
printf STDERR "New namespace \"$self\" created with id $self->{id}\n",
if $main::verbose < 2;
# debug output (higher verbose value means less output)
}
return $self;
};
# string that identifies the Namespace
has 'name' => ( is => 'rw', isa => 'Str', required => 1, writer => 'set_name', );
# DO NOT ACCESS -> for internal use only!
# unique IDs for objects internal to this namespace
has 'id' => ( is => 'ro', isa => 'Str', default => '00000000', writer => 'step_id', );
# tracks the object most recently added to this namespace
# Type 'IsWrapper' refers to any class that consumes 'Wrapper'
has 'recent_obj' => ( is => 'rw', isa => 'IsWrapper', writer => 'add_obj', );
# updates the ID value and gives it to the newly created object
after add_obj => sub {
my $self = shift;
my $id = $self->id;
my $new_obj = $self->recent_obj;
$new_obj->set_id( $self->step_id( ++$id ) );
# steps the current ID and assigns it to the object
# pushes new_obj into the correct hash with the current ID as a key
for (ref $new_obj) {
$self->add_pool ( $id => $new_obj ) when 'Pool';
$self->add_flow ( $id => $new_obj ) when 'Flow';
$self->add_loc ( $id => $new_obj ) when 'Location';
$self->add_region ( $id => $new_obj ) when 'Region';
$self->add_timeline ( $id => $new_obj ) when 'Timeline';
$self->add_event ( $id => $new_obj ) when 'Event';
default { $self->add_misc( $id => $new_obj ) }
}
DEBUG_OUTPUT: {
printf STDERR "%-8s %-15s spawned in namespace %6s with id %s\n",
ref $new_obj, $new_obj, $self, $new_obj->id
if $main::verbose < 1;
# debug output (higher verbose value means less output)
}
return $new_obj;
};
# DO NOT ACCESS -> for internal use only!
# tracks pools belonging to this namespace, organized by HashRef{ ID => object }
has 'pools' => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef[Pool]',
handles => {
add_pool => 'set',
del_pool => 'delete',
get_pool => 'get',
pool_keys => 'keys',
pool_vals => 'values',
no_pools => 'is_empty',
pool_count => 'count',
pool_pairs => 'kv',
},
);
# DO NOT ACCESS -> for internal use only!
# tracks flows belonging to this namespace, organized by HashRef{ ID => object }
has 'flows' => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef[Flow]',
handles => {
add_flow => 'set',
del_flow => 'delete',
get_flow => 'get',
flow_keys => 'keys',
flow_vals => 'values',
no_flows => 'is_empty',
flow_count => 'count',
flow_pairs => 'kv',
},
);
# DO NOT ACCESS -> for internal use only!
# tracks locations belonging to this namespace, organized by HashRef{ ID => object }
has 'locations' => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef[Location]',
handles => {
add_loc => 'set',
del_loc => 'delete',
get_loc => 'get',
loc_keys => 'keys',
loc_vals => 'values',
no_locs => 'is_empty',
loc_count => 'count',
loc_pairs => 'kv',
},
);
# DO NOT ACCESS -> for internal use only!
# tracks regions belonging to this namespace, organized by HashRef{ ID => object }
has 'regions' => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef[Region]',
handles => {
add_region => 'set',
del_region => 'delete',
get_region => 'get',
region_keys => 'keys',
region_vals => 'values',
no_regions => 'is_empty',
region_count => 'count',
region_pairs => 'kv',
},
);
# DO NOT ACCESS -> for internal use only!
# tracks regions belonging to this namespace, organized by HashRef{ ID => object }
has 'timelines' => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef[Timeline]',
handles => {
add_timeline => 'set',
del_timeline => 'delete',
get_timeline => 'get',
timeline_keys => 'keys',
timeline_vals => 'values',
no_timeline => 'is_empty',
timeline_count => 'count',
timeline_pairs => 'kv',
},
);
# DO NOT ACCESS -> for internal use only!
# tracks regions belonging to this namespace, organized by HashRef{ ID => object }
has 'events' => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef[Event]',
handles => {
add_event => 'set',
del_event => 'delete',
get_event => 'get',
event_keys => 'keys',
event_vals => 'values',
no_events => 'is_empty',
event_count => 'count',
event_pairs => 'kv',
},
);
# DO NOT ACCESS -> for internal use only!
# tracks regions belonging to this namespace, organized by HashRef{ ID => object }
has 'miscs' => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef[IsWrapper]',
handles => {
add_misc => 'set',
del_misc => 'delete',
get_misc => 'get',
misc_keys => 'keys',
misc_vals => 'values',
no_misc => 'is_empty',
misc_count => 'count',
misc_pairs => 'kv',
},
);
sub wrappers {
my $self = shift;
return ( $self->pool_vals,
$self->flow_vals,
$self->loc_vals,
$self->region_vals,
$self->timeline_vals,
$self->misc_vals, );
}
sub containers {
my $self = shift;
return ( $self->region_vals, );
}
# DO NOT ACCESS -> for internal use only!
# tracks retrieved addresses, organized by HashRef{ Address => Region }
has 'AddrCache' => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef[Region]',
);
# DO NOT ACCESS -> for internal use only!
# tracks retrieved names, organized by HashRef{ name => ArrayRef[Region] }
has 'NameCache' => (
traits => ['Hash'],
is => 'ro',
isa => 'HashRef[ArrayRef[Region]]',
);
sub update_cache {
my ( $self, $wrapper ) = @_;
$_[1] eq $wrapper ?
$self->AddrCache->delete( $_[0] ) : 0
for $self->AddrCache->kv;
$_[1] eq $wrapper and $_[0] ne $wrapper->name ?
( $self->NameCache->delete( $_[0] ) and $self->NameCache->set( $wrapper->name => $wrapper ) ) : 0
for $self->NameCache->kv;
}
sub retrieve {
my ( $self, $address ) = @_;
my ( @names, @possible, $parent, $child, $found );
# pulls the cached reference for $address if it exists
return $self->AddrCache->get( $address ) if $self->AddrCache->exists( $address );
# removes the "target" reference from the end of the address string
# and creates a list of the remaining references
pop ( @names = split ( '/', $address ) );
# retrieves the grandparent name from the @names array
my $grandparent = shift @names;
if ( $self->NameCache->exists( $grandparent ) ) {
@possible = $self->NameCache->get( $grandparent );
# pulls the cached array of references for $grandparent if it exists
} else {
@possible = grep { $_->name eq $grandparent } $self->containers unless @possible;
# searches this namespace for each container that matches the provided grandparent
return carp "retrieve_error: parent \"$grandparent\" not found in namespace \"$self->{name}\""
and 0 unless @possible;
# aborts the retrieval if $grandparent is not found in this namespace
$self->NameCache->set( $grandparent => @possible )
# caches the newly searched grandparent
}
# checks each Region in @possible to see if it contains the given address
PARENT: for $parent ( @possible ) {
for $child ( @names ) {
# traverses the address tree to see if the child exists under the current grandparent
$parent->owns( $child ) ?
$parent = $parent->visit( $child ) :
next PARENT;
}
# aborts the retrieval if more than one region matches the given address
$found ? ( return carp "retrieve_error: ambiguous address \"$address\"" and 0 ) : ( $found = 1 );
}
$self->AddrCache->set( $address => $parent ); # caches the newly retrieved address
return $parent; # $parent is now the grandchild reference
}
# prints the list of objects owned by this namespace
# in the format (class, name, key)
sub list_children {
my $self = shift;
my @objects_list = map { ( ref $_, $_->name, $_->id ) } sort by_id $self->wrappers;
sprintf "List of objects in $self:\n" .
"\t %8s %-15s %s \n" x ( @objects_list / 3 ),
@objects_list;
# prints a formatted list of objects in columns of (class, name, key)
}
sub by_id { $a->id ge $b->id }
1;
__PACKAGE__->meta->make_immutable;