Sorry for bothing, just a quick question. How can I access to global variable like $pid from class method? The following code results compile error.
class C {
C() {
Write-Host $pid
}
}
You need to define it as a global variable, otherwise it will look in the methods scope.
Write-Host $Global:pid
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.
I need $this to work inside static class! How to achieve that? Any workaround? I have analyzed return of Get-PSCallStack in class context and found nothing useful.
I need this for (a) logging and for (b) calling other static methods of same class without mentioning its name again and again.
Sample code (PowerShell v5):
class foo {
static [void]DoSomething() {
[foo]::DoAnything() #works
#$this.DoAnything #not working
$static_this = [foo]
$static_this::DoAnything() #works
}
static [void]DoAnything() {
echo "Done"
}
}
[foo]::DoSomething()
Static classes do not have this pointer. See MSDN
Static member functions, because they exist at the class level and not
as part of an object, do not have a this pointer. It is an error to
refer to this in a static method.
You must call method by class name.
Currently I am using the following syntax to explicitly access a private scoped variable, inside of a PowerShell function:
function MyPowershellFunction {
param($param1)
# ...
# lot of code here
# ...
# access variable x on private scope explicitly
if ($private:x) {
# do something
}
}
I am doing this so that I do not accidentally refer to a variable defined in parent scope. But the code looks ugly by having private all around. Is there a simpler way?
By making a variable private you restrict its visibility to the current scope. Since variables are looked up in the current scope first $x should give you the private variable after it was initially declared private as long as you don't leave the scope. Using the scope modifier all the time shouldn't be necessary.
Just use the Local scope modifier:
function MyPowershellFunction {
param($param1)
# access variable x on private scope explicitly
if ($local:x) {
# do something
}
}
The if statement does not see any $x defined in the parent scope.
I am calling a method as follows:
$self->class->method
I would like to pass a reference to this method as a parameter into a subroutine.
I have tried
\&{ $self->class->method }
but I get the following error:
Unable to create sub named ""
Any ideas on how to do this?
You can take a reference to static class method, but in your case you could use anonymous closure to achieve similar,
my $ref = sub { $self->class->method };
# ..
my $result = $ref->();
The class method is a little strange. I would expect a method with a name like that to return the class string, but it clearly returns an object as it has a method method.
I recommend that you use UNIVERSAL::can, which returns a reference to the given method if it exists. So you can write code like this
my $method_ref = $self->class->can('method');
mysub($method_ref);
You can also use the curry module to achieve this:
use curry;
my $mref = $self->class->curry::method;
I'm using MockObjects in some of my tests and just had to test a function with a call to a SUPER class and I cannot seem to make it work. Can UNIVERSAL calls like $this->SUPER::save() not be mocked? If yes, how do you do it?
Thanks.
Edit:
Found it!
Use fake_module from Test::MockObject
So, let's say your base module it Some::Module, and your subroutine is making a $this->SUPER::save call, use
my $child_class_mockup = Test::MockObject->new();
$child_class_mockup->fake_module(
'Some::Module',
save => sub () { return 1; }
);
Leaving the question open for a couple of days, to get inputs about different ways/libraries of doing this (what if, the SUPER call had a SUPER call?) before accepting this answer.
Find out the name of the object's superclass (or one of the superclasses, since Perl has multiple inheritance), and define the save call in the superclass's package.
For example, if you have
package MyClass;
use YourClass;
our #ISA = qw(YourClass); # <-- name of superclass
...
sub foo {
my $self = shift;
...
$self->SUPER::save(); # <--- want to mock this function in the test
...
}
sub save {
# MyClass version of save method
...
}
then in your test script, you would say
no warnings 'redefine'; # optional, suppresses warning
sub YourClass::save {
# mock function for $yourClassObj->save, but also
# a mock function for $myClassObj->SUPER::save
...
}