Bala Krishnan
Bala Krishnan

Reputation: 374

Perl - Return hash of objects as single object from a class

In general, perl objects are data structure such as hash, array, scalar, file handles etc.

I am thinking of a scenario when a perl module can return hash of objects (each object being as hash) as a single object. Please consider the following scenario.

I have a YAML file with multiple documents. (or an XML with multiple set of identical configuration nodes). I need a perl module for which I could pass this YAML file as input, and receive hash of objects (each object corresponds to a document in the YAML file).

YAML

---
mykey: 1
myname: John
---
mykey: 2
myname: Doe
----
mykey: 3
myname: Chris
...

The above YAML file has 3 documents in it. Let us consider this is going to be the input file.

I would like to write something like below and access the hash of objects.

SimpleParser.pl

use strict;
use warnings;
use YAMLParser;
my %objHashRef = YAMLParser->new('input.yml');

print keys %objHashRef;    #print keys for each objects
print values %objHashRef;  #print hash reference of each object

my $thirdObjectName = $objHashRef{3}->get_name();
print $thirdObjectName;    #this prints 'Chris'

To achieve this behavior, what are all the modifications required in the perl module file which is similar to something below?

YAMLParser.pm

use strict;
use warnings;
sub new {
    my ($class) = shift;
    my $self = {
         inputFile => shift,
         name => shift
    };
    bless $self, $class;
    return $self;
}

sub set_name {
    $self->{name} = $name;
}

sub get_name {
    my ($self) = @_;
    return $self->{name};
} 
1;

Below is a sample YAML parsing snippet that could help if required.

my @list;
my $myname;
my $i = 0;
my @conf = LoadFile('input.yml');   #returns array of reference to each document in the YAML file
my $config = \@conf;      #Returns reference to an array

foreach ( @conf ) {
    $list[$i] = $config->[$i]->{mykey};
    $objHash{$list[$i]} = YAMLParser->new();
    $myname = $config->[$i]->{myname};
    $objHash{$list[$i]}->setMyname($myname);
    my $host = $objHash{$list[$i]}->getMyname();
    $i++;
}

Please let me know your thoughts.

Upvotes: 2

Views: 461

Answers (2)

Diab Jerius
Diab Jerius

Reputation: 2320

There are a number of modules on CPAN which will happily create an object out of a hash (heck, I even wrote one: Hash::Wrap). If you want to recursively apply the object paradigm to the nested parts of the YAML documents, my favorite is Hash::AsObject. See Hash::Wrap for a more comprehensive list of similar modules.

Here's some code. It returns a list of objects, rather than a hash of objects, but fixing that is pretty straightforward.

use 5.010;

use strict;
use warnings;

use Hash::AsObject;
use YAML 'Load';


my $yaml = do { local $/ = undef;
                <DATA>
            };

my @objs = map { Hash::AsObject->new( $_ ) } Load( $yaml );

say " Name: ", $objs[0]->myname;
$objs[0]->myname( "Frank" );
say " Name: ", $objs[0]->myname;

__DATA__

---
mykey: 1
myname: John
---
mykey: 2
myname: Doe
---
mykey: 3
myname: Chris

And the output:

 Name: John
 Name::Frank

Upvotes: 1

choroba
choroba

Reputation: 242038

Just store the structures into a hash keyed by their mykey. I used map, but a for-loop is also possible:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

{
    package YAMLHash;
    use YAML qw{ LoadFile };
    sub new {
        my ($class, $file) = @_;
        my %hash = map { $_->{mykey} => $_ } LoadFile($file);
        bless \%hash, $class
    }
}


my $obj = 'YAMLHash'->new('1.yaml');

say keys %$obj;
say values %$obj;

my $third_object_name = $obj->{3}{myname};
print $third_object_name;    #this prints 'Chris'

Note that $obj->{3} is not the third object. It's the object whose mykey is 3.

Upvotes: 3

Related Questions