I have a library of objects in perl all having the same function_calls.
I am looking for how to create an approriate object from the library from a string.
my $object_name='myObject';#would actually be a hash lookup from user input with appropriate error checks
my $string = "return ${object_name}->new(\#params);";
my $object = eval $string;
$object->some_function();
Now I am having a problem, it works for some objects and doesn't for others? Is there a more reliable way of doing this. I have tried printing the string out before eval and it appears to be correct with the correct class name, also every object takes the same parameter, any Ideas, thanks.
The eval is not necessary since a string can be used as a package name, so the lines:
my $object_name = 'myObject';
my $object = $object_name->new(#params);
Will do what you want. If you want to make sure that myObject is actually a valid package name you could do:
my $object_name = 'myObject';
unless ($object_name->can('new')) {
die "bad object name: $object_name";
}
my $object = $object_name->new(#params);
Related
I have inherited some Perl code which contains a line that is mysterious to me:
my $binary = A->current->config->settings('arg1', 'arg2')
Basically, I am not sure how to find the related code. "A" is NOT a variable in the local code so I thought this was a class hierarchy. However I checked the directory structure to see if the following path existed, but there was none:
A/current/config/settings.pm
Is A->current->config->settings guaranteed to be a nested class hierarchy, or could it be something else? For example could config actually be a property or method of a different object A->current?
Any assistance you could lend tracking this down would be greatly appreciated!
A is a class name, you should find it in A.pm. current should be a method of the class, defined under a sub current in A.pm. It returns an object whose config method is being called which returns an object again whose settings method is being called with arguments 'arg1' and 'arg2' (well, in fact, the object itself is the first argument).
In fact, any of the methods can return a class instead of an object, too.
Step through the code in the perl debugger and see where it takes you.
foo->bar is a method call, meaning that there is likely a subroutine called bar defined in the package referred to by foo (or a superclass), and gives you no information about whether there is a package bar or foo::bar.
Is A->current->config->settings guaranteed to be a nested class hierarchy
You're thinking of A::current::config::settings.
The following are method calls:
INVOCANT->name
INVOCANT->name(LIST)
That means that A->current->config->settings is a chain of method calls.
The only class named in that code is A.
could config actually be a property or method of a different object A->current?
It's the name of a method of the object or class returned by A->current.
How to find the Perl code referenced by this line?
my $binary = A->current->config->settings('arg1', 'arg2');
is short for
my $obj1 = A->current;
my $obj2 = $obj1->config;
my $binary = $obj2->settings('arg1', 'arg2');
Now that you have the objects available, you can find the class of which they are an instance using
say ref($obj) || "Not a reference";
or
use Scalar::Util qw( blessed );
say blessed($obj) // "Not an object";
As explained, you are dealing with a chain of method calls in the class named A, where at least the first one is a class method since it is invoked on the class (A) itself, not on an object.
An easy way to find that class is by using Class::Inspector
use Class::Inspector;
say "Filename: ", Class::Inspector->resolved_filename( 'A' );
which printed the full path to the class I used in my tests. Also see loaded_filename.
Another interesting way to interrogate a class is to add to it at runtime.
Create an object of A and add to it a method of your choice at runtime
my $objA = A->new();
eval q( sub A::get_info { print "$_\n" for (caller(0)) } );
if ($#) { print "Eval: $#" };
eval q( sub A::boom { croak "Stacktrace: " } );
if ($#) { print "Eval: $#" };
$objA->get_info();
$objA->boom();
These are simple examples but you can acquire practically any information from inside a method.
If A happens to not have a method called new (possible) work with methods in the given chain, starting with my $objA = A->current.
Or, you can directly add a subroutine to the package's symbol table
*{A::new_method} = sub { say "A new method" };
$any_obj_of_A->new_method();
which is now also available on all existing instances, as well as on new ones.
Running Perl 5.18 on Ubuntu 14.04 LTS, I wanted to create some pathname constants so I did
use Path::Class;
use constant FILEPATH => file('directory', 'filename');
However, when I came to use the constant in a hash aggregate ...
my $hash = { filepath => FILEPATH };
use Data::Dumper;
print Dumper $href;
... I was surprised to discover that the value of the filepath key was a blessed reference, not the string result from the function call that I was expecting.
I can work around the problem like this ...
use constant FILEPATH => file('directory', 'filename') . "";
... which forces the Perl interpreter to evaluate the blessed reference, but
(a) is there a better way, and
(b) what the heck is going on?!
I know that use constant is evaluated in a list context, but normally use constant MYCONST => mysub(arg1, arg2); does The Right Thing, evaluates the subroutine call and uses the return value. What's the cleverness with Path::Class::file that breaks this expectation?
The file function from the module Path::Class is in fact a constructor for a Path::Class object. It always returns an object. Even the SYNOPSIS says so.
use Path::Class;
my $dir = dir('foo', 'bar'); # Path::Class::Dir object
my $file = file('bob', 'file.txt'); # Path::Class::File object
If all you want is the path, call that method on the return value of file and assign that calls' return value to your constant. The object you get is a Path::Class::File. It provides various methods. To do the same as when you use the string overload, call the stringify method.
use constant FILEPATH => file('directory', 'filename')->stringify;
The relevant part of HTML::Tiny decides what to do based on the type of the inputs. It expects either undef, a string or an array ref, but you provided something that is none of these. In other words, this is a case of GIGO. You are using the value returned by file(), which is an object that overloads stringification.
Use either of the following to provide the expected input:
use constant FILEPATH => file('directory', 'filename')->stringify;
or
use constant FILEPATH => "".file('directory', 'filename');
Note that it's usually unsafe to unsafe to use objects as constants because they're not constant. However, since file() returns an immutable object, there's no harm in using it as a constant since it really is constant.
You're right about Path::Class::file returning an object. That's what all the "bless" stuff was in the Dumper output. Sorry I didn't realise that sooner.
As you'll see from my comments, I ran into the problem using HTML::Tiny, which you can see as follows:-
$ perl -MPath::Class -MHTML::Tiny -le 'print HTML::Tiny->new(mode=>"html")->form({action=>file("cgi-bin", "script")})'
<form action></form>
As you can see, the action attribute is missing the path. However,
$ perl -MPath::Class -MHTML::Tiny -le 'print HTML::Tiny->new(mode=>"html")->form({action=>file("cgi", "script").""})'
<form action="cgi/script"></form>
This works because the ."" string concatenation operator causes the Class::Path::File object's automatic stringifier to be called, so an actual string is passed in the {action=>value} hash, not an object.
If you dig into the HTML::Tiny 1.05 code, you'll find sub _tag on line 622, which goes
if ( ref $val ) {
return $attr if not $self->_xml_mode;
This test allows you to use { attr=>[] } to output an attribute name without a value, but unfortunately the test is also TRUE if $val is an object. I'll raise a bug report for this against HTML::Tiny.
I get an error such as "can't call method 'xxxx' on an undefined value" when attempting to check if an object has been created (by the perl module Bio::Perl).
Is there a general way of checking if an attribute has a value or not? I would have liked to do something like:
if ($the_object->the_attribute) {
But as long as the attribute is "undef", calling the method will only give me the error message. I have not been able to find a solution to this problem - which is real, because the object is created by the Bio::Perl module, and some attributes may or may not be set. Maybe I should add that I am not particularly perl-objects-savvy.
edit:
Below is a relevant part of my code. The get_sequence() function is in the Bio::Perl module. On line 13, how can I make sure that there is a value (sequence in this case) before checking the length of it?
my #msgs;
my #sequence_objects;
my $maxlength = 0;
for ( #contigs ) {
my $seq_obj;
try {
$seq_obj = get_sequence( 'genbank', $_ );
}
catch Bio::Root::Exception with {
push #msgs, "Nothing found for $_ ";
};
if ( $seq_obj ) {
my $seq_length = length( $seq_obj->seq );
if ( $seq_length > $maxlength ) {
$maxlength = $seq_length;
}
push #sequence_objects, $seq_obj;
}
}
...
if ($the_object->the_attribute) {
This checks if the return value of the method the_attribute is true. True means that it's not 0, the empty string q{} or undef.
But you said you want to know whether the object exists.
Let's go over some basics first.
# | this variable contains an object
# | this arrow -> tells Perl to call the method on the obj
# | | this is a method that is called on $the_object
# | | |
if ($the_object->the_attribute) {
# ( )
# the if checks the return value of the expression between those parenthesis
It looks like you're confusing a few things.
First, your $the_object is supposed to be an object. It probably came from a call like this:
my $the_object = Some::Class->new;
Or maybe it was returned from some other function call. Maybe some other object returned it.
my $the_object = $something_else->some_property_that_be_another_obj
Now the_attribute is a method (that's like a function) that returns a specific piece of data in your object. Depending on the implementation of the class (the building plan of the object), if that attribute is not set (initialized), it might either just return undef, or some other value.
But the error message you are seeing is not related to the_attribute. If it was, you'd just not call the code in the block. The if check would catch it, and decide to go to else, or do nothing if there is no else.
Your error message says you are trying to call a method on something that is undef. We know you are calling the the_attribute accessor method on $the_object. So $the_object is undef.
The easiest way to check if something has a true value is to just put it in an if. But you already seem to know that.
if ($obj) {
# there is some non-false value in $obj
}
You've now checked that $obj is something that is true. So it could be an object. So you could now call your method.
if ($obj && $obj->the_attribute) { ... }
This will check the true-ness of $obj and only continue if there is something in $obj. If not, it will never call the right hand side of the && and you will not get an error.
But if you want to know whether $obj is an object that has a method, you can use can. Remember that attributes are just accessor methods to values stored inside the object.
if ($obj->can('the_attribute')) {
# $obj has a method the_attribute
}
But that can blow up if $obj is not there.
If you're not sure that $obj is really an object, you can use the Safe::Isa module. It provides a method $_call_if_object1 that you can use to safely call your method on your maybe-object.
$maybe_an_object->$_call_if_object(method_name => #args);
Your call would translate to.
my $the_attribute = $obj->$_call_if_object('the_attribute');
if ($the_attribute) {
# there is a value in the_attribute
}
The same way you can use $_isa and $_can from Safe::Isa.
1) Yes, the method starts with a $, it's really a variable. If you want to learn more about how and why this works, watch the talk You did what? by mst.
I am new to Perl and currently learning Perl object oriented and came across writing a constructor.
It looks like when using new for the name of the subroutine the first parameter will be the package name.
Must the constructor be using the keyword new? Or is it because when we are calling the new subroutine using the packagename, then the first parameter to be passed in will be package name?
packagename->new;
and when the subroutine have other name it will be the first parameter will be the reference to an object? Or is it because when the subroutine is call via the reference to the object so that the first parameter to be passed in will be the reference to the object?
$objRef->subroutine;
NB: All examples below are simplified for instructional purposes.
On Methods
Yes, you are correct. The first argument to your new function, if invoked as a method, will be the thing you invoked it against.
There are two “flavors” of invoking a method, but the result is the same either way. One flavor relies upon an operator, the binary -> operator. The other flavor relies on ordering of arguments, the way bitransitive verbs work in English. Most people use the dative/bitransitive style only with built-ins — and perhaps with constructors, but seldom anything else.
Under most (but not quite all) circumstances, these first two are equivalent:
1. Dative Invocation of Methods
This is the positional one, the one that uses word-order to determine what’s going on.
use Some::Package;
my $obj1 = new Some::Package NAME => "fred";
Notice we use no method arrow there: there is no -> as written. This is what Perl itself uses with many of its own functions, like
printf STDERR "%-20s: %5d\n", $name, $number;
Which just about everyone prefers to the equivalent:
STDERR->printf("%-20s: %5d\n", $name, $number);
However, these days that sort of dative invocation is used almost exclusively for built-ins, because people keep getting things confused.
2. Arrow Invocation of Methods
The arrow invocation is for the most part clearer and cleaner, and less likely to get you tangled up in the weeds of Perl parsing oddities. Note I said less likely; I did not say that it was free of all infelicities. But let’s just pretend so for the purposes of this answer.
use Some::Package;
my $obj2 = Some::Package->new(NAME => "fred");
At run time, barring any fancy oddities or inheritance matters, the actual function call would be
Some::Package::new("Some::Package", "NAME", "fred");
For example, if you were in the Perl debugger and did a stack dump, it would have something like the previous line in its call chain.
Since invoking a method always prefixes the parameter list with invocant, all functions that will be invoked as methods must account for that “extra” first argument. This is very easily done:
package Some::Package;
sub new {
my($classname, #arguments) = #_;
my $obj = { #arguments };
bless $obj, $classname;
return $obj;
}
This is just an extremely simplified example of the new most frequent ways to call constructors, and what happens on the inside. In actual production code, the constructor would be much more careful.
Methods and Indirection
Sometimes you don’t know the class name or the method name at compile time, so you need to use a variable to hold one or the other, or both. Indirection in programming is something different from indirect objects in natural language. Indirection just means you have a variable that contains something else, so you use the variable to get at its contents.
print 3.14; # print a number directly
$var = 3.14; # or indirectly
print $var;
We can use variables to hold other things involved in method invocation that merely the method’s arguments.
3. Arrow Invocation with Indirected Method Name:
If you don’t know the method name, then you can put its name in a variable. Only try this with arrow invocation, not with dative invocation.
use Some::Package;
my $action = (rand(2) < 1) ? "new" : "old";
my $obj = Some::Package->$action(NAME => "fido");
Here the method name itself is unknown until run-time.
4. Arrow Invocation with Indirected Class Name:
Here we use a variable to contain the name of the class we want to use.
my $class = (rand(2) < 1)
? "Fancy::Class"
: "Simple::Class";
my $obj3 = $class->new(NAME => "fred");
Now we randomly pick one class or another.
You can actually use dative invocation this way, too:
my $obj3 = new $class NAME => "fred";
But that isn’t usually done with user methods. It does sometimes happen with built-ins, though.
my $fh = ($error_count == 0) ? *STDOUT : *STDERR;
printf $fh "Error count: %d.\n", $error_count;
That’s because trying to use an expression in the dative slot isn’t going to work in general without a block around it; it can otherwise only be a simple scalar variable, not even a single element from an array or hash.
printf { ($error_count == 0) ? *STDOUT : *STDERR } "Error count: %d.\n", $error_count;
Or more simply:
print { $fh{$filename} } "Some data.\n";
Which is pretty darned ugly.
Let the invoker beware
Note that this doesn’t work perfectly. A literal in the dative object slot works differently than a variable does there. For example, with literal filehandles:
print STDERR;
means
print STDERR $_;
but if you use indirect filehandles, like this:
print $fh;
That actually means
print STDOUT $fh;
which is unlikely to mean what you wanted, which was probably this:
print $fh $_;
aka
$fh->print($_);
Advanced Usage: Dual-Nature Methods
The thing about the method invocation arrow -> is that it is agnostic about whether its left-hand operand is a string representing a class name or a blessed reference representing an object instance.
Of course, nothing formally requires that $class contain a package name. It may be either, and if so, it is up to the method itself to do the right thing.
use Some::Class;
my $class = "Some::Class";
my $obj = $class->new(NAME => "Orlando");
my $invocant = (rand(2) < 1) ? $class : $obj;
$invocant->any_debug(1);
That requires a pretty fancy any_debug method, one that does something different depending on whether its invocant was blessed or not:
package Some::Class;
use Scalar::Util qw(blessed);
sub new {
my($classname, #arguments) = #_;
my $obj = { #arguments };
bless $obj, $classname;
return $obj;
}
sub any_debug {
my($invocant, $value) = #_;
if (blessed($invocant)) {
$invocant->obj_debug($value);
} else {
$invocant->class_debug($value);
}
}
sub obj_debug {
my($self, $value) = #_;
$self->{DEBUG} = $value;
}
my $Global_Debug;
sub class_debug {
my($classname, $value) = #_;
$Global_Debug = $value;
}
However, this is a rather advanced and subtle technique, one applicable in only a few uncommon situations. It is not recommended for most situations, as it can be confusing if not handled properly — and perhaps even if it is.
It is not first parameter to new, but indirect object syntax,
perl -MO=Deparse -e 'my $o = new X 1, 2'
which gets parsed as
my $o = 'X'->new(1, 2);
From perldoc,
Perl suports another method invocation syntax called "indirect object" notation. This syntax is called "indirect" because the method comes before the object it is being invoked on.
That being said, new is not some kind of reserved word for constructor invocation, but name of method/constructor itself, which in perl is not enforced (ie. DBI has connect constructor)
I am kinda beginner in perl and I need know how can I check object class name.
My code is:
foreach my $y (keys %$x) {
print "$y\t$x->{$y}\n";
}
with output:
154176568 [object HTMLImageElement]
146292140 [object HTMLDocument]
153907016 [object HTMLImageElement]
I need to print just keys that are HTMLImageElement objects.
Now, question is:
(1) How can I check the class name
(2) How can I get/print class name
In Perl all classes magically extend the UNIVERSAL package. It has a method called isa() that you can use to do this:
foreach my $y (keys %$x) {
if( $x->{$y}->isa('HTMLImageElement') ) {
print "$y\t$x->{$y}\n";
}
}
Looking at the source for JE, it looks like JE::Object::Proxy is a subclass of JE::Object, and JE::Object has a stringification method (use overload fallback => 1, ... '""' => 'to_string' ...).
So when you do print "$y\t$x->{$y}\n";, this is printing the result of stringifying $x->{$y}.
You can stringify the object by putting it in double quotes, so "$x->{$y}". This expression will then have values such as you saw being printed, e.g. '[object HTMLImageElement]'.
If you want to pick up only HTMLImageElement objects, then you could check for these using an expression like
"$x->{$y}" eq '[object HTMLImageElement]'
If you especially want to extract the string 'HTMLImageElement' from the stringified value, you could do that using a regexp, e.g.
("$x->{$y}" =~ m{^\[object (.*)\]$}so)[0]
THOUGH, looking at the source for JE::Object::Proxy, JE::Object::Proxy has a method class which might perhaps return the name of the class that the object is a proxy for. So you might be able to get the class name using $x->{$y}->class, and then be able to test that directly as in $x->{$y}->class eq 'HTMLImageElement'.
If you want a string indicating the class name, use ref($object). This will return the reference type for a variable, which for perl objects, ends up being the package of the blessed object.
If you want to simply check if a variable is an instance of a certain class, use the isa() method. For instance:
if ($obj->isa('Animal::Dog')) {
push #dogs, $obj;
}