Reputation: 374
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
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
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