Data-Hierarchy
view release on metacpan or search on metacpan
Hierarchy.pm view on Meta::CPAN
# Have to do this explicitly on the elements of @_ in order to be destructive
if ($_[1] eq $_[0]->{sep}) {
$_[1] = '';
return;
}
my $self = shift;
my $path = shift;
my $location_of_last_separator = rindex($path, $self->{sep});
return if $location_of_last_separator == -1;
my $potential_location_of_trailing_separator = (length $path) - (length $self->{sep});
return unless $location_of_last_separator == $potential_location_of_trailing_separator;
require Carp;
Carp::confess('non-root path has a trailing slash!');
}
# Internal method.
#
# Actually does property updates (to hash or sticky, depending on name).
sub _store {
my ($self, $path, $new_props) = @_;
my $old_props = exists $self->{hash}{$path} ? $self->{hash}{$path} : undef;
my $merged_props = {%{$old_props||{}}, %$new_props};
for (keys %$merged_props) {
if (index($_, '.') == 0) {
defined $merged_props->{$_} ?
$self->{sticky}{$path}{$_} = $merged_props->{$_} :
delete $self->{sticky}{$path}{$_};
delete $merged_props->{$_};
}
else {
delete $merged_props->{$_}
unless defined $merged_props->{$_};
}
}
$self->{hash}{$path} = $merged_props;
}
# Internal method.
#
# Given a hash (probably $self->{hash}, $self->{sticky}, or their union),
# returns a sorted list of the paths with data that are ancestors of the given
# path (including it itself).
sub _ancestors {
my ($self, $hash, $path) = @_;
my @ancestors;
push @ancestors, '' if exists $hash->{''};
# Special case the root.
return @ancestors if $path eq '';
my @parts = split m{\Q$self->{sep}}, $path;
# Remove empty string at the front.
my $current = '';
unless (length $parts[0]) {
shift @parts;
$current .= $self->{sep};
}
for my $part (@parts) {
$current .= $part;
push @ancestors, $current if exists $hash->{$current};
$current .= $self->{sep};
}
# XXX: could build cached pointer for fast traversal
return @ancestors;
}
# Internal method.
#
# Given a hash (probably $self->{hash}, $self->{sticky}, or their union),
# returns a sorted list of the paths with data that are descendents of the given
# path (including it itself).
sub _descendents {
my ($self, $hash, $path) = @_;
# If finding for everything, don't bother grepping
return sort keys %$hash unless length($path);
return sort grep {index($_.$self->{sep}, $path.$self->{sep}) == 0}
keys %$hash;
}
# Internal method.
#
# Returns a sorted list of all of the paths which currently have any
# properties (sticky or not) that are descendents of the given path
# (including it itself).
#
# (Note that an arg of "/f" can return entries "/f" and "/f/g" but not
# "/foo".)
sub _all_descendents {
my ($self, $path) = @_;
$self->_path_safe ($path);
my $both = {%{$self->{hash}}, %{$self->{sticky} || {}}};
return $self->_descendents($both, $path);
}
# Internal method.
#
# Given a path, a hash reference of properties, and a hash reference
# (presumably {hash} or {sticky}), removes all properties from the
# hash at the path or its descendents with the same name as a name in
# the given property hash. (The values in the property hash are
# ignored.)
sub _remove_matching_properties_recursively {
( run in 0.615 second using v1.01-cache-2.11-cpan-71847e10f99 )