i'am trying to pass imported functions to another created package.
Maybe someone could help me :)
package Person;
use JSON; # i want to pass functions from this module to the package 'Employee'
sub new {
my $class = shift;
my $self = {
_name => "No Name",
};
bless $self, $class;
return $self;
}
sub setName {
my ($self, $name) = #_;
$self->{_name} = $name;
}
sub getName {
my $self = shift;
return $self->{_name};
}
1;
Now i want to use functions from the JSON Package inside this module.
package Employee;
use JSON qw( encode_json ); # This works, thx to everybody
our #ISA = qw(Person);
sub new {
my $class = shift;
my $self = Person->new();
encode_json({a=>1}); # this works now
bless $self, $class;
return $self;
}
1;
I would be nice, if someone could give me some hints.
Thanks to everybody
You're asking how to place encode_json in the Employee namespace. To do that, add the following after package Employee;:
use JSON qw( encode_json );
I'm also not sure why in the comment the OP said that he/she cannot (or does not want) put "use JSON" in the Employee package. Maybe because the Employee package file (Employee.pm) is written by someone else and cannot be modified.
Note that in Perl you can "open the Employee" package from any other code written in any file. So in your main script or the Person package file or wherever, you can do:
{ package Employee; use JSON; }
If you absolutely could not add use JSON to the Employee class because you were not sure what encoding you'd need to use, then you could pass a code reference into new:
# in Person.pm
my $e = Employee->new(\&JSON::encode_json);
# in Employee.pm
sub new {
my($class, $encoder) = #_;
...
$self->{_encoded} = $encoder->($value_to_encode);
...
return $self;
}
Again, the only reason you'd want to do this is if you dynamically needed to change which encoder you wanted to use. The solution you've adopted -- use JSON qw(encode_json) -- is the right one if you want that one function and won't need to change it.
Related
The title is vague but I'll explain it.
I have a Perl script which uses a module named systemId
I create an object inside the script
my $id = systemId->new({_dom => "dev"});
I am planning to instantiate an object similar to the one above but inside the systemId.pm.
How do I do that?
I can't really search it on the net as I do not know what to search to begin with.
That can be done the same way it's done in a script. Similarly to how you can put the package and main:: in the same file, you can use the class in the package file once it is defined. See comments after code.
File Play.pm
package Play;
use warnings;
use strict;
sub new {
my $class = shift;
my $self = { _data => shift || 'default' };
bless $self, $class;
print "New object created.\n";
return $self;
}
sub data {
my $self = shift;
if (#_) { $self->{_data} = shift }
return $self->{_data};
}
print "Inside the package. Create object.\n";
my $obj = Play->new();
my $data = $obj->data();
print "data: $data\n";
print "\n";
1;
The script
use warnings;
use strict;
use Play;
print "In main\n";
my $obj = Play->new(25);
print "data: " . $obj->data() . "\n";
Printout when running the script
Inside the package. Create object.
New object created.
data: default
In main
New object created.
data: 25
Once the bless call executed then $self is an object of the class Play. From bless
bless REF,CLASSNAME
bless REF
This function tells the thingy referenced by REF that it is now an object in the CLASSNAME package. If CLASSNAME is omitted, the current package is used. [...]
Since we are right in the package it can be used as an object and methods called on it. From perlobj
Once we've blessed the hash referred to by $self we can start calling methods on it.
This refers to working with $self hashref, which became the object.
Note that there may be issues of initialization when it comes to creating an object and the questions of what exactly is being done and how may be important.
I can't help it but ask, what do you want to do with this?
As easy as:
my $id = systemId->new({_dom => "dev"});
You may also use...
my $id = __PACKAGE__->new({_dom => "dev"});
...but the first one is more obvious.
A new object instance could be created everwhere, including the package/class itself.
The ->new function is typically:
sub new {
my $class = shift;
my $self = bless {#_}, $class;
return $self;
}
The instance is actually created in the class module itself (using bless). There is no magic in ->new in Perl, some modules also use another name, see DateTime's ->now which does ->new(epoch => time) internally.
I am getting:
Can't call method "test" without a package or object reference at 4.pl line 6.
And i don't know why, any ideas?
Users.pm
package Users;
sub new{
print "Created\n";
}
sub test{
print "a";
}
1;
Test.pl
BEGIN {
push #INC,"/home/baddc0re/Desktop/perl_test/";
}
use Users;
$user = new Users();
$user->test();
I suggest to you use syntax $users = Users->new() instead of new Users. You forgot to bless values inside new method. Please read perlootut under perldoc.
Users.pm
package Users;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
sub test {
print "a";
}
1;
MAIN
use strict;
use Users;
my $users = Users->new();
print $users->test();
Object construction in Perl doesn't work that way. The constructor has to explicitly return a reference that has been made into an object with the bless function; in fact, in Perl, this is what defines a constructor, as "new" is just another name for a subroutine and, unlike in C++, invoking a function named new does not force Perl to create an object. In this specific example, new is just returning the return value of print, which is presumably just some true value, and trying to invoke the test method on this value fails because it hasn't been blessed into any class.
I have a module foo that has extended sub-modules bar and baz. I want bar and baz to modify the same set of hashes that are in foo.
Right now I have something like:
my $foo = new foo;
my $bar = new foo::bar( $foo );
$bar->doStuff();
$bar->printSelf();
my $baz = new foo::bar( $foo );
$baz->doOtherStuff();
$baz->printSelf();
Inside one of the sub-modules the constructor looks like:
sub new {
my $class = shift;
my $self = shift;
--stuff--
bless $self, $class;
return $self;
}
Please don't laugh too hard. Is there a way I can do this without passing in $foo?
Thanks for reading. :)
I prefer to share things through methods. That way, no one has to know anything about the data structures or variables names (although you do need to know the method name):
{
package SomeParent;
my %hash1 = ();
my %hash2 = ();
sub get_hash1 { \%hash1 }
sub get_hash2 { \%hash2 }
sub set_hash1_value { ... }
sub set_hash1_value { ... }
}
Since SomeParent provides the interface to get at the private data structures, that's what you use in SomeChild:
{
package SomeChild;
use parent 'SomeParent';
sub some_method {
my $self = shift;
my $hash = $self->get_hash1;
...;
}
sub some_other_method {
my $self = shift;
$self->set_hash2_value( 'foo', 'bar' );
}
}
Your question is not very clear nor there is any code with hashes. But if you need module variables modified, you can use fully qualified name:
package Foo; # don't use lowercase named, they are reserved for pragmas
our %hash1 = ();
our %hash2 = ();
package Foo::Bar;
use Data::Dump qw(dd);
sub do_stuff {
$Foo::hash1{new_item} = 'thing';
}
sub do_other_stuff {
dd \%Foo::hash1;
}
package main;
Foo::Bar->do_stuff();
Foo::Bar->do_other_stuff();
But if you need to modify instance variables, you need to have reference to this instance. I see some strategies that would work:
inherit from Foo, so the hashes will be in instance of Foo::Bar
pass reference to Foo in constructor and store it as property in Foo::Bar
pass Foo reference as parameter to method
Proper solution depends on what you are trying to do and how you going to use it.
I'm working with a few Perl packages, we'll call them Some::Parser and Some::Data. A Some::Parser object has methods to return objects of type Some::Data. I have written a class that extends the Some::Data class, let's call it My::Data. Objects of class My::Data are really just objects of class Some::Data, but with additional methods that make it easier to work with.
My problem is that I want to continue to use the Some::Parser class to do the hard work of parsing the data. As I said earlier, Some::Parser objects give me Some::Data objects. Once I have a Some::Data object in hand, is there any way to reclassify it as a My::Data object? How would I do this?
I'm totally willing to change my approach, assuming someone can suggest a better way of doing what I want to do, but writing my own parser is not something I'm interested in doing!
This smells like a bit of a kludge. It might be time to rethink your strategy. For example, maybe you should write My::Parser which returns My::Data objects.
But if you don't want to do that, you can manually use bless to change an object's class:
my $obj = Some::Data->new;
bless $obj, 'My::Data';
See bless in perldoc.
Probably the best way to handle something like this is for Some::Parser to provide a way to specify the class it should be using for data objects. For example, HTML::TreeBuilder provides the element_class method. If you want TreeBuilder to produce something other than HTML::Element nodes, you subclass HTML::TreeBuilder and override element_class to return your desired node class. (The actual code in TreeBuilder is a bit more complex, because there was a different mechanism for doing this prior to HTML-Tree 4, and the new maintainer didn't want to break that.)
I take it that you didn't write Some::Parser, but perhaps it has this capability already. If not, maybe its maintainer will accept a patch. It should be a fairly simple change. You'd just add a data_class method (sub data_class { 'Some::Data' }), and then change Some::Data->new to $self->data_class->new. Then you can subclass Some::Parser to create My::Parser, and just override data_class.
You can rebless anything.
Inheritance in Perl 5 is nothing more than searching #ISA.
You can re-bless the returned object to whatever your heart desires:
#!/usr/bin/perl
package Some::Data;
use strict; use warnings;
sub new { my $class = shift; bless { #_ } => $class }
sub a { $_[0]->{a} }
package My::Data;
use strict; use warnings;
use base 'Some::Data';
sub a_squared {
my $self = shift;
my $v = $self->a;
return $v * $v;
}
package Some::Parser;
use strict; use warnings;
sub new { my $class = shift; bless { #_ } => $class }
sub parse { return Some::Data->new(a => 3) }
package main;
use strict; use warnings;
my $data = Some::Parser->new->parse;
bless $data => 'My::Data';
printf "%.1f\t%.1f\n", $data->a, $data->a_squared;
Alternatively, you can use #cjm's idea:
#!/usr/bin/perl
package Some::Data;
use strict; use warnings;
sub new { my $class = shift; bless { #_ } => $class }
sub a { $_[0]->{a} }
package My::Data;
use strict; use warnings;
use base 'Some::Data';
sub a_squared {
my $self = shift;
my $v = $self->a;
return $v * $v;
}
package Some::Parser;
use strict; use warnings;
sub new { my $class = shift; bless { #_ } => $class }
sub parse {
my $self = shift;
return $self->data_class->new(a => 3);
}
sub data_class { $_[0]->{data_class} }
package main;
use strict; use warnings;
my $data = Some::Parser->new(data_class => 'My::Data')->parse;
printf "%.1f\t%.1f\n", $data->a, $data->a_squared;
I'd consider re-blessing venturesome. Once you have an object you can't really tell if it was created using its constructor ( usually Foo::new() ), or someone re-blessed some other object.
The problem is, some constructors are fat, this means they do a whole lotta more than just blessing something:
sub new {
my $pkg = shift;
my ($required) = #_;
croak "Bad call" unless defined $required;
_do_something_magic ($required);
my $self = { 'foo' => $required };
return bless $self, $pkg;
}
In this case your re-blessed object might not be the one you'll expect later in code.
One may consider constructors with "re-blessing" functionality build in. But such "object converters" will make the design even more complicated.
Stick to the basic definition: "An object is an instance of the class. Forever.".
I've just started to learn about tie. I have a class named Link which I would like to do the following thing:
if fetched, return the link's address
if stored, store the new address
be able to call methods on it
So far, my code is :
package Link;
sub FETCH {
my $this = shift;
return $this->{"site"};
}
sub STORE {
my ($self,$site) = #_;
$self->{"site"} = $site;
}
sub print_method {
my $self = shift;
print $self->{"site"};
}
sub TIESCALAR {
my $class = shift;
my $link = shift;
my $this = {};
bless($this,$class);
$this->{"site"} = $link;
return $this;
}
1;
And the code I'm using to check the functionality is:
use Link;
tie my $var,"Link","http://somesite.com";
$var->print_method;
When ran, the script will terminate with the following error:
Can't call method "print_method" without a package or object reference at tietest.pl line 4..
If I understand its message correctly, $var->print_method resolves to some string upon which the method print_method is called. How could I benefit from tie, but also use the variable as an object?
EDIT: after experimenting a bit,I found out that if I return $self on fetch , I can call the methods , however , fetch won't return the address .
EDIT 2:the perl monks supplied me the solution : tied . tied will return a reference to the object VARIABLE .
By combining tied with my methods , I can accomplish everything I wanted .
Tie is the wrong tool for this job. You use ties when you want the same interface as normal data types but want to customize how the operations do their work. Since you want to access and store a string just like a scalar already does, tie doesn't do anything for you.
It looks like you want the URI module, or a subclass of it, and perhaps some overloading.
If you really need to do this, you need to use the right variable. The tie hooks up the variable you specify to the class you specify, but it's still a normal scalar (and not a reference). You have to use the object it returns if you want to call methods:
my $secret_object = tie my($normal_scalar), 'Tie::Class', #args;
$secret_object->print_method;
You can also get the secret object if you only have the tied scalar:
my $secret_object = tied $normal_scalar;
I have an entire chapter on tie in Mastering Perl.
I suggest making a normal Perl object and then overloading stringification. You lose the ability to store a value through assignment, but retain the ability to get the value out by printing the object. Once you start wanting to call methods directly, an object is probably what you want.
package Link;
use strict;
use Carp;
use overload
(
'""' => sub { shift->site },
fallback => 1,
);
sub new
{
my $class = shift;
my $self = bless {}, $class;
if(#_)
{
if(#_ == 1)
{
$self->{'site'} = shift;
}
else { croak "$class->new() expects a single URL argument" }
}
return $self;
}
sub site
{
my $self = shift;
$self->{'site'} = shift if(#_);
return $self->{'site'};
}
sub print_method
{
my $self = shift;
print $self->site, "\n";
}
1;
Example usage:
use Link;
my $link = Link->new('http://somesite.com');
print $link, "\n"; # http://somesite.com
$link->print_method; # http://somesite.com
If you really, really want assignment to work too, you can combine a normal object with overloaded stringification (Link, above) with tie:
package LinkTie;
use strict;
use Link;
sub FETCH
{
my $this = shift;
return $this->{'link'};
}
sub STORE
{
my($self, $site) = #_;
$self->{'link'}->site($site);
return $site;
}
# XXX: You could generalize this delegation with Class::Delegation or similar
sub print_method
{
my $self = shift;
print $self->{'link'}->print_method;
}
sub TIESCALAR
{
my $class = shift;
my $self = bless {}, $class;
$self->{'link'} = Link->new(#_);
return $self;
}
1;
Example usage:
tie my $link,'LinkTie','http://somesite.com';
print $link, "\n"; # http://somesite.com
$link->print_method; # http://somesite.com
$link = 'http://othersite.com';
print $link, "\n"; # http://othersite.com
$link->print_method; # http://othersite.com
This is all quite hideous and a long way to go just to get the dubious ability to assign to something that you can also call methods on and also print as-is. A standard URI object with stringification is probably a better bet.