Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"

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 and


#----------------------------------------------------------- # File: # Purpose: # To provide a test interface into # See 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: # Purpose: # To demonstrate class creation, object persistence # using storable, raising exceptions using, # 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

Replies are listed 'Best First'.
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 (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 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 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,


        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?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://270033]
Approved by broquaint
Front-paged by broquaint
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (13)
As of 2017-10-19 15:48 GMT
Find Nodes?
    Voting Booth?
    My fridge is mostly full of:

    Results (255 votes). Check out past polls.