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

Hi, I have struggled for the whole afternoon trying to
code a perl object which also enable users to fill in
the its data member ( a hash of hash).See the purpose below. I cannot figure it out. Please help.
Class Purpose: I am using this class as a data
storage for the list of MSSQL DATABASE servers which
later one I will try to connect to then do some query
against, then verify those query results
basically, it does the following:
1. get a list of servers with credentials from other program and feed those into the object.. use default as fallback (should I?)
2. read in those data tying to that server
3. clients can add server
4. clients can delete server
5.clients can delete everything clients here mean the users of the object
package myObject; $VERSION = 1.00; use strict; use warnings; use diagnostics; use vars qw(@ISA); @ISA = qw(Class::Singleton); use Carp (); $Carp::Verbose =1; { my %serverMap = ( default => { ipaddress=127.0.0.1, dsn=""default, userid="sa", password="password", instance="instance" }, ); sub new{ my ($self, %args) = @_; my %array=(); %array = (%args); #? my $self={}; return bless {$self}; } sub printMe(){ my ($self) = @_; while ( ($server, $credentials) = each $self->%serverMap) { print "$server: "; while ( ($credentials, $value) = each %$roles ) { print "$credentials=$value "; } print "\n"; } } sub fillServerMap($){ <<<<< no idea how to input my ($self) = @_; for $server ( @_ ) { push @ <<<-- NO IDEA how to do this } } } sub removeServerMap($){ my ($self) = @_; $self->serverMap ={}; } sub deleteServer($){ my ($self,$server)=@_; delete $self->serverMap {$server}; } 1

Replies are listed 'Best First'.
Re: how to code a class and use it with hash of hash as data member?
by roboticus (Chancellor) on Mar 17, 2006 at 03:09 UTC
    edward--

    I've never done any object-oriented Perl before, so please bear with me. I've been meaning to teach myself OOPerl, so I thought I'd give it a shot.

    Anyway, I've cleaned up some syntax errors in your code, and munged some stuff around, and came up with something that seems to work. I'm using a trivial test program:
    #!/usr/bin/perl -w use strict; use myObject; my $T = myObject->new(); # We add a server by passing in the server name, and a hash ref of the # credentials we want to add $T->addServer('barrabas', { password=>"sa", hostname=>"devo.marcorp.or +g" }); $T->printMe; $T->deleteServer('default'); $T->printMe; $T->removeServerMap; $T->printMe;
    The touched-up version of your code follows. Please note that I expect that there are some serious problems with it yet, as I haven't done this before. However, it will at least run with my test program.

    When some guru comes by and notices something, please be kind... ;^)
    package myObject; $VERSION = 1.00; use strict; use warnings; use diagnostics; use vars qw(@ISA); use Carp (); $Carp::Verbose =1; { my %serverMap = ( default => { ipaddress => "127.0.0.1", dsn => "default", userid => "sa", password => "password", instance => "instance" } ); sub new { my ($slf, %args) = @_; my %array=(); %array = (%args); #? my $self={}; return bless $self; } sub printMe() { my ($self) = @_; print "------ Available Servers ------\n"; for my $server (keys %serverMap) { print "\nServer: ", $server, "\n"; my $hr = $serverMap{$server}; for my $cr (keys %{$serverMap{$server}}) { print "\t$cr => $serverMap{$server}{$c +r}\n"; } } } sub addServer() { my ($self, $srvName, $hrCreds) = @_; $serverMap{$srvName} = $hrCreds; } sub removeServerMap($) { my ($self) = @_; %serverMap = (); } sub deleteServer($){ my ($self, $srvName) = @_; delete $serverMap{$srvName}; } } 1
    --roboticus

      That's close, but you can only ever have one "object" at a time, as you're using package-level data. That means you have to access the data in the object, not in the server map. You also don't need the prototypes on methods, as they're useless here.

      package myObject; use strict; use warnings; use vars '$VERSION'; $VERSION = 1.00; my %serverMap = ( default => { ipaddress => "127.0.0.1", dsn => "default", userid => "sa", password => "password", instance => "instance" } ); # use the arguments in $serverMap{ default } as attribute defaults sub new { my $class = shift; my %self = ( %{ $serverMap{ default } }, @_ ); bless \%self, $class; } sub printMe { my $self = shift; print "------ Available Servers ------\n"; for my $server ( keys %$self ) { print "\nServer: ", $server, "\n"; for my $cr ( keys %{ $self->{$server} } ) { print "\t$cr => $self->{$server}{$cr}\n"; } } } sub addServer { my ( $self, $srvName, $hrCreds ) = @_; $self->{$srvName} = $hrCreds; } sub removeServerMap { my $self = shift; %$self = (); } sub deleteServer { my ( $self, $srvName ) = @_; delete $self->{$srvName}; } 1;

      Update: Fixed a typo in the code.

        i guess I am hugely confuse about when to use $self->...
        in the first reply to my question, the code uses the
        %serverMap directly in each of the methods.. i guess because i define it outside all methods, it is visible???...
        but in yours, you use $self to access to it.
        another question of mine: i se eyou make a new constructor (more compact one), but
        don't quite get what it does? your decision for the change? my original verison has this package @ISA CLASS::Singleton...
        to prevent users of this class to have more than 1 copy of serverMap
        .. but from your comment in your psot, is that step necessary anymore? thanks
        thanks for your reply. i wans thinking of using this as the
        datastructure to collect the mssql server credentials then
        issues sql statements to test against various data already
        in the database. we will enver use live database as it is a
        app that depends on a fresh installed embedded msdn or a
        new or existing sql server. we have a set of sample
        inputs, and want to do some query against the databse to
        make sure the data has been inserted into the database.
        but since there may be schema, change I was thinking about
        using object
        relational mapping to map my test code against the SQL..
        but is there a similar test framewrok arleady exits? since this is a common problem, I
        have a feeling I may be duplicating someone else work. I
        cannot use MOCK database as the dev team only support MSSQL and MSDN. any suggestion?
Re: how to code a class and use it with hash of hash as data member?
by xdg (Monsignor) on Mar 17, 2006 at 03:11 UTC

    This code is a real mess -- I don't even think it will compile due to syntax errors and until you understand those, figuring out the object part will be a real challenge.

    I suggest you spend some time going back to some basic tutorials on OO Perl. Perhaps Tutorial: Introduction to Object-Oriented Programming or Perl Object Oriented Meta-Tutorial would be a good starting point to give you some examples to work from.

    Best of luck

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.