How should I serialize code references in Perl? - perl

I wish to nstore a Perl hash which also contains a code reference. Following this perldoc I wrote something like this:
use strict;
use warnings;
local $Storable::Deparse = 1;
my %hash = (... CODE => ...);
nstore (\%hash, $file);
I get a warning saying Name "Storable::Deparse" used only once: possible typo at test4.pl line 15.. I guess I could specifically suppress this warning, but it makes me wonder if I'm doing anything wrong.
Note this question relates to this one. Different titles to distinguish between the two will be most welcomed.

You have neglected to load the Storable module, before setting one of its config values.
use strict;
use warnings;
use Storable qw(nstore);
local $Storable::Deparse = 1;
my %hash = (... CODE => ...);
nstore (\%hash, $file);

Code references cannot be simply serialized. File handles, database connections, and anything that has external resources cannot be simply serialized.
When serializing such items, you must describe them in such a way that they can be recreated. For instance, you might serialize a file handle as a path and an offset or a code reference as the name of function the reference was pointing to.
You can find the name of the subroutine a code reference points to with Sub::Identify:
#!/usr/bin/perl
use strict;
use warnings;
use Sub::Identify qw/sub_fullname/;
sub foo {}
my $r = \&foo;
print sub_fullname($r), "\n";
Of course, this means you cannot serialize anonymous references and the serialized data can only reliably be used by programs that implement the named functions in the same way.
If you find yourself needing to do this, you are probably better off using a class instead of a simple code reference.

You also need to set
$Storable::Eval = 1;
thus:
#! perl
use strict;
use warnings;
use Storable qw /nstore retrieve/;
local $Storable::Deparse = 1;
local $Storable::Eval = 1;
my %hash = ( CODE => sub {print "ahoj\n";});
nstore (\%hash, 'test');
my $retrieved = retrieve ( 'test');
$retrieved->{CODE}();

Related

Perl import into all my packages?

I tend to use Data::Dumper very often, and I end up having the following boilerplate at the top of every package in my .pl code.
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Deparse = 1;
$Data::Dumper::Purity = 1;
Is there a way to specify that "inside the current .pl file, I want these statements to automatically assumed."
eg I would have
package foo;
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Deparse = 1;
$Data::Dumper::Purity = 1;
my #localState = (1, 2, 3, 4, 5);
sub test {
print Dumper \#localState;
}
package main;
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Deparse = 1;
$Data::Dumper::Purity = 1;
foo->test;
this can quickly get way too much boilerplate repetition and harm maintainability.
Sadly I can't use a function with "eval" in it to call all this boilerplate since that boilerplate would be placed into the function, not global scope; Perl does not have Lisp macros that I know of to actually have non-function bound eval-like bahavior(I could be wrong, would be so cool if Perl had lisp macros).
Does anyone know if this behavior can be achieved without writing a parser to insert the statements in for me if it is the first package being declared inside file?
You can build your own toolbox module that turns on pragmas, loads modules and sets stuff, and just load that. The module Import::Into us great for that.
Here is a blog post that explains how to do it.
But note that the config for Data::Dumper that you are setting is actually not related to the package you're setting it in. Those are package variables in the Data::Dumper package, so they are valid all the time once set. You're essentially overwriting them with the same stuff again in your example.
In production code you should usually not put multiple packages in one file unless you have a good reason. But that doesn't change any of the advice above.

Perl - Can't call method "content_type" on an undefined value

So, I got a PERL script I am trying to run, it start like this:
use strict;
use a;
use CGI 'param';
use URI::Escape;
use HTML::FromText 'text2html';
use XML::Simple;
use LWP::UserAgent;
use Data::Dumper;
use URI::Escape;
use DBI;
use Tie::DBI;
use Digest::MD5 'md5_hex';
use MIME::Base64;
use Encode;
my $r = shift; $r->content_type("text/html; charset=utf-8"); my $tmp = a::tmp();
When it get's to the part where content_type() function is called, it fails with this error message:
Can't call method "content_type" on an undefined value at script.pl line 18.
Any ideas? I am kinda PERL newbie.
If $r is coming from #ARGV, it won't have a content_type method.
You could potentially bless $r into some package, but that's surely not what you're intending to do, here.
I'm guessing that you want to obtain a CGI parameter, probably a POSTed upload file? So you want $r to be a CGI object, not a parameter. You'd start with
my $r = CGI->new;
But, then, I refer you to the very fine manual for CGI, http://perldoc.perl.org/CGI.html or perldoc CGI from the shell.
(To expand a bit:)
In Perl, a $scalar var holds "any one thing." Things coming in from the command-line are generally strings (maybe numbers, on a good day); that's what shift would get at the top level. (The special variable #ARGV contains command-line parameters passed in to your program.)
"One thing" can also be a reference to an object. In Perl's Object Oriented model, the methods of a package ("class") are tied to that reference using bless. That's usually handled for you, though; the special subroutine (aka function, method) CGI::new will create a new CGI object with some state data (things like form fields' values), and bless it into the CGI package.
The -> notation going to a function call will only work if your variable contains a blessed reference. You can "ask" what kind of a reference you have in a variable using ref; you'll get the name of its package (aka class). ($foo = []; bless $foo => 'Some::Package'; print ref $foo; => Some::Package)
— But, again, for your specific case, check out some of the examples in the CGI module's manual :-)
Perldoc says:
If ARRAY is omitted, shifts the #_ array within the lexical scope of
subroutines and formats, and the #ARGV array outside a subroutine (...)
This is second case (#ARGV) which seems to empty. Try dumping #ARGV to check its contents.

In Perl, how can I access a scalar defined in another package?

I seem to be stuck trying to access a scalar which is defined in another package, and have narrowed down an example to a simple test case where I can reproduce the issue.
What I wish to be able to do it access a reference to a list which is in defined within the package 'Example', using the our mechanism, however, Dumper is showing that the variable is always undefined within example.pl:
Example.pm looks like the following:
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
package Example;
use Data::Dumper;
my $exported_array = [ 'one', 'two', 'three' ];
print Dumper $exported_array;
1;
And the code which uses this package looks like this:
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
use Data::Dumper;
use lib '.';
use Example;
{ package Example;
use Data::Dumper;
our $exported_array;
print Dumper $exported_array;
}
exit 0;
Upon running this code, the first Dumper runs and things look normal, after this, the second Dumper, example.pl runs and the reference is then undefined:
$VAR1 = [
'one',
'two',
'three'
];
$VAR1 = undef;
A my declaration does not create a package level variable and does not enter anything onto the symbol table for any namespace.
To do what you look like you are trying to do, you will have to change the declaration in the first file to
our $exported_array = [ ... ];
You can then access it in another file as
$Example::exported_array
Even if $exported_array weren't lexically scoped in the Example package, Example's $exported_array and main's $exported_array are two different things. The easiest way to change the example you've given is to 1. change my to our in the Example declaration and explicitly qualify the variable name.
our $exported_array;
...
print Dumper $Example::exported_array;
Otherwise, you need to make Example an Exporter. (Or just write an Example::import routine--but I' not going to cover that.)
package Example;
our $exported_array = ...;
our #EXPORT_OK = qw<$exported_array>;
use parent qw<Exporter>;
And in the script:
use Example qw<$exported_array>;
However, as you can actually export arrays (not just refs), I would make that:
our #exported_array = (...);
our #EXPORT_OK = qw<#exported_array>;
...
use Example qw<#exported_array>;
...
print Dumper( \#exported_array );
When you use the my operator, you are lexically scoping the variable name to either the scope you're in or to the file.
If you want something to be visible as a qualified package array, you need to use our like you do in the driver code. I believe you also need to declare a few special exporter variables in the .pm file, but on the plus side you won't need to declare our $exported_array; in the driver file.
Using Exporter is fine for smaller projects, but if you have lots of code handling data that is internal to a module, things can get ... messy. Object-orientation is a lot friendlier for this type of thing.
Why not construct a method to fetch this data? In fact, why not just use Moose?
In your Example.pm, just load Moose - this gives you a constructor and destructor for free, as well as a subroutine to fetch values and turns on strict, etc by default. Array references have to be declared a little differently, due to how Class:MOP (The engine under the antlers of Moose) initializes attributes - you have to wrap it in a code reference (aka sub {}). You would also use Data::Dumper in the script which calls the package, instead of the package itself.
Example.pm
package Example;
use Moose;
has 'exported_array' => (is => 'rw', default => sub { [ 'one', 'two', 'three' ] });
1;
Then call this from a script:
example.pl
#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;
my $example = Example->new;
my $imported_array_ref = $example->exported_array;
my #imported_array = #{$imported_array_ref};
foreach my $element(#imported_array) { say $element; }
say Dumper(\#imported_array);
I made the dereferencing really explicit in the example.pl script above... it can be much more terse by dereferencing it directly into the array:
#!/usr/bin/env perl
use Modern::Perl '2013';
use lib '.';
use Example;
use Data::Dumper;
my $example = Example->new;
my #imported_array = #{$example->exported_array};
foreach my $element(#imported_array) { say $element; }
say Dumper(\#imported_array);
I think a lot more Perl programmers would embrace Moose if there were more simple examples that show how to get simple things done.
The Official Moose Manual is excellent, but it was really written for those who are already familiar with OOP.

How can I share global values among different packages in Perl?

Is there a standard way to code a module to hold global application parameters to be included in every other package? For instance: use Config;?
A simple package that only contains our variables? What about readonly variables?
There's already a standard Config module, so choose a different name.
Say you have MyConfig.pm with the following contents:
package MyConfig;
our $Foo = "bar";
our %Baz = (quux => "potrzebie");
1;
Then other modules might use it as in
#! /usr/bin/perl
use warnings;
use strict;
use MyConfig;
print "Foo = $MyConfig::Foo\n";
print $MyConfig::Baz{quux}, "\n";
If you don't want to fully qualify the names, then use the standard Exporter module instead.
Add three lines to MyConfig.pm:
package MyConfig;
require Exporter;
our #ISA = qw/ Exporter /;
our #EXPORT = qw/ $Foo %Baz /;
our $Foo = "bar";
our %Baz = (quux => "potrzebie");
1;
Now the full package name is no longer necessary:
#! /usr/bin/perl
use warnings;
use strict;
use MyConfig;
print "Foo = $Foo\n";
print $Baz{quux}, "\n";
You could add a read-only scalar to MyConfig.pm with
our $READONLY;
*READONLY = \42;
This is documented in perlmod.
After adding it to #MyConfig::EXPORT, you might try
$READONLY = 3;
in a different module, but you'll get
Modification of a read-only value attempted at ./program line 12.
As an alternative, you could declare in MyConfig.pm constants using the constant module and then export those.
Don't use global variables for configuration and don't sotre configuration as code. I have an entire chapter in Mastering Perl about this.
Instead, make a configuration class that any other package can use to access the configuration data. It will be much easier in the long run to provide an interface to something you may want to change later than deal with the nuttiness you lock yourself into by scattering variables names you have to support for the rest of your life.
A config interface also gives you the benefit of composing new answers to configuration questions by combining the right bits of actual configuration data. You hide all of that behind a method and the higher levels don't have to see how it's implemented. For instance,
print "Hello!" unless $config->be_silent;
The be_silent answer can be triggered for multiple reasons the higher-level code doesn't need to know about. It could be from a user switch, that the program detected it is not interactive, and so on. It can also be flipped by options such as a debugging switch, which overrides all other preferences. No matter what you decide, that code line doesn't change because that statement only cares about the answer, not how you got the answer.

Why can't my Perl script see the our() variables I defined in another file?

I have a question relating to Perl and scoping. I have a common file with lots of various variables. I require the common file in my main script, but I cannot access the variables; they seem to be outside of its scope. I assumed that an our declaration would overcome that problem, but it doesn't seem to work.
Script 1: common.pl
#!/usr/bin/perl
our $var1 = "something";
our $var2 = "somethingelse";
Script 2: ftp.pl
#!/usr/bin/perl
use strict;
use warnings;
require('common.pl');
print $var1;
I get the error: Global symbol "$var1" requires explicit package name
There's no require statement in your second example, but it wouldn't work anyway. What our does is declare a lexically-scoped package variable. Since you have no package statement, it uses the default package main. So your first script sets up the variable $main::var1, but this will only be available within that file's scope.
A better way to provide common variables for other scripts is to use Exporter. You can define package symbols in one place and Exporter will take care of copying them to the requesting script or class's namespace when needed.
I would put the config in a module instead.
File: MyConfig.pm
package MyConfig;
require Exporter;
use strict;
our #ISA = qw(Exporter);
our #EXPORT = qw( getconfig );
my %confighash = (
thisone => 'one',
thatone => 2,
somthingelse => 'froboz',
);
sub getconfig {
return %confighash;
}
1;
Example usage:
#!/usr/bin/perl
use strict;
use warnings;
use MyConfig;
my %config = getconfig();
print $config{ somthingelse };
This should print froboz
It looks like you need a proper configuration file there. I'd go for a non-code configuration file that you can read when you need to setup things. There are modules on CPAN to handle just about any configuration format you can imagine.
If you want to do it the way you have it, get rid of our and declare them with use vars. Don't let the PBP police scare you off that. :) You only really need our to limit a scope of a package variable, and that's exactly the opposite of what you are trying to do.
our() does something a little different than you think. Its sole purpose is to work with strict in requiring you to declare package variables that you are going to use (unless they are fully-qualified or imported). Like strict, its effect is lexically-scoped. To use it to allow accessing a global $main:var1 from multiple files (which are separate scopes) as just $var1, you need to say our $var1 in each file.
Alternatively, you would change your required file to be a module with its own package that exports the variables to any package that uses it.
Try this. I am new at Perl but this is how I got it to work on a script I made
#!/usr/bin/perl
$var1 = "something";
$var2 = "somethingelse";
Script 2: ftp.pl
#!/usr/bin/perl
use strict;
use warnings;
our $var1;
our $var2;
require('common.pl');
print $var1;