Cant print a hash on a perl module - perl

I have a .pm Package Test file which contains:
sub new{
my $hash = shift;
my $self = {};
bless($self,$class);
$self->{hash} = %hash;
return $self;}
and
sub printer{
my $self = shift;
print("Test: ",$self->{hash},"\n");
return;}
On my main.pl I use:
$test = Test->new(%myhash);
I don't know if explained it properly but the problem is that I can't print my hash using my printer function.
I really appreciatte some help about it and if more information about it is needed I can paste all the files here.

The first argument to ->new is the class name. The arguments to the constructor come next. Not hardwiring the class name also makes inheritance possible.
Do you understand the difference between a hash and a hash reference? %hash is a hash, \%hash is a hash reference. If $test->{hash} contains a hash reference, you can dereference it (i.e. retrieve the hash from it) with %{ $test->{hash} }. Hash values must be scalars, which means you can't make a hash a value of a hash - but you can make a hash reference the value.
I'd also recommend to indent the code properly.
#! /usr/bin/perl
use warnings;
use strict;
{
package Test;
sub new {
my ($class, %hash) = #_;
bless { hash => \%hash }, $class;
}
sub printer {
my $self = shift;
print "Test: ", %{ $self->{hash} }, "\n";
}
}
my %hash = ( a => 11, b => 12 );
my $t = 'Test'->new(%hash);
$t->printer; # a11b12 or b12a11

Related

Cannot get hash passed as reference in a module

I want to pass a hash reference to a module. But, in the module, I am not able to get the hash back.
The example:
#!/usr/bin/perl
#code.pl
use strict;
use Module1;
my $obj = new Module1;
my %h = (
k1 => 'V1'
);
print "reference on the caller", \%h, "\n";
my $y = $obj->printhash(\%h);
Now, Module1.pm:
package Module1;
use strict;
use Exporter qw(import);
our #EXPORT_OK = qw();
use Data::Dumper;
sub new {
my $class = $_[0];
my $objref = {};
bless $objref, $class;
return $objref;
}
sub printhash {
my $h = shift;
print "reference on module -> $h \n";
print "h on module -> ", Dumper $h, "\n";
}
1;
The output will be something like:
reference on the callerHASH(0x2df8528)
reference on module -> Module1=HASH(0x16a3f60)
h on module -> $VAR1 = bless( {}, 'Module1' );
$VAR2 = '
';
How can I get back the value passed by the caller?
This is an old version of perl: v5.8.3
In Module1, change sub printhash to:
sub printhash {
my ($self, $h) = #_;
# leave the rest
}
When you invoke a method on a object as $obj->method( $param1 ) the
method gets the object itself as the first parameter, and $param1 as the second parameter.
perldoc perlootut - Object-Oriented Programming in Perl Tutorial
perldoc perlobj - Perl Object Reference
When you call a sub as a method, the first value in #_ will be the object you called it on.
The first argument you pass to it will be the second value in #_, which you are currently ignoring.
sub printhash {
my ($self, $h) = #_;

Unblessing Perl objects and constructing the TO_JSON method for convert_blessed

In this answer I found a recommendation for a simple TO_JSON method, which is needed for serializing blessed objects to JSON.
sub TO_JSON { return { %{ shift() } }; }
Could anybody please explain in detail how it works?
I changed it to:
sub TO_JSON {
my $self = shift; # the object itself – blessed ref
print STDERR Dumper $self;
my %h = %{ $self }; # Somehow unblesses $self. WHY???
print STDERR Dumper \%h; # same as $self, only unblessed
return { %h }; # Returns a hashref that contains a hash.
#return \%h; # Why not this? Works too…
}
Many questions… :( Simply, I’m unable to understand 3-liner Perl code. ;(
I need the TO_JSON but it will filter out:
unwanted attributes and
unset attributes too (e.g. for those the has_${attr} predicate returns false)
This is my code – it works but I really don't understand why the unblessing works…
use 5.010;
use warnings;
use Data::Dumper;
package Some;
use Moo;
has $_ => ( is => 'rw', predicate => 1,) for (qw(a1 a2 nn xx));
sub TO_JSON {
my $self = shift;
my $href;
$href->{$_} = $self->$_ for( grep {!/xx/} keys %$self );
# Same mysterious unblessing. The `keys` automagically filters out
# “unset” attributes without the need of call of the has_${attr}
# predicate… WHY?
return $href;
}
package main;
use JSON;
use Data::Dumper;
my #objs = map { Some->new(a1 => "a1-$_", a2 => "a2-$_", xx=>"xx-$_") } (1..2);
my $data = {arr => \#objs};
#say Dumper $data;
say JSON->new->allow_blessed->convert_blessed->utf8->pretty->encode($data);
EDIT: To clarify the questions:
The %{ $hRef } derefences the $hRef (getting the hash pointed to by the reference), but why get a plain hash from a blessed object reference $self?
In other words, why the $self is a hashref?
I tried to make a hash slice like #{$self}{ grep {!/xx/} keys %$self} but it didn't work. Therefore I created that horrible TO_JSON.
If the $self is a hashref, why the keys %$self returns only attributes having a value, and not all declared attributes (e.g. the nn too – see the has)?
sub TO_JSON { return { %{ shift() } }; }
| | |
| | L_ 1. pull first parameter from `#_`
| | (hashref/blessed or not)
| |
| L____ 2. dereference hash (returns key/value list)
|
L______ 3. return hashref assembled out of list
In your TO_JSON() function { %h } returns a shallow hash copy, while \%h returns a reference to %h (no copying).
Perl implemented object orientation by simply making it possible for a reference to know which package it came from (with bless). Knowing that a reference came from the Foo package means that methods are really functions defined in that package.
Perl allows any kind of reference to get blessed; not just hash references. It's very common to bless hash references; a lot of documentation shows doing exactly that; and Moose does it; but, it's possible to bless an array reference, or a subroutine reference, or a filehandle, or a reference to a scalar. The syntax %{$self} only works on hash references (blessed or not). It takes the hash reference, and dereferences it as a hash. The fact that the original reference may have been blessed is lost.
I need the TO_JSON but what will filter out:
unwanted attributes
and unset attributes too (e.g. for those the has_${attr} predicate returns false.
Pre-5.20, hash slices only give you the values and not the keys from the original hash. You want both keys and values.
Assuming you have a hash, and want to filter out undef values and keys not on a whitelist, there are a few options. Here's what I have, using the JSON module:
use strict; # well, I used "use v5.18", but I don't know which version of Perl you're using
use warnings;
use JSON;
my $foo = { foo => undef, bar => 'baz', quux => 5 };
my %whitelist = map { $_, 1 } qw{foo bar};
my %bar = map { $_ => $foo->{$_} }
grep { defined $foo->{$_} && exists $whitelist{$_} }
keys %$foo;
print to_json(\%bar) . "\n";
# well, I used say() instead of print(), but I don't know which version of Perl you're using
The maps and greps aren't necessarily pretty, but it's the simplest way I could think of to filter out keys not on the whitelist and elements without an undef value.
You could use an array slice:
use strict;
use warnings;
use JSON;
my $foo = { foo => undef, bar => 'baz', quux => 5 };
my #whitelist = qw{foo bar};
my %filtered_on_keys;
#filtered_on_keys{#whitelist} = #$foo{#whitelist};
my %bar = map { $_ => $filtered_on_keys{$_} }
grep { defined $filtered_on_keys{$_} }
keys %filtered_on_keys;
print to_json(\%bar) . "\n";
Or if you like loops:
use strict;
use warnings;
use JSON;
my $foo = { foo => undef, bar => 'baz', quux => 5 };
my %whitelist = map { $_ => 1 } qw{foo bar};
my %bar;
while (my ($key, $value) = each %$foo) {
if (defined $value && exists $whitelist{$key}) {
$bar{$key} = $value;
}
}
print to_json(\%bar) . "\n";
It seems like a good time to bring up Larry wall's quote, "Perl is designed to give you several ways to do anything, so consider picking the most readable one."
However, I made a big point that not all objects are hashes. The appropriate way to get data from an object is through its getter functions:
use strict;
use warnings;
use JSON;
my $foo = Foo->new({ foo => undef, bar => 'baz', quux => 5 }); # as an example
my %filtered_on_keys;
#filtered_on_keys{qw{foo bar}} = ($foo->get_foo(), $foo->get_bar());
my %bar = map { $_ => $filtered_on_keys{$_} }
grep { defined $filtered_on_keys{$_} }
keys %filtered_on_keys;
print to_json(\%bar) . "\n";

Getting issues in object oriented perl

I am new to OO perl. I am trying to write one simple program but getting the error.
Created a package Employee.pm as
package Employee;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
sub get_names {
my $self = #_;
print " getting the names \n";
return $self;
}
sub set_names {
my ($self, $last_name) = #_;
$self->{last_name} = $last_name;
return $self->{$last_name};
}
1;
And created a .pl file as
use strict;
use warnings;
use Employee;
my $obj = new Employee("name" => "nitesh", "last_name" => "Goyal");
my $val = $obj->get_names();
print %$val;
my $setName = $obj->set_names("kumar");
print "$setName \n";
I am getting error as
"Can't use string ("1") as a HASH ref while "strict refs" in use at class1.txt line 10."
The error
"Can't use string ("1") as a HASH ref ..
Comes from this part:
sub get_names {
my $self = #_;
When an array is put in scalar context, it returns its size. Since you call the sub with
$obj->get_names();
Only one argument is passed, which is the object, so #_ contains 1 argument, and its size is 1, therefore in the sub get_names, the variable $self is set to 1. Hence the error. What you probably should do is
my $self = shift;
But then, that will not do anything, because you never stored the names in your constructor. As mpapec said, you should do
my $self = { #_ };
in the constructor sub new.
Also, in get_names, you simply return the object, which is not very useful. You should perhaps return $self->{name} and $self->{last_name}.

Reference found where even-sized list expected in Perl - Possible pass-by-reference error?

I have a Perl class/module that I created to display Bible verses. In it there is a hash that stores several verses, with the key being the book/chapter/verse and the value being the text. This hash is returned from the module.
I'm including the Bible class in a controller class, and that connection seems to work. The problem is I keep getting errors on executing. My IDE because I'm following a Lynda tutorial, is Eclipse with the EPIC plugin.
The error is:
Reference found where even-sized list expected at C:/Documents and Settings/nunya/eric.hepperle_codebase/lynda/lamp/perl5/Exercise Files/14 Modules/eh_bibleInspiration_controller.pl line 42.
Use of uninitialized value $value in concatenation (.) or string at C:/Documents and Settings/nunya/eric.hepperle_codebase/lynda/lamp/perl5/Exercise Files/14 Modules/eh_bibleInspiration_controller.pl line 45.
HASH(0x19ad454) =>
Here is the CONTROLLER class:
#!/usr/bin/perl
# eh_bibleInspiration_controller.pl by Eric Hepperle - 06/23/13
#
use strict;
use warnings;
use Data::Dumper;
use EHW_BibleInspiration;
main(#ARGV);
sub main
{
my $o = EHW_BibleInspiration->new; # instantiate new object.
my %bo_ref = $o->getBibleObj();
print "\$o is type: " . ref($o) . ".\n";
print "\%bo_ref is type: " . ref(\%bo_ref) . ".\n";
# exit;
$o->getVerseObj();
listHash(\%bo_ref);
message("Done.");
}
sub message
{
my $m = shift or return;
print("$m\n");
}
sub error
{
my $e = shift || 'unkown error';
print("$0: $e\n");
exit 0;
}
sub listHash
{
my %hash = #_;
foreach my $key (sort keys %hash) {
my $value = $hash{$key};
message("$key => $value\n");
}
}
Here is the class that returns the verses and has the method to pick a random verse:
# EHW_BibleInspiration.pm
# EHW_BibleInspiration.
#
package EHW_BibleInspiration;
use strict;
use warnings;
use IO::File;
use Data::Dumper;
our $VERSION = "0.1";
sub new
{
my $class = shift;
my $self = {};
bless($self, $class); # turns hash into object
return $self;
}
sub getVerseObj
{
my ($self) = #_;
print "My Bible Verse:\n";
my $verses = $self->getBibleObj();
# get random verse
#$knockknocks{(keys %knockknocks)[rand keys %knockknocks]};
# sub mysub {
# my $params = shift;
# my %paramhash = %$params;
# }
# my %verses = %{$verses};
# my $random_value = %verses{(keys %verses)[rand keys %verses]};
# print Dumper(%{$random_value});
}
sub getBibleObj
{
my ($self) = #_;
# create bible verse object (ESV)
my $bibleObj_ref = {
'john 3:16' => 'For God so loved the world,that he gave his only Son, that whoever believes in him should not perish but have eternal life.',
'matt 10:8' => 'Heal the sick, raise the dead, cleanse lepers, cast out demons. You received without paying; give without pay.',
'Luke 6:38' => 'Give, and it will be given to you. Good measure, pressed down, shaken together, running over, will be put into your lap. For with the measure you use it will be measured back to you.',
'John 16:24' => 'Until now you have asked nothing in my name. Ask, and you will receive, that your joy may be full.',
'Psalms 32:7' => 'You are a hiding place for me; you preserve me from trouble; you surround me with shouts of deliverance. Selah',
'Proverbs 3:5-6' => 'Trust in the LORD with all your heart, and do not lean on your own understanding. 6 In all your ways acknowledge him, and he will make straight your paths.',
'John 14:1' => 'Let not your hearts be troubled. Believe in God; believe also in me.'
};
my $out = "The BIBLE is awesome!\n";
return $bibleObj_ref;
}
1;
What am I doing wrong? I suspect it has something to do with hash vs hash reference, but I don't know how to fix it. My dereferencing attempts had failed miserably because I don't really know what I'm doing. I modeled my random getter off of something I saw on perlmonks. #$knockknocks{(keys %knockknocks)[rand keys %knockknocks]};
In the main, you have:
my %bo_ref = $o->getBibleObj();
but, in package EHW_BibleInspiration;, the method getBibleObj returns : return $bibleObj_ref;
You'd do, in the main : my $bo_ref = $o->getBibleObj();
and then call listHash($bo_ref);
Finaly, don't forget to change sub listHash to:
sub listHash
{
my ($hash) = #_;
foreach my $key (sort keys %{$hash}) {
my $value = $hash->{$key};
message("$key => $value\n");
}
}
In your main, you do
listHash(\%bo_ref);
This passes a hash reference to the sub. However, it tries to unpack its arguments like
my %hash = #_;
Oops, it wants a hash.
Either, we pass it a hash: listHash(%bo_ref). This saves us much typing.
Or, we handle the reference inside the sub, like
sub listHash {
my ($hashref) = #_;
foreach my $key (sort keys %$hashref) {
my $value = $hashref->{$key};
print "$key => $value\n";
}
}
Notice how the reference uses the dereference arrow -> to access hash entries, and how it is dereferenced to a hash for keys.
I suspect that your suspicion is correct. In your method sub listHash you're correctly passing in the hash but you're trying to use a hash instead of a hash reference for the internal variable. Try using my ($hash) = #_; instead of my %hash = #_;.
When using references you can use the -> operator to de-reference it to get to the underlying values. The rest of your method should look like this:
sub listHash
{
my ($hash) = #_;
foreach my $key (sort keys %{$hash}) {
my $value = $hash->{$key};
message("$key => $value\n");
}
}
On line 43 of your program I had to tell Perl that the reference should be a hash reference by calling keys %{$hash}. Then on line 44 I de-referenced the hash to get the correct value by calling $hash->{$key}. For more information on Perl and references you can read the through the tutorial.
listHash is expecting a hash and you're passing it a hash reference. Change:
listHash(\%bo_ref);
to:
listHash(%bo_ref);

Size of hash instance variable

I have a Perl class that contains a hash instance variable for storing other objects. I would like to have a method to print the number of elements in the hash but I am getting the following error message on the line return keys($self->{'_things'});
Type of arg 1 to keys must be hash (not hash element)
package MyClass;
use strict;
sub new {
my ($class) = #_;
my $self = {
_things => undef
};
$self->{'_things'} = ();
bless $self, $class;
return $self;
}
sub get_count {
my ( $self ) = #_;
return keys($self->{'_things'});
}
Use
return scalar(keys(%{$self->{'_things'}}));
$self->{'_things'} is just a reference to a hash, and keys() expects a hash as its argument—so, you have to dereference it first by wrapping it in %{…}. Finally, since you want to count items, you have to make sure the return value of keys() (which is a list) is interpreted in scalar context, by wrapping it in scalar(…).
If I understand you correctly, $self->{_things} should contain a hash data structure. If so, you have two problems:
sub new {
my ($class) = #_;
my $self = {
# Initialize _things to be a reference to an empty hash.
_things => {},
};
bless $self, $class;
return $self;
}
sub get_count {
my ( $self ) = #_;
# Here's the way to get the N of keys.
# The %{ FOO } syntax will take a hash reference (FOO in this case) and
# convert it to a hash, on which we can then call keys().
return scalar keys %{ $self->{'_things'} };
}
The error message is totally correct! ;) You need to 'dereference' the element into a hash, also you need to call keys() in a scalar context to get the count.
$ perl -wle 'use strict; my $href = { foo => undef }; $href->{foo} = (); print sclar keys $href->{foo}'
Type of arg 1 to keys must be hash (not hash element) at -e line 1, at EOF
Execution of -e aborted due to compilation errors.
vs.
$ perl -wle 'use strict; my $href = { foo => undef }; $href->{foo} = (); print scalar keys %{ $href->{foo} }'
0
You might want to use a hash ref instead for $self->{_things} to avoid accidental list flattening and other issues though.
$ perl -wle 'use strict; my $href = { foo => undef }; $href->{foo} = { bar => 1 }; print scalar keys %{ $href->{foo} };'
1