Why don't Perl attribute handlers get called from other packages? - perl

I am having a strange problem with Attribute::Handlers that looks like some kind of bug:
package MyPackage;
use Attribute::Handlers;
sub UNIVERSAL::foo :ATTR(CODE) {
...
}
When used in MyPackage, or from the main package of a script that uses MyPackage, the foo handler is called whenever the compiler comes across a function of the form
sub bar:foo {
...
}
However, I have another package, in a separate .pm file, that uses MyPackage. The compiler accepts the ":foo" attribute, but the handler is not called.
I tried writing an import function in MyPackage that exports the foo handler to the caller's namespace, but that doesn't seem to help.
Can anyone make sense of this? I've been racking my brain for the past few days over how to fix this.

By default, attribute handlers are called in the CHECK block after the compilation phase.
If the "using" package uses eval "use packagename"; then only BEGIN blocks will be executed. CHECK blocks won't be executed, and the attribute handlers won't be called.
Try using ATTR(CODE,BEGIN) to execute the handler in the BEGIN block.

I somehow totally missed the Attribute::Handlers in your post yesterday - as mentioned in my comment to the older version of this answer, perhaps wrapping the use MyPackage in a BEGIN block will cause things to be resolved properly.
I'm unsure as to why you chose to put the foo() attribute handler in UNIVERSAL - was that a step toward trying to get it to work?

Related

Perl use Package - AH01215: Undefined subroutine

I'm using the package URI::Escape. Usually, I can call the functions directly by naming it, e.g. uri_unescape('some text') but actual I'm getting AH01215: Undefined subroutine &MyFunctions::uri_unescape called at ...
This happens in an own package ('MyFunctions') of me. I got the use URI::Escape line. When I use &URI::Escape::uri_unescape it seems to work fine. But I just don't get why it is looking for this subroutine in my package...
Can someone explain it to me? Is there any way to solve this? I really don't wanna write this whole package-name::funktion every time I call this function :/
The subroutines are imported into the current namespace. You have to put the use line after the package declaration:
package MyFunctions;
use URI::Escape;
Otherwise, the functions are imported into the previous namespace, which is probably main in your case (you can verify by running main::uri_unescape().

Perl module version information in the BEGIN block

In some CPAN modules I found the next construction
BEGIN {
$Package::Name::VERSION = "N.N";
}
What is a rationale behind putting the package version information into the BEGIN block?
for example: http://cpansearch.perl.org/src/JSWARTZ/Poet-0.12/lib/Poet/Cache.pm
EDIT - in the most recent module version it is pulled out, but anyway - it was here - so wondering why it is good (or bad) :)
It's one of those things that everyone has always done and can't remember why!
Essentially it is because use statements allow multiple modules to be in compilation at the same time, so although it looks like a module is complete it may have only just started compiling.
Any code being compiled can check the value of $Module::VERSION by using the inherited UNIVERSAL::VERSION subroutine, which is already defined implicitly before a module even starts compiling.
Remember that, if Module.pm contains
use Another::Module;
Then compilation of Module.pm is put on hold while Another/Module.pm is compiled.
There is nothing to stop Another::Module from doing
use Module 1.5;
which will call Module::VERSION(1.5) (inherited from UNIVERSAL::VERSION) to check that $Module::VERSION is 1.5 or greater.
If $Module::VERSION is defined outside a BEGIN block, it won't be set until after all use statements have been completed, and so too late for other modules to do version checking on Module.
I hope this is clear. I can't help thinking there must be a simpler explanation, but nothing comes to mind.

Explain this witchcraft!!! (in Perl, with Moose and namespace::autoclean)

So these days I'm working with a project that uses Perl and Moose. I understand Moose is built on MOP. I'm not too familiar with MOP, and I've encountered something I don't understand, and I could use a theoretical explanation. Here is the module namespace::autoclean's documentation:
SYNOPSIS
package Foo;
use namespace::autoclean;
use Some::Package qw/imported_function/;
sub bar { imported_function('stuff') }
# later on:
Foo->bar; # works
Foo->imported_function; # will fail. imported_function got cleaned after compilation
So, back before I ever used Moose, the way that you called a method on an object was: the Perl interpreter would look up that method in the symbol table of the package that your object was blessed into (then, if not found, consider #ISA inheritance and the like). The way it called an imported function from within the package was: it looked up the name of the function in the symbol table of the package. As far as I've been aware to date, that means the same symbol table, either way, so this behavior should be impossible.
My initial inspection of the source was not productive. In broad terms, what is different when using Moose, MOP, and namespace::autoclean, that this sort of trickery becomes possible?
ed. To be especially clear, if I were to replace use namespace::autoclean with
CHECK { undef *Foo::imported_function }
then the Foo->bar; call described in the documentation would crash, because Foo->bar doesn't know where to find imported_function.
It's actually quite simple. For
some_sub()
some_sub is resolved at compile time. For
$o->some_method()
some_method is resolved at runtime. It cannot be done at compile-time since it depends on the value of $o.
There is nothing here that is non-standard. The line
use Some::Package qw/imported_function/;
imports imported_function into the current package, so Foo::imported_function is the same subroutine as Some::Package::imported_function. That assumes that Some::Package inherits from Exporter to do the necessary manipulation of the symbol tables.
The calls are method calls, so Foo->bar is the same as Foo::bar('Foo'). The only special thing here is that the magic that has been done by the import function from Exporter is undone at the end of compile time by namespace::autoclean.
I haven't looked at the code for this module, but since a package's symbol table is just a hash (known as a stash, for symbol table hash) it would be easy to preserve its state at one point and restore it afterwards. So I would guess namespace::autoclean takes a snapshot of the symbol table when it is loaded and the restores that state at the end of compilation time. This can conveniently be done in a CHECK block which behaves like a BEGIN block but is executed at the end of compilation and before the run starts.

Importing a require'd file as if it were a use statement

I am experiencing a problem with using a constant defined in a configuration file.
This is my package:
package myPackage;
require "APIconfig.pl";
APIconfig::import(APIconfig);
use constant SERVICE_URL => APIconfig::SERVICE_URL();
The configuration looks like this:
package APIconfig;
use constant SERVICE_URL => 'http://api.example.org/blah';
1;
When running this code, I get the following error:
Undefined subroutine &APIconfig::SERVICE_URL called at API.pl line 4.
I cannot use 'use' instead of 'require' because this expects the configuration file to be named .pm, and it's called .pl on a lot of servers on our network.
How can I use the package without renaming the file?
There are two differences between 'use' and 'require'. One of them affects your current problem, the other doesn't. Unfortunately you are working around one that has no effect.
The differences are:
1/ 'use' calls the import() function, 'require' doesn't.
2/ 'use' happens at compile time, 'require' happens at runtime.
You're working around the fact that 'require' doesn't call import() by calling it explicitly. This has no effect as your module doesn't export any symbols and doesn't have an import() subroutine.
You're not working around the fact that 'use' statements are executed at runtime. The problem is that "use constant SERVICE_URL => APIconfig::SERVICE_URL();" is executed at compile time and your 'require' hasn't run by then so myPackage knows nothing about APIconfig.
The (nasty, hacky) solution is to put the 'require' statement into a BEGIN block - to force it to be executed at compile time. You'll also want to remove the call to import() as that gives a runtime error (due to the absence of the subroutine).
The test files that I used to work this out are as follows:
$ cat APIconfig.pl
package APIconfig;
use constant SERVICE_URL => 'http://api.example.org/blah';
1;
$ cat api.pl
#!/usr/bin/perl
package myPackage;
BEGIN {
require "APIconfig.pl";
}
# APIconfig::import(APIconfig);
use constant SERVICE_URL => APIconfig::SERVICE_URL();
print SERVICE_URL, "\n";
$ ./api.pl
http://api.example.org/blah
The real solution is to rewrite APIconfig as a real module. You hint that you know that, but that environmental issues prevent you taking this approach. I highly recommend trying to work around those issues and doing things correctly.
That can't be possibly right - there is no subroutine import in package APIconfig. Once you're accessing symbolic names with a full package path, you don't need to export/import anyway.
The solution is to run require at compile time, before use constant. This works:
package myPackage;
BEGIN {
require "APIconfig.pl";
}
use constant SERVICE_URL => APIconfig::SERVICE_URL();
If it's a configuration file, don't make it code. I have a whole chapter in Mastering Perl about that, and there are many modules on CPAN to help you with almost any configuration format.
If it's code, why not just make it a module so you can use use. Modules are so much easier to control and manipulate within another program.
The easiest solutions are the ones where you don't swim against the tide. :)
Beyond that, use is the same as:
BEGIN {
require Module;
Module->import;
}
You just do the same thing with filename and the namespace it defines (as long as the code in the file looks like a module):
BEGIN {
require "file.pl"; # defines SomeNamespace
SomeNamespace->import;
}

How can I mark Perl code as deprecated?

In my project I'm currently preparing a step-by-step move from legacy code to new, properly-designed and tested modules. Since not every fellow programmer follows closely what I do, I would like to emit warnings when old code is used. I would also strongly prefer being able to output recommendations on how to port old code.
I've found two ways of doing it:
Attribute::Deprecated, which is fine for functions, but rather cumbersome if a complete module is deprecated. Also, no additional information apart from warnings.
Perl::Critic::Policy::Modules::ProhibitEvilModules for modules or maybe a custom Perl::Critic rule for finer deprecation on function or method level. This method is fine, but it's not immediately obvious from code itself that it's deprecated.
Any other suggestions or tricks how to do this properly and easy?
For methods and functions, you can just replace the body of the function with a warning and a call to the preferred function.
perl perllexwarn gives the following example:
package MyMod::Abc;
sub open {
warnings::warnif("deprecated",
"open is deprecated, use new instead");
new(#_);
}
sub new {
# ...
}
1;
If you are deprecating a whole module, put the warning in a BEGIN block in the module.
You can also put the warnings in the import method (e.g. Win32::GUI::import): It all depends on exactly what you want to do.