I am trying to make a library of functions for my oscilloscope, but I can't seem to get other module files to play nice.
What I have is here, except the Oscope.pm file. If it's needed I can upload it too.
test.pl
# Includes
use 5.012;
use Oscope;
use Oscope::Acquire;
use warnings;
# From Oscope.pm
my $scope = Oscope->new('port', 'COM3');
# From Oscope::Acquire.pm
$scope->QueryAcquire();
Oscope/Acquire.pm
package Oscope::Acquire;
use Oscope;
use parent 'Oscope';
sub QueryAcquire
{
my ($self) = #_;
# Oscope.pm
my $message = $self->Send('ACQUIRE?');
return();
}
1;
Output
Can't locate object method "QueryAcquire" via package "Oscope" at C:\Documents and Settings\ericfoss\My Documents\Slick\Perl\tests\Test.pl line 11.
Oscope->new('port', 'COM3')
should be
Oscope::Acquire->new('port', 'COM3')
I'm not going to say this is a good idea. You apparently want Oscope::Aquire to monkey patch Oscope. That is possible, but I would recommend having Oscope::Acquire export a function that takes an Oscope parameter (more information on exporting):
Oscope/Acquire.pm
package Oscope::Acquire;
require Exporter 'import';
#EXPORT_OK = qw{QueryAcquire};
use Oscope;
sub QueryAcquire
{
my ($oscope) = #_;
my $message = $oscope->Send('ACQUIRE?');
return $message;
}
1;
Which you would use:
use Oscope;
use Oscope::Acquire 'QueryAcquire';
my $oscope = Oscope->new();
print QueryAquire($oscope);
However, if you really want the $oscope->QueryAcquire() syntax, and you don't want to put it in Oscope itself, you can monkey patch the module. Perl documentation refers to this as modifying the module's symbol table through a typeglob and it's apparently deprecated ("The results of creating new symbol table entries directly ... are undefined and subject to change between releases of perl"):
Oscope/Acquire.pm
package Oscope::Acquire;
use Oscope;
*Oscope::QueryAcquire = sub {
my ($self) = #_;
my $message = $self->Send('ACQUIRE?');
return $message;
}
1;
I should have read my own link more closely. It appears that the approved way of doing this is to simply add methods to the Oscope package inside the Oscope/Acquire.pm file ("You can define a subroutine outside its package by explicitly qualifying the name of the subroutine"):
package Oscope::Acquire;
use Oscope;
...
sub Oscope::QueryAcquire {
my ($self) = #_;
my $message = $self->Send('ACQUIRE?');
return $message;
}
1;
That is, there's no need to the typeglob.
Where are your lib packages, place your code there. You could also use
use lib "path"
Another explanation can be found here which answers require over lib.
Your area message says it all in that it can't find the function.
As the code stands you could just say $scope->Oscope::Acquire::QueryAcquire();, but to get the desired effect, you need to make it part of the package.
package Oscope;
sub QueryAcquire
{
# Code here
}
1;
Related
is it possible to import (use) a perl module within a different namespace?
Let's say I have a Module A (XS Module with no methods Exported #EXPORT is empty) and I have no way of changing the module.
This Module has a Method A::open
currently I can use that Module in my main program (package main) by calling A::open I would like to have that module inside my package main so that I can directly call open
I tried to manually push every key of %A:: into %main:: however that did not work as expected.
The only way that I know to achieve what I want is by using package A; inside my main program, effectively changing the package of my program from main to A.
Im not satisfied with this. I would really like to keep my program inside package main.
Is there any way to achieve this and still keep my program in package main?
Offtopic: Yes I know usually you would not want to import everything into your namespace but this module is used by us extensively and we don't want to type A:: (well the actual module name is way longer which isn't making the situation better)in front of hundreds or thousands of calls
This is one of those "impossible" situations, where the clear solution -- to rework that module -- is off limits.
But, you can alias that package's subs names, from its symbol table, to the same names in main. Worse than being rude, this comes with a glitch: it catches all names that that package itself imported in any way. However, since this package is a fixed quantity it stands to reason that you can establish that list (and even hard-code it). It is just this one time, right?
main
use warnings;
use strict;
use feature 'say';
use OffLimits;
GET_SUBS: {
# The list of names to be excluded
my $re_exclude = qr/^(?:BEGIN|import)$/; # ...
my #subs = grep { !/$re_exclude/ } sort keys %OffLimits::;
no strict 'refs';
for my $sub_name (#subs) {
*{ $sub_name } = \&{ 'OffLimits::' . $sub_name };
}
};
my $name = name('name() called from ' . __PACKAGE__);
my $id = id('id() called from ' . __PACKAGE__);
say "name() returned: $name";
say "id() returned: $id";
with OffLimits.pm
package OffLimits;
use warnings;
use strict;
sub name { return "In " . __PACKAGE__ . ": #_" }
sub id { return "In " . __PACKAGE__ . ": #_" }
1;
It prints
name() returned: In OffLimits: name() called from main
id() returned: In OffLimits: id() called from main
You may need that code in a BEGIN block, depending on other details.
Another option is of course to hard-code the subs to be "exported" (in #subs). Given that the module seems to be immutable in practice this option is reasonable and more reliable.
This can also be wrapped in a module, so that you have the normal, selective, importing.
WrapOffLimits.pm
package WrapOffLimits;
use warnings;
use strict;
use OffLimits;
use Exporter qw(import);
our #sub_names;
our #EXPORT_OK = #sub_names;
our %EXPORT_TAGS = (all => \#sub_names);
BEGIN {
# Or supply a hard-coded list of all module's subs in #sub_names
my $re_exclude = qr/^(?:BEGIN|import)$/; # ...
#sub_names = grep { !/$re_exclude/ } sort keys %OffLimits::;
no strict 'refs';
for my $sub_name (#sub_names) {
*{ $sub_name } = \&{ 'OffLimits::' . $sub_name };
}
};
1;
and now in the caller you can import either only some subs
use WrapOffLimits qw(name);
or all
use WrapOffLimits qw(:all);
with otherwise the same main as above for a test.
The module name is hard-coded, which should be OK as this is meant only for that module.
The following is added mostly for completeness.
One can pass the module name to the wrapper by writing one's own import sub, which is what gets used then. The import list can be passed as well, at the expense of an awkward interface of the use statement.
It goes along the lines of
package WrapModule;
use warnings;
use strict;
use OffLimits;
use Exporter qw(); # will need our own import
our ($mod_name, #sub_names);
our #EXPORT_OK = #sub_names;
our %EXPORT_TAGS = (all => \#sub_names);
sub import {
my $mod_name = splice #_, 1, 1; # remove mod name from #_ for goto
my $re_exclude = qr/^(?:BEGIN|import)$/; # etc
no strict 'refs';
#sub_names = grep { !/$re_exclude/ } sort keys %{ $mod_name . '::'};
for my $sub_name (#sub_names) {
*{ $sub_name } = \&{ $mod_name . '::' . $sub_name };
}
push #EXPORT_OK, #sub_names;
goto &Exporter::import;
}
1;
what can be used as
use WrapModule qw(OffLimits name id); # or (OffLimits :all)
or, with the list broken-up so to remind the user of the unusual interface
use WrapModule 'OffLimits', qw(name id);
When used with the main above this prints the same output.
The use statement ends up using the import sub defined in the module, which exports symbols by writing to the caller's symbol table. (If no import sub is written then the Exporter's import method is nicely used, which is how this is normally done.)
This way we are able to unpack the arguments and have the module name supplied at use invocation. With the import list supplied as well now we have to push manually to #EXPORT_OK since this can't be in the BEGIN phase. In the end the sub is replaced by Exporter::import via the (good form of) goto, to complete the job.
You can forcibly "import" a function into main using glob assignment to alias the subroutine (and you want to do it in BEGIN so it happens at compile time, before calls to that subroutine are parsed later in the file):
use strict;
use warnings;
use Other::Module;
BEGIN { *open = \&Other::Module::open }
However, another problem you might have here is that open is a builtin function, which may cause some problems. You can add use subs 'open'; to indicate that you want to override the built-in function in this case, since you aren't using an actual import function to do so.
Here is what I now came up with. Yes this is hacky and yes I also feel like I opened pandoras box with this. However at least a small dummy program ran perfectly fine.
I renamed the module in my code again. In my original post I used the example A::open actually this module does not contain any method/variable reserved by the perl core. This is why I blindly import everything here.
BEGIN {
# using the caller to determine the parent. Usually this is main but maybe we want it somewhere else in some cases
my ($parent_package) = caller;
package A;
foreach (keys(%A::)) {
if (defined $$_) {
eval '*'.$parent_package.'::'.$_.' = \$A::'.$_;
}
elsif (%$_) {
eval '*'.$parent_package.'::'.$_.' = \%A::'.$_;
}
elsif (#$_) {
eval '*'.$parent_package.'::'.$_.' = \#A::'.$_;
}
else {
eval '*'.$parent_package.'::'.$_.' = \&A::'.$_;
}
}
}
I am new to this site, so bear with me, If this question has already been answered somewhere else already. I am trying to call a subroutine "bar" from a module "codons1.pm" , and I encounter the error:
Can't locate object method "bar" via package "codons1.pm" (perhaps you forgot to load "codons1.pm"?). The main script looks like:
use strict;
use warnings;
my $i = 1;
my $pack = "codons$i\.pm";
require $pack;
(my %temp) = $pack->bar();
print keys %INC ;
Thanks to (Perl objects error: Can't locate object method via package) , I was able to verify using %INC, that the module is loaded.
The module looks like:
package codons1;
sub bar{ #some code;
return (%some_hash);}
1;
I am using $i so that I can load multiple similar modules via a loop. Any suggestions is welcome and thanks a lot, in advance.
Your package is codons1, and you're trying to call codons1.pm->bar. Either of the following will work correctly:
my $pack = "codons$i";
require "$pack.pm";
$pack->bar();
or
my $pack = "codons$i";
eval "require $pack";
$pack->bar();
A better way to do what you're trying to achieve
#!/usr/bin/perl
use strict;
use warnings;
package codons1;
sub new {
my $class = shift;
return bless {}, $class;
}
sub bar {
my %some_hash = (temperature=>"35");
return %some_hash;
}
1;
package main;
my $object = codons1->new(); #creates the object of codons1
my %temp = $object->bar(); #call the bar method from codons1's object
print keys %temp;
Demo
You need to learn basic object oriented programming in Perl. Start with perlootut, and then perlobj. Read the Object Oriented Perl chapter from freely available Beginning Perl book.
It's a long title, but I'm afraid I can't take a single word out without losing the true meaning of the question. I'll give a quick description of what I'm trying to achieve first, then a long rambling on why I want it done this way. Skip the rambling if you intend to directly answer abiding with the question title :-)
Quick description
Assuming the existence of a lexicalize builtin that does just what I want, here goes:
package Whatever;
{
lexicalize $Other::Package::var;
local $var = 42;
Other::Package->do_stuff; # depends on that variable internally
}
Whys and whynots
For a bit of context, I'm whitebox-testing a third-party module.
I want the variable localized because I want it changed for a limited time only, before the tests move on to something else. local is the best way I found to do this without depending on knowing the module's choice for an initial value.
I want a lexical binding for two main reasons:
I don't want to pollute the test file's higher-level namespace.
I want something shorter than the fully-qualified name. It's not in the sample code for brevity, but I use the identifier a lot more than what's shown, with calculations and updates relative to its previous value.
I couldn't decently use our because it won't grab a variable from another package: “No package name allowed for variable $Other::Package::var in "our".” Cheating to temporarily enter Other::Package's scope doesn't cut it: if I use a block ({ package Other::Package; our $var }) then the binding doesn't last long enough to be useful; and if I don't (package Other::Package; our #var; package main) then I need to know and copy the previous package's name, which prevents moving that piece of code around too much.
While doing my homework before asking a previous form of this question, I discovered Lexical::Var, which seemed like it would be exactly what I needed. Alas: “Can't localize through a reference.”
I've also tried my best on my gut feeling of my *var-based forms, but kept bumping into syntax errors. I've learned more than I cared to about scoping and binding today :-)
I can't think of a reason why what I want shouldn't be possible, but I can't find the right incantation. Am I asking for an unfortunate unimplemented edge case?
If I get you right, all you need is our. Forgive me if I dont.
Here's working example:
#!/usr/bin/env perl
use strict;
use warnings;
package Some;
our $var = 42;
sub do_stuff { return $var }
package main;
{
local $Some::var = 43;
print "Localized: " . Some->do_stuff() . "\n";
};
print "Normal: " . Some->do_stuff() . "\n";
But if you try to localize private (my) variable of some package, you probably doing something wrong.
there are several ways to do this:
given:
{package Test::Pkg;
our $var = 'init';
sub method {print "Test::Pkg::var = $var\n"}
}
alias a package variable from the current package to the target package.
{
package main;
our $var;
Test::Pkg->method; # Test::Pkg::var = init
local *var = \local $Test::Pkg::var;
# alias $var to a localized $Test::Pkg::var
$var = 'new value';
Test::Pkg->method; # Test::Pkg::var = new value
}
Test::Pkg->method; # Test::Pkg::var = init
localize through a glob reference:
{
package main;
my $var = \*Test::Pkg::var; # globref to target the local
Test::Pkg->method; # Test::Pkg::var = init
local *$var = \'new value'; # fills the scalar slot of the glob
Test::Pkg->method; # Test::Pkg::var = new value
}
Test::Pkg->method; # Test::Pkg::var = init
bind a the lexical in the target package, and let it spill into the current package:
{
package Test::Pkg; # in the target package
our $var; # create the lexical name $var for $Test::Pkg::var
package main; # enter main package, lexical still in scope
Test::Pkg->method; # Test::Pkg::var = init
local $var = 'new value';
Test::Pkg->method; # Test::Pkg::var = new value
}
Test::Pkg->method; # Test::Pkg::var = init
the last example uses a slightly awkward double package declaration to create a lexical in one package and get it into another. This trick is useful with local in other scenarios:
no strict 'refs';
local ${'Some::Pkg::'.$name} = 'something';
use strict 'refs';
I am not quite sure if I understand you correctly. Does this help?
#!/usr/bin/env perl
{
package This;
use warnings; use strict;
our $var = 42;
sub do_stuff {
print "$var\n";
}
}
{
package That;
use warnings; use strict;
use Lexical::Alias;
local $This::var;
alias $This::var, my $var;
$var = 24;
print "$var\n";
This->do_stuff;
}
package main;
use warnings; use strict;
This->do_stuff;
package Other::Package;
$var = 23;
sub say_var {
my $label = shift;
print "$label: $Other::Package::var\n";
}
package Whatever;
Other::Package::say_var("before");
{
local $Other::Package::var = 42;
local *var = \$Other::Package::var;
Other::Package::say_var("during");
print "\$Whatever::var is $var inside the block\n";
}
Other::Package::say_var("after");
print "\$Whatever::var is ",
defined($var) ? "" : "un", "defined outside the block\n";
Output:
before: 23
during: 42
$Whatever::var is 42 inside the block
after: 23
$Whatever::var is undefined outside the block
local $Other::Package::var makes the original value temporarily 42 for the duration of the block, and local *var = \$Other::Package::var makes $var in the current package an alias for $Other::Package::var temporarily for the duration of the block.
Naturally some of this isn't strict-compliant, but I avoided using our because our obfuscates the issue if both packages are in the same file (as they might be if you copy-pasted this sample) — the our declaration can leak out of the package it's used in, into a following package in the same file :)
Let's say I have a perl module file and I want to include and use it dynamically at runtime. Said module includes a class that I need to instantiate without knowing its name until runtime.
For example,
#inside module.pm
package module;
sub new {
#setup object
}
#inside main.pl
#get module.pm as argument
my $module_var = #load reference to module using text argument?
my $module_instance = $module_var->new();
This can be done without eval as follows:
my $module_name = 'Some::Module';
(my $require_name = $module_name . ".pm") =~ s{::}{/}g;
require $require_name;
my $obj = $module_name->new();
If you need to do this many times, just wrap up that code in a subroutine:
sub load_module {
for (#_) {
(my $file = "$_.pm") =~ s{::}{/}g;
require $file;
}
}
load_module 'Some::Module', 'Another::Module';
my $module_var = 'module';
eval "use $module_var; 1" or die $#;
my $module_instance = $module_var->new();
Note that the eval is a possible security hole. If $module_var contains code, it will get executed. One way around this is to use Class::MOP. Replace the eval line with:
use Class::MOP;
Class::MOP::load_class($module_var);
If you don't want to require Class::MOP, you could copy the _is_valid_class_name function from it into your code, and just make sure that $module_var contains a valid class before you eval it. (Note that if you're using Moose, you're already using Class::MOP behind-the-scenes.)
You can do this with eval.
my $module = "Foo";
eval "use $module;1" or die($#); # Couldn't load module
How could I access the symbol table for the current package an object was instantiated in? For example, I have something like this:
my $object = MyModule->new;
# this looks in the current package, to see if there's a function named run_me
# I'd like to know how to do this without passing a sub reference
$object->do_your_job;
If in the implementation of do_your_job I use __PACKAGE__, it will search in the MyModule package. How could I make it look in the right package?
EDIT:I'll try to make this clearer. Suppose I have the following code:
package MyMod;
sub new {
return bless {},$_[0]
}
sub do_your_job {
my $self = shift;
# of course find_package_of is fictional here
# just for this example's sake, $pkg should be main
my $pkg = find_package_of($self);
if(defined &{ $pkg . '::run_me' }) {
# the function exists, call it.
}
}
package main;
sub run_me {
print "x should run me.\n";
}
my $x = MyMod->new;
# this should find the run_me sub in the current package and invoke it.
$x->do_your_job;
Now, $x should somehow notice that main is the current package, and search it's symbol table. I tried using Scalar::Util's blessed , but it still gave me MyModule instead of main. Hopefully, this is a bit clearer now.
You just want caller
caller tells you the package from which it was called. (Here I added some standard perl.)
use Symbol qw<qualify_to_ref>;
#...
my $pkg = caller;
my $symb = qualify_to_ref( 'run_me', $pkg );
my $run_me = *{$symb}{CODE};
$run_me->() if defined $run_me;
To look it up and see if it's defined and then look it up to call it would duplicate it as standard perl doesn't do Common Subexpression Elimination, so you might as well 1) retrieve it, and 2) check definedness of the slot, and 3) run it if it is defined.
Now if you create an object in one package and use it in another, that's not going to be too much help. You would probably need to add an additional field like 'owning_package' in the constructor.
package MyMod;
#...
sub new {
#...
$self->{owning_package} = caller || 'main';
#...
}
Now $x->{owning_package} will contain 'main'.
See perldoc -f caller:
#!/usr/bin/perl
package A;
use strict; use warnings;
sub do_your_job {
my ($self) = #_;
my ($pkg) = caller;
if ( my $sub = $pkg->can('run_me') ) {
$sub->();
}
}
package B;
use strict; use warnings;
sub test {
A->do_your_job;
}
sub run_me {
print "No, you can't!\n";
}
package main;
use strict; use warnings;
B->test;
Output:
C:\Temp> h
No, you can't!