| Hash-Object documentation | Contained in the Hash-Object distribution. |
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.
#.. 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};
# ...since you didn't declare this as valid it will return an error warning and not store anything.
# However, within the class, you will have direct access to the full range of the hash...
$self->{cgi} = CGI->new;
# This would work inside TieThis::Object for example.. (as well as any super class)
This method allows you to quickly create protection for an Object by using a tied hash instead of the standard hash ref. Simply, provide a list of allowed keys and a reference to the original object type.
Note: All calls to the set/retrieve keys from the tied hash object will actually call the internal methods of the same name. So consider this for mostly get/set methods or methods that do a small amount of work. This generally isn't a problem since it is bad practice to call/set blessed reference internals directly.
Reason: I like using hashes and wanted to be able to use object data as a hash without violating direct calls to the object internals. I also wanted to be able to access the object methods.
Pros: It will probably make your module much more safe and convenient to use. Cons: This is will slow things down and use more memory.
I hope this module makes it easy enough for others to begin tying up their module references.
Best luck.
new() Can be called as a class or object method. Allows for the following parameters:
keys
An arrayref of method names which list the accessible method names.
Defaults to the keys already available within the object (but don't do that).
I may update this to allow a hashref where key names are mapped to methods of
a different name.
keys
An arrayref of method names which list the accessible method names.
Defaults to the keys already available within the object (but don't do that).
I may update this to allow a hashref where key names are mapped to methods of
a different name.
sets the internally stored object. Call this first! Or inherit Tie::HashObject
and call it's new() method to do this automatically.
Jeffrey B Anderson jeff@pvrcanada.com
perltie(1). Tie::Hash
| Hash-Object documentation | Contained in the Hash-Object distribution. |
package Tie::HashObject; sub new { my $class = shift; my %args = @_; my %tied; #tie %tied, Tie::HashMethods, {keys=> $args{keys}}; tie %tied, Tie::HashMethods; my $self = bless \%tied, $class; $tied{keys} = $args{keys} if exists $args{keys}; $tied{object} = $self; return $self; } 1; package Tie::HashMethods; use strict; 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!