There are two files, pm and pl under one file. If you run the pl file, the pm package call is unsuccessful - linux

File Directory:
/home/wh/perlstudy/perl2/Person/Student.pm
/home/wh/perlstudy/perl2/Person/person.pl
Student.pm
package Student;
use strict;
use warnings FATAL => 'all';
# use utf8;
# binmode(STDIN,"encoding(gbk)");
sub new
{
my $class = shift;
my $self = {
_name => shift, _rank => shift, };
# Print all the values just for clarification.
print "获取学生名字 $self->{_name}\n";
print "获取学生排名 $self->{_rank}\n";
bless $self, $class;
return $self;
}
sub studentRank {
my ( $self, $name ) = #_;
$self->{_name} = $name if defined($name);
return $self->{_name};
}
sub studentName {
my( $self ) = #_;
return $self->{_name};
}
1;
person.pl
#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
# use utf8;
# binmode(STDOUT,"encoding(gbk)");
BEGIN(push #INC,"/home/wh/perlstudy/perl2/Person/");
use Student;
my$object = Student->new( "Ana", "9th");
# name which is set using constructor.
my$name = $object->studentName();
print "Name set using constructor is : $name\n";
# name set using helper function.
$object->studentRank( "Anastasia" );
# getting name set by helper function.
$name = $object->studentName();
print "名字 set using helper is : $name\n";
I get:
Prototype after '#' for BEGIN : push #INC,"/home/wh/perlstudy/perl2/Person/" at perlson.pl line 6.
Want to solve the use of perl modules other than #INC.

BEGIN is a code block, so you need curly braces:
#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
# use utf8;
# binmode(STDOUT,"encoding(gbk)");
BEGIN {
push #INC, "/home/wh/perlstudy/perl2/Person/";
}
# rest of person.pl goes here
Or you use the -I flag when you call Perl:
perl -I/home/wh/perlstudy/perl2/Person/ person.pl
This has the advantage that you don't have to hard-code the path, but you'll have to re-type it each time. (Or make an alias or shell script for it.)
Or use lib:
use lib "/home/wh/perlstudy/perl2/Person/";
Finally you could install your Perl module in a place where Perl looks for modules by default, but during development you'll have to do that each time you make changes to Student.pm.

Related

How to "use" a module at run time

I am in the process of developing a module that will call a Perl modules on specific conditions.
And the logic will be this:
$var = "db_tk";
if ( $var =~ /db/ ) {
use dbi;
}
if ( $var =~ /tk/ ) {
use tk;
}
I am not able to run them at run time using require.
use Module;
is equivalent to
BEGIN {
require Module;
import Module;
}
so you want
require Module;
import Module;
Except importing from a module at run-time makes no sense. So you either want
# Conditionally load modules at runtime.
# Gotta use fully-qualified names to call provided functions.
my $var = "db_tk";
require DBI if $var =~ /db/;
require Tk if $var =~ /tk/;
or
# Conditionally load modules at compile-time.
BEGIN {
my $var = "db_tk";
if ($var =~ /db/) { require DBI; import DBI; }
if ($var =~ /tk/) { require Tk; import Tk; }
}
The if module can be used to simplify the latter:
# Conditionally load modules at compile-time.
my $var;
BEGIN {
$var = "db_tk";
}
use if $var =~ /db/, 'DBI';
use if $var =~ /tk/, 'Tk';
"I am not able to run them on runtime using "require"" Yes, you are. Anywhere that use works, require will also work: use calls require
Assuming that you meant to use the standard CPAN modules DBI and Tk, and not dbi and tk, then you need this
if ( $var =~ /db/ ) {
use DBI;
}
if ( $var =~ /tk/ ) {
use Tk;
}
Or, as long as you have previously defined $var in a BEGIN block, you can use the if pragma
use if $var =~ /db/, DBI;
use if $var =~ /tk/, Tk;

perl Can't locate object method query_form via package LWP::UserAgent

I'm creating a script with thread so I had to rebuild perl (perl5.20) with threads support.
Since I have rebuild perl, I have an error :
Can't locate object method "query_form" via package "LWP::UserAgent"
I've tried to re-install LWP::UserAgent, LWP::Simple, URI, but they are up-to-date(according to cpan).
The faulty code :
#!/usr/bin/env perl
package get_xml;
use strict;
use warnings;
use Curses;
use LWP::Simple;
use LWP::UserAgent;
use MIME::Base64;
use URI;
use URI::http;
use HTTP::Request::Common;
use parse_xml;
# ...
sub write_conv_thread{
my ($window, $rows, $username, $url, $ua) = #_;
while(1){
$$url->query_form( # line 43
"heartbeat" => '0',
"conv" => 0,
"username" => "$username",
"active" => 0
);
my $xml = $$ua->get($url);
my #conv = get_conv($xml);
print_all_lines($window, $rows, #conv);
$$window->refresh();
sleep(5);
}
}
1;
And the exact error message : Thread 1 terminated abnormally: Can't locate object method "query_form" via package "LWP::UserAgent" at get_xml.pm line 43.
Code that call the function :
#!/usr/bin/env perl
use strict;
use warnings;
use Curses;
use LWP::Simple;
use LWP::UserAgent;
use MIME::Base64;
use URI;
use threads;
use get_xml;
use post_xml;
# ... initialization of Curses windows ...
# $chat_win is a curse, $row is a number
my $server_endpoint = "...";
my $ua = LWP::UserAgent->new;
my $url = URI->new( "$server_endpoint/index.php" );
my $thread = threads->new(\&get_xml::write_conv_thread, \$chat_win, $row-4,"...", \$url, \$ua);
$thread->detach();
What can I do to make perl find the object method ?
Thank you for your answer.
The (reference to the) UA got assigned to $url instead of $ua.
My best guess as to the cause (since you didn't provide the actual code that gives the error): $window, $rows or $username wasn't provided, causing the (reference to the) UA to be the fourth argument.

Change thread priority ERROR_INVALID_HANDLE

I'm trying to change a thread priority within my script, without success, here are the details.
$thr = threads->new(\&someFunction,
$shared variable 1,
$shared variable 2,
);
I've tried using threads::State;
$thr->priority(2);
Without success
So, I thought the Win32::API must work
my $functionGetLastError= Win32::API->new('Kernel32',
'GetLastError',
'',
'N'
);
my $functionSetThreadPriority= Win32::API->new('Kernel32',
'SetThreadPriority',
'II', # I've tried 'PI' and 'II' as well
'N'
);
my $h = $thr->_handle();
my $success = $functionSetThreadPriority->Call( $h, 2 );
warn "Return Error #".$functionGetLastError->Call() if !$success;
Again, without success: (, but now I have a clue, the script return error number
last Error 6
From MSDN site, System Error Codes (0-499), it seems that the error is
ERROR_INVALID_HANDLE
What am I doing wrong?
$thread->_handle weirdly returns a HANDLE*, while SetThreadPriority expects a HANDLE. You need to dereference the pointer, which you can do as follows:
use constant THREAD_PRIORITY_HIGHEST => 2;
sub SetThreadPriority {
my ($thread, $priority) = #_;
# $thread->_handle() returns a HANDLE*.
my $handle_ptr = $thread->_handle();
my $packed_handle = unpack('P'.HANDLE_SIZE, pack(PTR_FORMAT, $handle_ptr));
my $handle = unpack(HANDLE_FORMAT, $packed_handle);
state $SetThreadPriority = (
Win32::API->new('Kernel32', 'SetThreadPriority', 'Ni', 'i')
or die("Loading SetThreadPriority: $^E\n")
);
return $SetThreadPriority->Call($handle, $priority);
}
Here's the full test program:
use strict;
use warnings;
use feature qw( say state );
use threads;
use threads::shared;
use Carp qw( croak );
use Config qw( %Config );
use Win32::API qw( );
sub uint_format {
$_[0] == 4 ? 'L'
: $_[0] == 8 ? 'Q'
: croak("Unsupported")
}
use constant PTR_SIZE => $Config{ptrsize};
use constant PTR_FORMAT => uint_format(PTR_SIZE);
use constant HANDLE_SIZE => PTR_SIZE;
use constant HANDLE_FORMAT => PTR_FORMAT;
use constant THREAD_PRIORITY_HIGHEST => 2;
sub SetThreadPriority {
my ($thread, $priority) = #_;
# $thread->_handle() returns a HANDLE*.
my $handle_ptr = $thread->_handle();
my $packed_handle = unpack('P'.HANDLE_SIZE, pack(PTR_FORMAT, $handle_ptr));
my $handle = unpack(HANDLE_FORMAT, $packed_handle);
state $SetThreadPriority = (
Win32::API->new('Kernel32', 'SetThreadPriority', 'Ni', 'i')
or die("Loading SetThreadPriority: $^E\n")
);
return $SetThreadPriority->Call($handle, $priority);
}
{
my $done :shared = 0;
my $thread = async {
{ lock($done); cond_wait($done) while !$done; }
};
my $rv = SetThreadPriority($thread, THREAD_PRIORITY_HIGHEST);
say $rv ? "Success" : "Error: $^E";
{ lock($done); $done = 1; cond_broadcast($done); }
$thread->join();
}
Notice that you can use $^E to access GetLastError.
SetThreadPriority($handle, THREAD_PRIORITY_HIGHEST)
or die("SetThreadPriority: $^E\n";
ERROR_INVALID_HANDLE
Which suggests that what _handle returns is not something Win32::API understands. I suspect "P" wants a string buffer not an integer-casted pointer. "I" may be the wrong thing because it's the wrong size on 64-bit, I would try "N" myself.
Also, for future readers running into this issue on Unix: try my POSIX::RT::Scheduler module.

Perl Error: thread failed to start: Invalid value for shared scalar

I get the following error when trying to run my test code:
thread failed to start: Invalid value for shared scalar at ./threaded_test.pl line 47.
Line 47 is:
%hoh = hoh(#new_array);
My observations:
If I remove line 47 and other lines referencing %hoh, then the script runs without errors
I can create a new hash %new_hash = (itchy => "Scratchy"); without errors, but when I try to "return" a hash from another sub (line 47), it results in the error above.
Unfortunately, I cannot use a in/out Queue because the version of Thread::Queue that I use is too old (and installed on a system I have no control over) and doesn't support hash and hash-ref types to be returned via a Queue (according to this). Apparently, my version only support strings to be returned via queues.
Is there a way to successfully do this: $hash{$string}{"jc"} = \%hoh;
#!/usr/bin/perl
use strict;
use warnings;
use threads;
use Thread::Queue;
use constant NUM_WORKERS => 10;
my #out_array : shared = ();
main();
sub main
{
my #results = test1();
foreach my $item (#results) {
print "item: $item\n";
}
}
sub test1
{
my $my_queue = Thread::Queue->new();
foreach (1..NUM_WORKERS) {
async {
while (my $job = $my_queue->dequeue()) {
test2($job);
}
};
}
my #sentiments = ("Axe Murderer", "Mauler", "Babyface", "Dragon");
$my_queue->enqueue(#sentiments);
$my_queue->enqueue(undef) for 1..NUM_WORKERS;
$_->join() for threads->list();
my #return_array = #out_array;
return #return_array;
}
sub test2
{
my $string = $_[0];
my %hash : shared;
my #new_array : shared;
my %new_hash : shared;
my %hoh : shared;
#new_array = ("tom", "jerry");
%new_hash = (itchy => "Scratchy");
%hoh = hoh(#new_array);
my %anon : shared;
$hash{$string} = \%anon;
$hash{$string}{"Grenade"} = \#new_array;
$hash{$string}{"Pipe bomb"} = \%new_hash;
$hash{$string}{"jc"} = \%hoh;
push #out_array, \%hash;
return;
}
sub hoh
{
my %hoh;
foreach my $item (#_) {
$hoh{"jeepers"}{"creepers"} = $item;
}
return %hoh;
}
The problem is that your trying to store a reference to something that isn't shared in a shared variable. You need to use share as previously mentioned, or you need to serialise the data structure.
#!/perl/bin/perl
use strict;
use threads;
use threads::shared;
my %hm_n2g:shared = ();
my $row = &share([]);
$hm_n2g{"aa"}=$row;
$row->[0]=1;
$row->[1]=2;
my #arr = #{$hm_n2g{"aa"}};
print #arr[0]." ".#arr[1]."\n";
#If you want to lock the hash in a thread-subroutine
{
lock(%hm_n2g)
}

App doesn't exit from MainLoop after dialog

I have this problem.
I have solved, it but does it correct for big application (in future:)?
#!/usr/bin/perl
use strict;
use warnings;
use lib '.';
use MyApp;
use LoginFrame;
my $f = LoginFrame->new;
$f->ShowModal;
if(int($f->GetReturnCode)) {
print '['.$f->GetReturnCode."]\n";
$f->Destroy;
my $app = new MyApp;
$app->MainLoop;
} else {
print "PLEASE NOT THIS CRAP AGAIN!!!\n";
print '['.$f->GetReturnCode."]\n";
}
"The ( main ) loop will not terminate until there are top level windows."
wxPerl tutorial http://wxperl.sourceforge.net/tutorial/tutorial2.html#id4690123

Resources