Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

General Class Creation Using Persistent Object, Method Privacy Enforcement and Exceptions

by DeadPoet (Scribe)
on Jun 29, 2003 at 22:27 UTC ( #270033=perlmeditation: print w/ replies, xml ) Need Help??

To All:

I ran into a scenario where I was in need of persistent objects that could be stored and reloaded; private methods that were inheritable ( @ISA = qw( Some::Class )), provided enforced privacy is not defined by the typical ‘my _private_meth = sub {   }’ scenario; methods that could raise and catch user defined exceptions. The following snippet is a boilerplate example that I put together for those who are seeking an example of how to accomplish such a task. The code is divided into two files tB.pl and TestB.pm.

Cheers,

DeadPoet
#----------------------------------------------------------- # File: tB.pl # Purpose: # To provide a test interface into TestB.pm # See TestB.pm for details. # Created By: # Philip A. Reyniers # Hewlett-Packard #----------------------------------------------------------- use TestB; use strict; my $str_file = './object.dat'; #----------------------------------------------------------- # Create new Object #----------------------------------------------------------- print STDOUT "\nTest Create New Object\n"; my $o = TestB->new(); print STDOUT "\nTest Print Object\n"; $o->print_object(); my $return = $o->store_object( \$str_file ); if ( defined $return ) { # This should not generate an Exception. print STDOUT "\t" . $$return . "\n"; } print STDOUT "\nTest PRIVATE Check: This should raise an exception!\n" +; my $return = $o->_caller_check(); if ( defined $return ) { # Exception Generated print STDOUT "\t" . $$return . "\n"; } #----------------------------------------------------------- # Destroy Object #----------------------------------------------------------- print STDOUT "\nTest DESTROY Object\n"; undef $o; #----------------------------------------------------------- # Load Object #----------------------------------------------------------- print STDOUT "\nTest Loading Object File from $str_file\n"; my $o = TestB->load_object( \$str_file ); print STDOUT "\nTest Print Loaded Object\n"; $o->print_object(); undef $o; exit; #----------------------------------------------------------- # File: TestB.pl # Purpose: # To demonstrate class creation, object persistence # using storable, raising exceptions using Exception.pm, # and restricting access to private classes. # Created By: # Philip A. Reyniers # Hewlett-Packard #----------------------------------------------------------- package TestB; use strict; use Storable; use Exception qw( :all ); Exception->debugLevel( DEBUG_STACK ); my $err=new Exception 'TestB'; sub _caller_check { my ( $self ) = shift; my ( $str_package ) = caller( 0 ); print STDOUT "\tCALLER: $str_package\n"; try { # Allow only inherited classes $err->new( 'CallerException' )->raise( "Unmediated access deni +ed to foreign package ${str_package}!" ) unless $str_package->isa( __ +PACKAGE__ ); # Allow only from same class. #$err->new( 'CallerException' )->raise( "Unmediated access den +ied to foreign package ${str_package}!" ) unless $str_package eq ( __ +PACKAGE__ ); # Allow Main #$err->new( 'CallerException' )->raise( "Unmediated access den +ied to foreign package ${str_package}!" ) if ( $str_package ne 'main' + ); print STDOUT "\tCaller $str_package Authorized\n"; return undef; } when 'CallerException', except { return \( $_[0]->id . ': ' . $_[0]->text ); } except { $_[0]->confess; } } sub store_object { my ( $self ) = shift; # Caller Check my $return = $self->_caller_check(); if ( $return ) { print STDERR $$return . "\n"; return $return; } Storable::store ( \%{ $self }, './object.dat' ); return undef; } sub load_object { my ( $self, $sref_file ) = @_; return Storable::retrieve( $$sref_file ) } sub print_object { my ( $self ) = shift; foreach ( keys %{ $self } ) { print STDOUT $_ . "\t" . $self->{ $_ } . "\n"; } } sub new { my ( $class ) = @_; my $self = { _testA => 1, _testB => 0 }; bless $self, $class; return $self; } sub DESTROY { my ( $self ) = @_; print STDOUT "\nDestroying Object...\n"; } 1; __END__

Comment on General Class Creation Using Persistent Object, Method Privacy Enforcement and Exceptions
Select or Download Code
Re: General Class Creation Using Persistent Object, Method Privacy Enforcement and Exceptions
by Revelation (Deacon) on Jun 30, 2003 at 04:42 UTC
    Please note that you're loading the object from a file with the name of the dereferenced $sref_file, but you're storing it in './object.dat,' even though you pass $sref_file to that as well- that's simple to fix :)

    I'm also not a big fan of Exception; rather, I like to use Error. I just love being able to throw different types of errors with about two seconds of code as well as the utter extensibility that Error provides:
    package SomeError; @ISA = qw(Error::Simple);
    Then you can throw an error of type 'SomeError', and you can create even more complicated hierarchies of errors so easily with Error.pm (just have another, more specific subset of SomeError inherit from it.) It's a perfect use of Universal::isa().

    Error's errors also propogate down, so if you throw an exception on an upper sub, you can catch it later. This allows you to not have to return the error if there is one, and instead follow the standard rule of 0 or undefined on failure, and true of success (you could still do this, but Error.pm makes it really intuitive to me.) Furthermore, you wouldn't have to comment out the thrown errors, because if they weren't asking to be caught somewhere, they'd never really be used (this is my knowledge of Error.pm- just use record(), and never catch the error. However, this is possible using either error module again, probably)...

    Also, afaik-  \%{ $self } == $self , so  Storable::store ( \%{ $self }, './object.dat' ); could be  Storable::store ($self,'./object.dat' );.

    Instead of storable, I'm also becomming a fan of YAML, if you haven't tried it- try it! It's pretty cool, and you can actually read the files it generates (I'm not sure if it'd be good for saving a reference to an object, because I've never tried that using it, but I expect it would do fine...)

      Thanks, I missed the fact that I had hard coded the store file name but had passed the reference to the file name. The sub store_object {} should read as follows:

      sub store_object { my ( $self, $sref_file ) = @_; # Caller Check my $return = $self->_caller_check(); if ( $return ) { print STDERR $$return . "\n"; return $return; } Storable::store ( \%{ $self }, $$sref_file ); return undef; }

      Peace Out,

      DeadPoet

        Why write \%{$self}? It's a waste of both space and execution time for your code (perl may optimize it, but it's still a waste of space...) Instead, use $self, which is the exact same thing, and makes it obvious that you're putting a blessed object into the file (it took me a while to comprehend that \%{$self} somehow kept the object blessed and returned $self, itself-- this is completely countra-my previous knowledge of perl. Could somebody explain why that works?)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://270033]
Approved by broquaint
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (8)
As of 2014-12-26 19:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (174 votes), past polls