cvsuser 01/11/22 14:33:35
Modified: P5EEx/Beige/P5EEx README
Added: P5EEx/Beige/P5EEx/Beige/Registry ClassRegistery.pm
P5EEx/Beige/P5EEx/Beige/Security CallerDependentHash.pm
PublicPrivateMethods.pm
Log:
Added a few files - read readme for details.
This is a very premature release. Apologies
Revision Changes Path
1.2 +28 -0 p5ee/P5EEx/Beige/P5EEx/README
Index: README
===================================================================
RCS file: /cvs/public/p5ee/P5EEx/Beige/P5EEx/README,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -w -r1.1 -r1.2
--- README 2001/11/20 20:16:03 1.1
+++ README 2001/11/22 22:33:34 1.2
@@ -11,5 +11,33 @@
I've seen class::fields but I may be taking this in a
slightly different direction.
+*------------ New Files --------------*
+
+I've added a few files here.
+
+They contain a few large errors, but may assist
+in explaining the direction that I wish to go with this.
+( I'm not even sure if the registry stuff compiles )
+
+Basically - the short term future will involve fixing
+bugs, bringing the whole thing together in a package,
+and making sure that the dependant hash, and publicprivate
+methods interface correctly with the registry 'object',
+this together with making public private import it's new
+method should lead to a nicer environment.
+
+Although this has been developed seperate from Stephen
+Atkins blue project, it appears to be reasonably
+complementry. This fact, together with a few issues
+that are arising from other sources lead me to what
+is quite obviously a premature commit to the repository.
+
+Therefore I'll leave of declaring this on the group until
+it's a stable release
+
+I do hope you'll forgive me, comments as always,
+will be much appreciatted.
+
+Cheers,
Steve.
1.1 p5ee/P5EEx/Beige/P5EEx/Beige/Registry/ClassRegistery.pm
Index: ClassRegistery.pm
===================================================================
package ClassRegistry;
=head1 NAME
(P5EEx::Biege) Class Registry
=head1 DESCRIPTION
This is intended to allow classes to be registered
in a central reposistory
This will provide a few key features:
=head2 Register a class with a purpose
As perl is all about TMTOWTDI, it's probable that
a number of classes can be created to serve a similar
purpose.
This allows the choice of a particular class to be a
configuration rather than a programming model.
=head2 Register a class as a member of a group.
This is best illustrated by an example.
One of my bug bears with programmers is that
beginners will put print statements in objects that
could never be in an environment where it is desirable
to print from - i.e in a cgi-script before the
Content-Type Tag has been issued.
In Order to help facilitate a few more barriers,
It's nice to segregate objects into groups.
=head2 Register a Method with accessing groups
This takes the public/private thing one step futher,
and I can't resist a slight analogy.
Just because you work with someone doesn't emply you
want to drink with them, or go even further...
Likewise, whilst you may allow any object to check
for the existence of a file, you wouldn't necessarily
want any old perl fragment to be able to delete it.
=head2 Register a Method with named arguments.
Whilst you can have named arguments in perl:
my %args = (
Arg1 => undef,
Arg2 => undef,
@_
);
It's incredibly easy to implement this in perl,
and unfortunately it's also easy to call the
wrong stored procedure with the wrong arguments
For example, whilst still in my early days of perl
programming, I wrote the something like following:
prunk ( Roger => "Hello World" );
sub prunk
{
my %args=(
Rodger => undef,
@_
);
print $args{Rodger};
}
And it took me a wee while to find out the cause
of the error.
And finally, yes, it is slower, but hey, it looks
so much clearer. and programmers can sometimes be more
expensive than CPU or memory...
=head2 Lock The Registry
Otherwise some smart arse will just modify the
attributes of the particular module he wants to call
in order to allow him access.
Sod's law. Hopefully by the time they have the time
to break the finalised version, they will have learnt
why they shouldn't.
Unless of course they are bad people.
=head1 Methods
=cut
{
my $object = bless {};
$object -> {NextGroup} = 0;
$object -> Purpose = {};
$object -> Groups = {Default => {
ID => $object -> {NextGroup}++,
Description => 'Default group'
};
=head2 GenerateGroup
You need to generate a group before you can define
it on a class. A default group, 'Default' is provided.
Usage:
my $id = bob;
ClassRegistry::GenerateGroup(
Name => "Sue",
Description => 'A group called Sue.',
GroupId => \$id
);
=cut
sub GenerateGroup
{
die "Object Locked\n" if ( defined $object -> {Lock} );
my %args = (
Name => undef,
Description => 'A badly defined group.',
@_
);
die "Bad Generation Attempt\n" unless (
defined $args{Name}
);
die "Attempt To Regenerate Group\n" if (
exists $object -> {Groups} -> { $args{Name} }
);
my $t = $object -> {NextGroup}++;
$object -> {Groups} -> { $args{Name} } = {
Description => "".$args{Description},
ID => $t,
};
};
=head2 RegisterClass
Registers a class's purpose, and it's group
Usage:
ClassRegistry::RegisterPurpose (
Class => "Example::Package",
Purpose => "Purpose::Of::Package",
Group => "Sue"
);
=cut
sub RegisterPurpose
{
die "Object Locked\n" if ( defined $object -> {Lock} );
my %args = (
Class => undef,
Purpose => undef,
Group => 0,
@_
);
die "Bad Group\n" unless ( exists ${$object -> {Groups}}{ $args{Group} } );
$object -> {Purpose} -> {$args{Purpose}} =
{
Class => $args{Class},
Group => ${ $object -> {Groups} -> {$args{Group}} }{ID}
};
};
=head2 Lock
Usage:
ClassRegistry::Lock();
Locks the registry so that no more modifications can be made.
=cut
sub Lock
{
$object -> {Lock} = 1;
};
=head2 RegisterMethod
Registers a Method with a set of arguments,
with validation and accessing groups.
Usage:
ClassRegistry::RegisterMethod(
Purpose => 'Purpose::Of::Package',
Method => 'MethodName',
Arguments => {
Argument1 => 'ref $_ eq "HASH"',
Argument2 => "! ref $_",
Argument3 => "( ref $_ eq 'Hash' || ref $_ eq 'Array' )",
},
Groups => ['Sue'],
);
I really need to make this more efficient. Recomendations welcome.
I didn't want to put much effort into any of this as it's an expirement.
=cut
sub RegisterMethod
{
die "Object Locked\n" if ( defined $object -> {Lock} );
my %args = (
Purpose => undef,
Method => undef,
Arguments => {},
Groups => [],
@_
);
die "Bad Purpose\n" unless ( exists $object -> {Purpose} -> {$args{Purpose}}
);
die "No method\n" unless ( defined ref $args{Method} );
die "Bad Arguments\n" unless ( ref $args{Arguments} eq "HASH" );
die "Bad Groups\n" unless ( ref $args{Groups} eq "ARRAY" );
die "Method Already Exists\n" if ( exists ${ $object -> {Purpose} ->
{$args{Purpose}} }{Methods} );
my %groups;
map {
(
defined ( my $g = ${}{$_} ) ?
$groups{ ${ $object -> {Groups} -> {$_} }{ID} } = undef :
die "Bad Group".$_;
)
} @{$args{Groups}};
# Generate subroutene to validate arguments
my $sub =
eval
"
sub {
my %h = ("
.join ',',(map { $_." => " undef } keys %{ $args{Argument} } ) #
copy in arguments
.",@_);
die \"BadArguments\n\" unless ( scalar ( keys %h ) eq
".scalar(keys %{ $args{Argument} })." );
".
# Heres where field validation takes place
join '',( map {
'for ( $h{'.$_.'} ){ die "Argument Invalid :'.$_.'\n" unless
'.
${ $args{Arguments} }{$_}.'; };'
} keys %{ $args{Arguments} } )
."
};
";
die "Cannot Generate Subroutene\n" if ( $@ );
# And place subroutene and groups into object data
${ $object -> {Purpose} -> {$args{Purpose}} }{Methods} = {
Groups => \%groups,
Validate => $sub
};
};
=head2 CanCall
This tests to see if a given purpose can call a method
belonging to another purpose.
=cut
sub CanCall
{
my %args = (
CallingPurpose => undef,
Purpose => undef,
Method => undef,
Arguments => {},
@_
);
die "Calling Purpose does not exist\n " unless ( exists $object ->
{Groups} -> { $args{CallingPurpose} } );
die "Purpose does not exist\n" unless ( exists $object -> {Groups} ->
{ $args{CallingPurpose} } );
die "Method does not exist\n" unless ( exists ${ $object -> {Purpose}
-> {$args{Purpose}} }{Methods} );
die "Permission denied on object\n" unless ( exists $object ->
{Purpose} -> {$args{Purpose}} } -> {Methods} -> {Groups} ->
{ $object -> {Groups} -> {
$args{CallingPurpose} } -> {ID} } )
&{$object -> {Purpose} -> {$args{Purpose}} } -> {Methods} -> {Groups}
-> {Validate} }( %{ $args{Arguments} } );
return 1;
};
};
=head1 TODO
This isn't my final opinion on the subject, just the
my current opinion. I'll end up kicking and cursing
myself later.
Wouldn't mind adding some sort of error repository also.
And it's a first cut. I'm sure there are beter techniques
which can be used to achieve the same purpose. The means
of using this to generate could also do with some work.
=cut
'The green teletubby is an underated charactor actor, IMHO';
1.1 p5ee/P5EEx/Beige/P5EEx/Beige/Security/CallerDependentHash.pm
Index: CallerDependentHash.pm
===================================================================
#!/usr/local/bin/perl
=pod
=head1 NAME
P5EEx::Biege::Security::CallerDependentHash;
=head1 DESCRIPTION
This creates a tied hash which behaves quite
like a normal hash with two key exceptions.
The first is that a list of classes must
be specified in order to tie the package.
The second is that the hash is visible
only to the class that begat it.
Each of the different classes see a different
view of the hash.
=head1 METHODS
Everything you would expect to be in a normal
hash really.
=cut
use strict;
package Security::CallerDependentHash;
sub TIEHASH
{
my $class = shift;
my %args = (
AccessClass => undef,
@_
);
my %access;
if ( ref $args{AccessClass} eq "ARRAY" )
{
map { $access{"".$_} = {} } @{ $args{AccessClass} };
}
elsif ( ! ref $args{AccessClass} && length $args{AccessClass} )
{
$access{ $args{AccessClass} } = {};
}
else
{
die "ILLEGALACCESSCLASS";
}
my $obj = {
AccessClass => \%access
};
return bless $obj,$class;
};
sub FETCH
{
my $self = shift;
my $key = shift;
die "ILLEGALFETCH\n" unless ( exists ${ $self -> {AccessClass} }{ ( caller
)[0] } );
return ${ $self -> {AccessClass} } { $key };
};
sub STORE
{
my $self = shift;
my $key = shift;
my $value = shift;
die "ILLEGALSTORE\n" unless ( exists ${ $self -> {AccessClass} }{ ( caller
)[0] } );
${ $self -> {AccessClass} } { $key } = $value;
};
sub DELETE
{
my $self = shift;
my $key = shift;
die "ILLEGALDELETE\n" unless ( exists ${ $self -> {AccessClass} }{ ( caller
)[0] } );
delete ${ $self -> {AccessClass} } { $key };
};
sub CLEAR
{
my $self = shift;
die "ILLEGALCLEAR\n" unless ( exists ${ $self -> {AccessClass} }{ ( caller
)[0] } );
$self -> {AccessClass} = {};
};
sub EXISTS
{
my $self = shift;
my $key = shift;
die "ILLEGALEXISTS\n" unless ( exists ${ $self -> {AccessClass} }{ ( caller
)[0] } );
return exists ${ $self -> {AccessClass} } { $key };
};
sub FIRSTKEY
{
my $self = shift;
die "ILLEGALFIRSTKEY\n" unless ( exists ${ $self -> {AccessClass} }{ ( caller
)[0] } );
scalar keys %{ $self -> {AccessClass} };
return scalar each %{ $self -> {AccessClass} } ;
};
sub NEXTKEY
{
my $self = shift;
die "ILLEGALNEXTKEY\n" unless ( exists ${ $self -> {AccessClass} }{ ( caller
)[0] } );
return scalar each %{ $self -> {AccessClass} } ;
};
sub DESTROY
{
};
1;
1.1 p5ee/P5EEx/Beige/P5EEx/Beige/Security/PublicPrivateMethods.pm
Index: PublicPrivateMethods.pm
===================================================================
#!/usr/local/bin/perl
=pod
=head1 NAME
P5EEx::Biege::Security::PublicPrivateMethods;
=head1 DESCRIPTION
A wee play around with implementing a public/private
method framework in perl.
This ones really simple. It simply allows the user to
create an instance of a given class, and to define
public methods. Any methods not defined as public are
taken to be private.
=head1 METHODS
Well at the moment there is two really.
new() creates a new instance of a class, and requires
the ClassName of the object( together with a list of
publicly available methods, in order to make
it usefull ).
can() allows code to test wether it has permission to
call a method on a given class.
Anything else is taken to be a call to the object
invoked.
=cut
use strict;
use Security::CallerDependentHash;
package Security::PublicPrivateMethods;
sub new
{
my $class = shift;
my %args = (
InstanceRealm => undef,
ClassName => undef,
PublicMethods => {},
@_
);
die "BAD DECLARATION OF PUBLIC METHODS\n" unless ( ref $args{PublicMethods} eq
"ARRAY" );
if ( ref $args{InstanceRealm} eq "SCALAR" && defined ${ $args{InstanceRealm} }
)
{
return ${ $args{InstanceRealm} }; # Job Done
}
# Generate Container
my $self = {};
tie %{$self},'Security::CallerDependentHash',
(
AccessClass => [$class,$args{ClassName}]
);
$self -> {Object} = bless {},$args{ClassName};
# Copy in Public Methods
$self -> {PublicMethods} = {};
map { ${$self -> {PublicMethods}}{$_} = undef } @{ $args{PublicMethods} };
# ClassName of object might be nice to store
$self -> {ClassName} = $args{ClassName};
# And generate and return object
my $handler = bless $self,$class;
if ( ref $args{InstanceRealm} eq "SCALAR" )
{
${ $args{InstanceRealm} } = $handler; # Job Done
}
return $handler;
};
sub DESTROY # To prevent AUTOLOAD
{
my $self = shift;
delete $self -> {Object};
};
sub can
{
my $self = shift;
my $method = shift;
return $self -> {Object} -> can($method) &&
( ( caller )[0] eq $self -> {ClassName} ||
exists ${ ${$self}{PublicMethods} }{$method}
);
}
sub AUTOLOAD
{
my $self = shift;
my $method;
{
no strict 'vars';
$method = $AUTOLOAD;
$method =~ s/.*:://;
}
# What is the context?
if ( ( caller )[0] eq $self -> {ClassName} )
{
return $self -> {Object} -> $method( @_ );
}
else # Call public methods only
{
if ( exists ${ ${$self}{PublicMethods} }{$method} )
{
return $self -> {Object} -> $method ( @_);
}
else
{
die "Illegal Method : ".$method." , from Package:".( caller
)[0]."\n";
}
};
};
1;