Hash-Object
view release on metacpan or search on metacpan
HashObject.pm view on Meta::CPAN
our $VERSION = '0.01';
sub defined_public_keys {
my $self = shift;
my $keys = [];
foreach my $key (@{$self->method_keys}) {
push @$keys, $key if defined $self->{storage}->{$key};
}
return $keys;
}
sub DESTROY {
my $self = shift;
# Note: I don't know if this is neccessary.
# but it gets rid of the self reference...
$self->{object} = {};
# I worried about having a reference inside a reference... but I'm not sure whether this is a problem.
}
sub object {
my $self = shift;
$self->{object} = shift if defined $_[0];
return $self->{object};
}
sub method_keys {
my $self = shift;
$self->{keys} = shift if defined $_[0];
return $self->{keys};
}
sub TIEHASH {
my $class = shift;
my $args = shift;
my $self = bless {}, $class;
if (exists $args->{keys}) {
$self->method_keys($args->{keys});
}
return $self;
}
sub STORE {
my $self = shift;
my $key = shift;
my $value = shift;
if (!defined $self->object && $key eq 'object') {
if (ref $value) {
$self->object($value);
} else {
warn sprintf('First call to %s->{object} must be a reference to an object', __PACKAGE__);
}
}
elsif (!defined $self->method_keys && $key eq 'keys') {
$self->method_keys($value);
}
elsif ( $self->object->isa( (caller)[0] ) ) {
return $self->{storage}->{$key} = $value;
}
elsif (grep /^$key$/, @{$self->method_keys}) {
$self->object->$key($value);
}
else {
warn "Invalid key: " . $key;
}
}
sub FETCH {
my $self = shift;
my $key = shift;
if ( $self->object->isa((caller)[0]) ) {
return $self->{storage}->{$key};
}
elsif (grep /^$key$/, @{$self->method_keys}) {
return $self->object->$key;
}
else {
warn "Invalid key: " . $key;
}
}
sub FIRSTKEY {
my $self = shift;
if ( $self->object->isa((caller)[0]) ) {
return (keys %{$self->{storage}})[0];
}
else {
# we have to do this for data dumps...
return (@{$self->defined_public_keys})[0];
}
}
sub NEXTKEY {
my $self = shift;
my $last_method = shift;
my @keys;
if ( $self->object->isa((caller)[0]) ) {
@keys = keys %{$self->{storage}};
}
else {
@keys = @{$self->defined_public_keys};
}
my $next_index = 0;
foreach my $key (@keys) {
$next_index++;
last if $last_method eq $key;
}
return $next_index > scalar @keys ? undef : $keys[$next_index];
}
sub EXISTS {
my $self = shift;
my $key = shift;
if ( $self->object->isa((caller)[0]) ) {
return exists $self->{storage}->{$key};
}
else {
return (grep /^$key$/, @{$self->defined_public_keys});
}
}
sub DELETE {
my $self = shift;
my $key = shift;
if ( $self->object->isa((caller)[0]) ) {
return delete $self->{storage}->{$key};
}
else {
warn "Cannot delete methods. Please set the values instead.";
}
}
# override this method if you have some default for clearing the method hash values...
sub CLEAR {
my $self = shift;
if ( $self->object->isa((caller)[0]) ) {
$self->{storage} = {};
}
else {
warn "Cannot clear tied method calls";
}
}
sub SCALAR {
my $self = shift;
if ( $self->object->isa((caller)[0]) ) {
return scalar keys %{$self->{storage}};
}
else {
return scalar @{$self->defined_public_keys};
}
}
1;
__END__
# Below is stub documentation for your module. You better edit it!
=head1 NAME
Tie::HashObject - Perl extension for changing object methods into a limited set of allowed hash keys. Returns a tied hash with keyed access to the defined methods. The original object is accessed through a specially named key.
=head1 SYNOPSIS
#.. example ..
use Tie::HashObject;
my $some_object = Bla::Bla->new;
my %tied_hash;
tie %tied_hash, 'Tie::HashMethods', { object => $some_object, keys => [qw(method1 method2 etc)] };
#...or...
$tied = Tie::HashObject->new(
object => $someobject,
keys => [qw(method1 method2 etc)],
);
#...generally, you will want to inherit from Tie::HashObject and call it's new...
package TieThisObject;
use vars qw(Tie::HashObject);
sub method1 {$_[0]->{method1} = $_[1]}
sub method2 {$_[0]->{method2} = $_[1]}
#...then in the main program you would...
my $outside = TieThisObject->new(keys => [qw(method1 method2)]);
# Now, from the 'main' program, you will only have access to...
my $outside = TieThis::Object->new;
$outside->{method1};
$outside->{method2};
# Also, calling these keys from outside the object will actually call the related method, so...
$outside->{method1} = 5;
# ...will actually call...
$self->method1(5);
# ...from inside the TieThis::Object object.
# try this for fun...
@{$outside}{method1 method2} = qw(jelly booba);
# don't try this...
$outside->{random_key};
( run in 1.312 second using v1.01-cache-2.11-cpan-e93a5daba3e )