The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

##----------------------------------------------------------------------------
## Module Generic - ~/lib/Module/Generic/Tie.pm
## Version v1.1.0
## Copyright(c) 2021 DEGUEST Pte. Ltd.
## Author: Jacques Deguest <jack@deguest.jp>
## Created 2021/03/20
## Modified 2022/02/27
## All rights reserved
##
## This program is free software; you can redistribute it and/or modify it
## under the same terms as Perl itself.
##----------------------------------------------------------------------------
BEGIN
{
use Tie::Hash;
use strict;
use warnings;
our @ISA = qw( Tie::Hash );
our $VERSION = 'v1.1.0';
};
use strict;
sub TIEHASH
{
my $self = shift( @_ );
my $pkg = ( caller() )[0];
my %arg = ( @_ );
my $auth = [ $pkg, __PACKAGE__ ];
if( $arg{ 'pkg' } )
{
my $ok = delete( $arg{ 'pkg' } );
push( @$auth, ref( $ok ) eq 'ARRAY' ? @$ok : $ok );
}
my $priv = { 'pkg' => $auth };
my $data = { '__priv__' => $priv };
my @keys = keys( %arg );
@$priv{ @keys } = @arg{ @keys };
return( bless( $data, ref( $self ) || $self ) );
}
sub CLEAR
{
my $self = shift( @_ );
my $pkg = ( caller() )[0];
my $data = $self->{ '__priv__' };
return() if( $data->{ 'readonly' } && $pkg ne __PACKAGE__ );
if( !( $data->{ 'perms' } & 2 ) )
{
return if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
}
my $key = $self->FIRSTKEY( @_ );
my @keys = ();
while( defined( $key ) )
{
push( @keys, $key );
$key = $self->NEXTKEY( @_, $key );
}
foreach $key ( @keys )
{
$self->DELETE( @_, $key );
}
}
sub DELETE
{
my $self = shift( @_ );
my $pkg = ( caller() )[0];
$pkg = ( caller(1) )[0] if( $pkg eq 'Module::Generic' );
my $data = $self->{ '__priv__' };
return if( $_[0] eq '__priv__' && $pkg ne __PACKAGE__ );
if( !( $data->{ 'perms' } & 2 ) )
{
return() if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
}
return( delete( $self->{ shift( @_ ) } ) );
}
sub EXISTS
{
my $self = shift( @_ );
my $pkg = ref( $self );
return(0) if( $_[0] eq '__priv__' && $pkg ne __PACKAGE__ );
my $data = $self->{ '__priv__' };
if( !( $data->{ 'perms' } & 4 ) )
{
my $pkg = ( caller() )[0];
return(0) if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
}
return( exists( $self->{ shift( @_ ) } ) );
}
sub FETCH
{
my $self = shift( @_ );
my $pkg = ref( $self );
# This is a hidden entry, we return nothing
return() if( $_[0] eq '__priv__' && $pkg ne __PACKAGE__ );
my $data = $self->{ '__priv__' };
# If we have to protect our object, we hide its inner content if our caller is not our creator
# if( $data->{ 'protect' } )
if( !( $data->{ 'perms' } & 4 ) )
{
my $pkg = ( caller() )[0];
return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
}
return( $self->{ shift( @_ ) } );
}
sub FIRSTKEY
{
my $self = shift( @_ );
# my $a = scalar( keys( %$hash ) );
# return( each( %$hash ) );
my $data = $self->{ '__priv__' };
## if( $data->{ 'protect' } )
if( !( $data->{ 'perms' } & 4 ) )
{
my $pkg = ( caller(0) )[0];
return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
}
my( @keys ) = grep( !/^__priv__$/, keys( %$self ) );
$self->{ '__priv__' }->{ 'ITERATOR' } = \@keys;
return( shift( @keys ) );
}
sub NEXTKEY
{
my $self = shift( @_ );
## return( each( %$hash ) );
my $data = $self->{ '__priv__' };
## if( $data->{ 'protect' } )
if( !( $data->{ 'perms' } & 4 ) )
{
my $pkg = ( caller(0) )[0];
return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
}
my $keys = $self->{ '__priv__' }->{ 'ITERATOR' };
return( shift( @$keys ) );
}
sub STORE
{
my $self = shift( @_ );
return() if( $_[0] eq '__priv__' );
my $data = $self->{ '__priv__' };
if( !( $data->{ 'perms' } & 2 ) )
{
my $pkg = ( caller() )[0];
$pkg = ( caller(1) )[0] if( $pkg eq 'Module::Generic' );
return if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
}
$self->{ $_[0] } = $_[1];
}
1;
__END__