I am trying to get started using Device::BlinkyTape::SimulationPort, but when executing the simple example script below, I get the error:
'x' outside of string in unpack at /home/pi/perl5/lib/perl5/Device/BlinkyTape/SimulationPort.pm line 70.
Any idea how I can get it to work?
#!/usr/bin/env perl
use lib '../lib';
use Device::BlinkyTape::WS2811; # BlinkyTape uses WS2811
my $bb = Device::BlinkyTape::WS2811->new(simulate => 1);
$bb->all_on();
sleep 2;
$bb->all_off();
sleep 2;
$bb->send_pixel(255,255,255);
$bb->show();
sleep 2;
$bb->send_pixel(255,0,0);
$bb->show();
sleep 2;
$bb->send_pixel(240,0,0);
$bb->show();
sleep 2;
# Go crazy
for (my $b=0; $b<=1000; $b++) {
for (my $a=0; $a<=59; $a++) {
$bb->send_pixel(int(rand(254)),int(rand(254)),int(rand(254)));
}
$bb->show(); # shows the sent pixel row
}
sleep 2;
It looks like a bug in the module.
The Device::BlinkyTape POD BUGS section states:
The device is not yet available so the module has been implemented by
inspecting partly undocumented and unfinished code in other languages.
The module was last updated 8 years ago (2013); perhaps it is just a work-in-progress.
The module has no meaningful tests, as can be seen from the CPAN Testers results and the lack of Coverage results. Thus, there is no public evidence that the module works.
The code posted in the Question is from the simulate.pl example. Here is a minimal example which reproduces the problem:
use diagnostics;
use Device::BlinkyTape::WS2811;
my $bb = Device::BlinkyTape::WS2811->new(simulate => 1);
$bb->all_on();
I added diagnostics to get more information about the error. Here is my output:
simulation on. at lib/perl5/Device/BlinkyTape.pm line 114.
'x' outside of string in unpack at
lib/perl5/Device/BlinkyTape/SimulationPort.pm line 70 (#1)
(F) You had a pack template that specified a relative position after
the end of the string being unpacked. See "pack" in perlfunc.
Uncaught exception from user code:
'x' outside of string in unpack at lib/perl5/Device/BlinkyTape/SimulationPort.pm line 70.
Device::BlinkyTape::SimulationPort::write(Device::BlinkyTape::SimulationPort=HASH(0x348b050), "\x{fe}") called at lib/perl5/Device/BlinkyTape/WS2811.pm line 34
Device::BlinkyTape::WS2811::send_pixel(Device::BlinkyTape::WS2811=HASH(0x3481fe0), 255, 255, 255) called at lib/perl5/Device/BlinkyTape.pm line 137
Device::BlinkyTape::all_on(Device::BlinkyTape::WS2811=HASH(0x3481fe0)) called at line 4
Here is line 70:
my $b = unpack("x2 C1", $color);
The next step is to report this issue and try to get an update on the status of the module.
Related
I am confused by one perl question, anyone has some idea?
I use one hash structure to store the keys and values like:
$hash{1} - > a;
$hash{2} - > b;
$hash{3} - > c;
$hash{4} - > d;
....
more than 1000 lines. I give a name like %hash
and then, I plan to have one loop statement to search for all keys to see whether it will match with the value from the file.
for example, below is the file content:
first line 1
second line 2
nothing
another line 3
my logic is:
while(read line){
while (($key, $value) = each (%hash))
{
if ($line =~/$key/i){
print "found";
}
}
so my expectation is :
first line 1 - > return found
second line 2 - > return found
nothing
another line 3 - > return found
....
However, during my testing, only first line and second line return found, for 'another line3', the
program does not return 'found'
Note: the hash has more than 1000 records.
So I try to debug it and add some count inside and find out for those found case, the loop has run like 600 or 700 times, but for the 'another line3' case, it only runs around 300 times and just exit the loop and did not return found.
any idea why it happens like that?
and I have done one more testing is if my hash structure is small, like only 10 keys, the logic works.
and I try to use foreach, and It looks like foreach does not have this kind of issue.
The pseudo code you give should work fine, but there might be a subtle problem.
If after you found your key and print it out you end the while loop, the next time each is called, it will continue where you left. Put it in other words "each" is an iterator that stores its state in the hash it iterates over.
In http://blogs.perl.org/users/rurban/2014/04/do-not-use-each.html the author explains this in more detail. His conclusion:
So each should be treated as in php: Avoid it like a plague. Only use it in optimized cases where you know what you are doing.
The problem is not very well articulated by OP, provided sample data are poor for demonstration purpose.
Following sample code is an attempt based on provided problem description by OP.
Recreate filter hash from DATA block, compose $re_filter consisting of filter hash keys, walk through a file given as an argument on command line to filter out lines matching $re_filter.
use strict;
use warnings;
my $data = do { local $/; <DATA> };
my %hash = split ' ', $data;
my $re_filter = join('|',keys %hash);
/$re_filter/ && print for <>;
__DATA__
1 a
2 b
3 c
4 d
Input data file content
first line 1
second line 2
nothing
another line 3
Output
first line 1
second line 2
another line 3
I'm fixing a large test script (> 1000 lines) that uses some utility methods (also > 1000 lines) to perform repeated tests on various initial data setups. This helps consolidate code. However, when a test fails it reports the line number of inside the utility method making it hard to trace which test failed.
Is it possible to configure Test::Most to give a stacktrace instead of just a single line number when a test fails?
#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use Test::Most tests => 3;
ok(1, 'first test');
note "The following includes a failed test, but a stack trace would be more helpful";
helper_sub_with_test(); # Line 13
ok(1, 'third test');
sub helper_sub_with_test {
ok(0, "second test"); # Line 17
}
Outputs:
$ perl scratch.pl
1..3
ok 1 - first test
# The following includes a failed test, but a stack trace would be more helpful
not ok 2 - second test
# Failed test 'second test'
# at scratch.pl line 17.
ok 3 - third test
# Looks like you failed 1 test of 3.
As you can see, it would be helpful if the failed test reported both line 17 and line 13 for when there are multiple calls to the utility method.
I don't believe that the Test::More infrastructure provides such a beastie, but do you really need a stack trace? Reporting line 13 alone should be sufficient, provided you give your tests descriptive names.
To report line 13 instead of line 17, just add the following to your sub:
local $Test::Builder::Level = $Test::Builder::Level + 1;
Longer example:
#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use Test::Most tests => 3;
ok(1, 'first test');
note "The following includes a failed test, but a stack trace would be more helpful";
helper_sub_with_test(); # Line 13
ok(1, 'third test');
sub helper_sub_with_test {
local $Test::Builder::Level = $Test::Builder::Level + 1;
ok(0, sprintf "second test (look at line %d)", __LINE__); # Line 18
}
The quick and dirty way to get what you want is to put a wrapper around Test::Builder::ok. This is how Test::Most operates.
Using Aspect makes this less of a hack.
use Carp qw(longmess);
use Test::Most;
use Aspect;
after {
# For some reason, the return value is not being captured by Aspect
my $last_test = ($_->self->summary)[-1];
print longmess if !$last_test;
} call "Test::Builder::ok";
sub foo { ok(0) }
foo();
pass;
done_testing;
Input: A list of numbers on command line
Output: Two lists of numbers ,one with input numbers that are greater than zero and one with those that are less than zero (Ignoring zero valued numbers)
here is my code
#!/usr/bin/perl
$i++ = 0;
$j++ = 0;
while ($number = <>)
{
if($number<0)
$first[$i++]=$number;
else
$second[$j++]=$number;
}
print "The numbers with value less than zero are\n";
foreach $number (#first)
print $number;
print "The numbers with value greater than zero are\n"
foreach $number(#second)
print $number;
I am getting the following silly errors which i am not able to rectify.The errors are
divide.pl: 2: ++: not found
divide.pl: 3: ++: not found
divide.pl: 5: Syntax error: ")" unexpected
Can anybody help me out with rectifying these errors please? I am new to perl script
Curly braces on compound statements are not optional in Perl.
Your statements:
$i++=0;
$j++=0;
don't make sense; you probably just want to delete the "++".
You're missing a semicolon on one of your print statements.
Once you've got those problems fixed, you should add
use strict;
use warnings;
after the #! line. This will introduce more error messages; you'll need to fix those as well. For example, you'll need to declare your variables using my().
The code you present will hardly compile. Loops should have {} around the main block, arrays are better created with push (or unshift), you should use strict and warnings, and you can't do increments at the same time as assignments (e.g. $i++ = 0).
use v5.10;
use strict;
use warnings;
my (#first, #second);
while (<STDIN>) { # <STDIN> clearer than <> in this case
chomp;
if ($_ < 0) {
push #first, $_;
} elsif ($_ > 0) {
push #second, $_;
}
}
say "Numbers less than zero:";
say "#first";
say "Numbers greater than zero:";
say "#second";
I don't know what $i++ = 0 is supposed to mean, but change that to $i = 0 to initialize the variables.
Also, the first thing yuu should do in the while loop is call chomp($number) to remove spurious newlines - 5\n is not a number and treating it as one will confuse perl.
Once you've fixed that, post any new errors that show up - I don't see any other problems though.
How are you executing this perl script? Beyond the errors mentioned about the code itself. It looks like you are attempting to evaluate the code using dash instead of perl.
The errors you should be seeing if you were executing it with Perl would be like:
Can't modify postincrement (++) in scalar assignment at /tmp/foo.pl
line 2, near "0;"
But instead, your errors are more in line with what dash outputs:
$ dash /tmp/foo.pl
/tmp/foo.pl: 2: ++: not found
/tmp/foo.pl: 3: ++: not found
Once you've verified that you are running your perl script properly you can start working through the other problems people have mentioned your code. The easiest way to do this is to run it via perl divide.pl instead of whatever you are doing.
use DateTime::TimeZone::Local;
use Test::More tests => 1;
my #input = (1 .. 10 );
my (#output) = sort {
DateTime::TimeZone::Local->TimeZone();
$a cmp $b
} #input;
is_deeply(\#output, \#input);
Output:
1..1
Can't return outside a subroutine at /usr/local/share/perl/5.8.8/DateTime/TimeZone/Local.pm line 72.
# Looks like your test exited with 9 before it could output anything.
shell returned 9
I have checked and it definitely is inside a sub routine. It doesn't appear to be anything to do with the module used, this code also causes the same error:
my #output = sort {
sub1();
} (1 .. 5);
sub sub1 {
eval "use ModuleDoesntExist";
return 1; # remove this and get a seg fault
}
Looks like it is a bug in perl more than anything. Any ideas? More interested in why this is happening than a workaround - it only occurs if the module doesn't exist.
It looks as though it is actually a bug in Perl. See this thread on the Perl Porters list.
I know that the BEGIN block is compiled and executed before the main body of a Perl program. If you're not sure of that just try running the command perl -cw over this:
#!/ms/dist/perl5/bin/perl5.8
use strict;
use warnings;
BEGIN {
print "Hello from the BEGIN block\n";
}
END {
print "Hello from the END block\n";
}
I have been taught that early compilation and execution of a BEGIN block lets a programmer ensure that any needed resources are available before the main program is executed.
And so I have been using BEGIN blocks to make sure that things like DB connections have been established and are available for use by the main program. Similarly, I use END blocks to ensure that all resources are closed, deleted, terminated, etc. before the program terminates.
After a discussion this morning, I am wondering if this the wrong way to look at BEGIN and END blocks.
What is the intended role of a BEGIN block in Perl?
Update 1: Just found out why the DBI connect didn't work. After being given this little Perl program:
use strict;
use warnings;
my $x = 12;
BEGIN {
$x = 14;
}
print "$x\n";
when executed it prints 12.
Update 2: Thanks to Eric Strom's comment below this new version makes it clearer:
use strict;
use warnings;
my $x = 12;
my $y;
BEGIN {
$x = 14;
print "x => $x\n";
$y = 16;
print "y => $y\n";
}
print "x => $x\n";
print "y => $y\n";
and the output is
x => 14
y => 16
x => 12
y => 16
Once again, thanks Eric!
While BEGIN and END blocks can be used as you describe, the typical usage is to make changes that affect the subsequent compilation.
For example, the use Module qw/a b c/; statement actually means:
BEGIN {
require Module;
Module->import(qw/a b c/);
}
similarly, the subroutine declaration sub name {...} is actually:
BEGIN {
*name = sub {...};
}
Since these blocks are run at compile time, all lines that are compiled after a block has run will use the new definitions that the BEGIN blocks made. This is how you can call subroutines without parenthesis, or how various modules "change the way the world works".
END blocks can be used to clean up changes that the BEGIN blocks have made but it is more common to use objects with a DESTROY method.
If the state that you are trying to clean up is a DBI connection, doing that in an END block is fine. I would not create the connection in a BEGIN block though for several reasons. Usually there is no need for the connection to be available at compile time. Performing actions like connecting to a database at compile time will drastically slow down any editor you use that has syntax checking (because that runs perl -c).
Have you tried swapping out the BEGIN{} block for an INIT{} block? That's the standard approach for things like modperl which use the "compile-once, run-many" model, as you need to initialize things anew on each separate run, not just once during the compile.
But I have to ask why it's all in special block anyway. Why don't you just make some sort of prepare_db_connection() function, and then call it as you need to when the program starts up?
Something that won't work in a BEGIN{} will also have the same problem if it's main-line code in a module file that gets used. That's another possible reason to use an INIT{} block.
I've also seen deadly-embrace problems of mutual recursion that have to be unravelled using something like an require instead of use, or an INIT{} instead of a BEGIN{}. But that's pretty rare.
Consider this program:
% cat sto-INIT-eg
#!/usr/bin/perl -l
print " PRINT: main running";
die " DIE: main dying\n";
die "DIE XXX /* NOTREACHED */";
END { print "1st END: done running" }
CHECK { print "1st CHECK: done compiling" }
INIT { print "1st INIT: started running" }
END { print "2nd END: done running" }
BEGIN { print "1st BEGIN: still compiling" }
INIT { print "2nd INIT: started running" }
BEGIN { print "2nd BEGIN: still compiling" }
CHECK { print "2nd CHECK: done compiling" }
END { print "3rd END: done running" }
When compiled only, it produces:
% perl -c sto-INIT-eg
1st BEGIN: still compiling
2nd BEGIN: still compiling
2nd CHECK: done compiling
1st CHECK: done compiling
sto-INIT-eg syntax OK
While when compiled and executed, it produces this:
% perl sto-INIT-eg
1st BEGIN: still compiling
2nd BEGIN: still compiling
2nd CHECK: done compiling
1st CHECK: done compiling
1st INIT: started running
2nd INIT: started running
PRINT: main running
DIE: main dying
3rd END: done running
2nd END: done running
1st END: done running
And the shell reports an exit of 255, per the die.
You should be able to arrange to have the connection happen when you need it to, even if a BEGIN{} proves too early.
Hm, just remembered. There's no chance you're doing something with DATA in a BEGIN{}, is there? That's not set up till the interpreter runs; it's not open to the compiler.
While the other answers are true, I find it also worth to mention the use of BEGIN and END blocks when using the -n or -p switches to Perl.
From http://perldoc.perl.org/perlmod.html
When you use the -n and -p switches to Perl, BEGIN and END work just as they do in awk, as a degenerate case.
For those unfamiliar with the -n switch, it tells Perl to wrap the program with:
while (<>) {
... # your program goes here
}
http://perldoc.perl.org/perlrun.html#Command-Switches if you're interested about more specific information about Perl switches.
As an example to demonstrate the use of BEGIN with the -n switch, this Perl one-liner enumerates the lines of the ls command:
ls | perl -ne 'BEGIN{$i = 1} print "$i: $_"; $i += 1;'
In this case, the BEGIN-block is used to initiate the variable $i by setting it to 1 before processing the lines of ls. This example will output something like:
1: foo.txt
2: bar.txt
3: program.pl
4: config.xml