##---------------------------------------------------------------------------- ## 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. ##---------------------------------------------------------------------------- package Module::Generic::Tie; 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__