Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Capturing Method Call, And Relaying.

by Revelation (Deacon)
on Jan 03, 2004 at 10:06 UTC ( [id://318489]=perlquestion: print w/replies, xml ) Need Help??

Revelation has asked for the wisdom of the Perl Monks concerning the following question:

I've hacked up a class to be inherited from allowing me to parse an input hash, verify that each key value pair passes a regex for that key, and access keys by method name.

The third capability (accessing keys by method name) is giving my mind fits right now (possibly because it's almost 5:00 A.M). I'd like to be able to call  $o->parameters->user, and access the user attribute held in the object $o (Note: not $o->parameters).  $self->{'params'}->{$_} would access it inside a subroutine. How would I 'fake' an object, so as to have  $o->parameters->user return  $o->{'params'}->{'user'}, and have  $o->parameters->user('Jeffory') change  $o->{'params'}->{'user'} to Jeffory, after validating it with a subroutine in my class (so, in fact  $o->{'params'}->{'user'} = $o->validate('Jeffory'); ) In other words, the parameters method has to return an object that has access to the class it's currently in, parses the method called on it, and executes the code (the object could be self, but I'd prefer not to do that, as I'd like to allow people to use _anything_, even new or validate, as a parameter--it's probably what I'll end up doing, though):
return $o->{'param'}->{$method};
The easiest way ( I guess?) to do that would be to create a 'false' object, that captures the method call, but is actually in the class that $o is in, and therefore can call its methods...? Any ideas if that's available?

Obviously, there's a major design flaw in this class, but humor me (or give me advice on the code, which I've posted below--the code probably doesn't work, I've been freewriting it, which means there are probably spelling errors, and important logic errors ) :)
package Input::SignUp; our @ISA = qw/Input/; use strict; use warnings; sub _init { $_[0]->make_methods( 'user' => [ qr/^[a-zA-Z0-9]+$/, 'Username may only contain alphanu +meric characters' ], 'password' => [ qr/^[a-zA-Z0-9]+$/, 'Password may only contain alp +hanumeric characters' ], 'key' => [ qr/^[a-fA-F0-9]+$/, 'Key may only contain A-F alphanume +ric characters' ], ); } 1;
package Input; use strict; use warnings; use Want; sub new { my $self = bless {}, shift; $self->{'params'} = Parameters->new; $self->_init; $self; } sub make_methods { $self = shift; my %methods = @_; for (keys %methods) { my($p,$re,$error) = $methods{$_}; $self->{'regex'}->{$p} = $re; $self->{'error'}->{$p} = $error; } } sub validate { $self = shift; my %input = @_; $self->{'params'}->{$_} = $self->_validate($input{$_},$_}) for keys +%input; } sub _validate { $_[1] =~ $_[0]->{'regex'}->{$_[2]} or $_[0]->error($_[2],$_[0]->{'er +ror'}->{$_[2]}); $1; } sub error { my $self = shift; push @{$self->{'errors'}}, [ @_ ] and return 1 if scalar @_ == 2; return scalar @{$self->{'errors'}}; } sub error_hash { my @loop_data; for (@{$self->{'errors'}}) { push(@loop_data, { 'ERROR' => ucfirst $_->[0].' Error: '.$_->[1] } + ) for @{$self->{'errors'} }; } return ( 'ERRORS' => \@loop_data ); } sub parameters { my $self = shift; return bless [], if want('OBJECT'); # Single Param. # This is where I'm stuck. Ideally, the object would be called # as $o->parameters->user('Bob'), or something like that. Then # We'd validate the parameter, using the key 'user'. It's rather # simple to do, by just changing parameters->user to parameters->('u +ser','bob'), # but I don't want that! } 1;

Gyan Kapur

Replies are listed 'Best First'.
Re: Capturing Method Call, And Relaying.
by tachyon (Chancellor) on Jan 03, 2004 at 11:26 UTC

    As you say it is bad design. Why not just call a user method on the object - this method just needs to know where to go for its data? But as (almost) always Perl will accomodate you.

    package Bad::Design; use Data::Dumper; my $o = Bad::Design->new(); print Dumper $o; print $o->parameters->user, $/; $o->parameters->user('Matt Wright'); print $o->parameters->user, $/; sub new { bless { 'params' => { user => 'Randal Schwartz' } }, shift } sub parameters { bless $_[0]->{'params'}, ref($_[0]) } sub user{ $_[0]->{'user'} = $_[1] if defined $_[1]; $_[0]->{'user'} } __DATA__ $VAR1 = bless( { 'params' => { 'user' => 'Randal Schwartz' } }, 'Bad::Design' ); Randal Schwartz Matt Wright

    cheers

    tachyon

Re: Capturing Method Call, And Relaying.
by tachyon (Chancellor) on Jan 04, 2004 at 05:20 UTC

    Have a look at this, it may be the sort of thing you are looking for:

    package OO; my $properties = { 'user' => [ qr/^[a-zA-Z0-9]+$/, 'Username may only contain alphanu +meric characters' ], 'password' => [ qr/^[a-zA-Z0-9]+$/, 'Password may only contain alp +hanumeric characters' ], 'key' => [ qr/^[a-fA-F0-9]+$/, 'Key may only contain A-F alphanume +ric characters' ], }; $o = OO->new( user => 'username' ); $o->password( 'secret' ); $o->key( '***Invalid' ); $o->no_exist( 'foo' ); print "Password: ", $o->password(), $/; print "Input errors:\n" . $o->error() if $o->error(); use Data::Dumper; print Dumper $o; sub new { my $class = shift; my $self = { error => '' }; bless $self, $class; $self->init(@_) if @_; return $self; } sub init { my ( $self, %props ) = @_; for my $prop ( keys %props ) { my $value = $props{$prop}; $self->$prop( $value ); } } sub AUTOLOAD { my ( $self, $value ) = @_; my ( $method ) = $AUTOLOAD =~ m/::([^:]+)$/; if ( $properties->{$method} ) { if ( defined $value ) { # its a set method if ( $value =~ m/$properties->{$method}->[0]/ ) { $self->{$method} = $value; } else { $self->error( $properties->{$method}->[1] . "\n" ); } } else { # we have a get method return $self->{$method}; } } else { $self->error("Unknown method $method called from " . (join ' ' +, caller()) . "\n" ); } } sub error { my ( $self, $error ) = @_; $self->{error} .= $error if $error; return $self->{error}; } __DATA__ Password: secret $VAR1 = bless( { 'error' => 'Key may only contain A-F alphanumeric cha +racters Unknown method no_exist called from OO C:\\PROGRA~1\\PERLBU~1\\debug\\ +oo 15 ', 'password' => 'secret', 'user' => 'username' }, 'OO' ); Input errors: Key may only contain A-F alphanumeric characters Unknown method no_exist called from OO C:\PROGRA~1\PERLBU~1\debug\oo 1 +5

    cheers

    tachyon

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://318489]
Approved by tachyon
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (1)
As of 2024-04-18 23:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found