Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

What am I breaking? (solved - double unquoting needing 'qw')

by perl-diddler (Chaplain)
on May 09, 2019 at 18:20 UTC ( [id://1233521]=perlquestion: print w/replies, xml ) Need Help??

perl-diddler has asked for the wisdom of the Perl Monks concerning the following question:

This is what I get for trying to refactor and make improvements in my code grief grief grief.

One of the tests for one of my modules am in process of trying to simplify/rewrite but I'm torturing myself far more than I think I should so thought I'd throw this in here and ask for some more eyes.

This program started out looking something like:

#!/usr/bin/perl -w ## Before 'make install' is performed this script should be runnable w +ith # 'make test'. After 'make install' it should work as 'perl t09.t' ######################### use strict; use warnings; { package one; our $VERSION='0.0.5'; use mem; our @EXPORT; use mem(@EXPORT=qw(expone)); sub expone() {"oneok"} use Xporter; 1} { package two; our $VERSION='0.1.1'; use mem; our @EXPORT; use mem(@EXPORT=qw(exptwo)); sub exptwo() {"twook"} use Xporter; 1} #...(but with 10 cases not shown) package main; use Test::More; my $res1 = eval "use one '0.1.1'; expone;"; ok(!defined($res1), "undef for res1: wanted ver '0.1.1' from ver '0.0. +5'"); my $res2 = eval "use two '0.0.5'; exptwo;"; ok($res2 eq "twook", "got answer w/min '0.0.5' from ver '0.1.1'"); #...(same comment as above) done_testing(); # vim: ts=2 sw=2 ai number foldcolumn=1
So I wanted to add some more, and while enumeration of each case wasn't a problem with a few, the problem grew, so I decided to bite the code now before it bit back harder -- even though it's biting back out of spite.

My 174 lines for twelve cases now has shrunk to 85 lines for 16 cases, but is giving more grief than it should. Currently I have:

01 #!/usr/bin/perl 02 use warnings; use strict; 03 use P; 04 ## Before 'make install' is performed this script should be runnabl +e with 05 # 'make test'. After 'make install' it should work as 'perl t09.t' 06 07 ######################### 08 09 our @num2nam; 10 11 BEGIN { 12 our @num2nam = ( 13 [ zero => 0 ], 14 [ one => '0.0.5'], 15 [ two => '0.1.1'], 16 [ three => 0.000005], 17 [ four => 0.000101], 18 [ five => 0.0.5], 19 [ six => 0.1.1], 20 [ seven => 1.10], 21 [ eight => 1.5], 22 [ nine => 0.1.5], 23 [ ten => 0.1.10], 24 [ eleven => '000005'], 25 [ twelve => '001010'], 26 [ thirteen => 3.0014], 27 [ fourteen => 3.1], 28 [ fifteen => '3.0014'], 29 [ sixteen => '3.1'],); 30 31 my $prog=""; 32 33 for (my $i=1; $i < @num2nam; ++$i) { 34 35 my ($nam, $val) = @{$num2nam[$i]}; 36 37 $prog .= sprintf( 38 q< { package %s; 39 our $VERSION=%s; 40 use mem; our @EXPORT; 41 use mem(@EXPORT=qw(exp%s)); 42 sub exp%s() {"%sok"} 43 use Xporter; 44 } > . "\n\n", $nam, $val, $nam, $nam, $nam); 45 } 46 47 eval "$prog"; 48 $@ and do { Pe "eval error: %s", $@; }; 49 } 50 51 package main; 52 53 use Test::More; 54 55 BEGIN { 56 our @num2nam; 57 58 my $prog=""; 59 my $res; 60 61 for (my $i=1; $i < @num2nam; $i+=2) { 62 63 my ($nam1, $val1) = @{$num2nam[$i]}; 64 my ($nam2, $val2) = @{$num2nam[$i+1]}; 65 66 $prog .= sprintf( 67 q< 68 $res = eval "use %s %s; exp%s;"; 69 ok(!defined($res), "undef for res: wanted ver %s from ver %s +"); 70 71 $res = eval "use %s %s; exp%s;"; 72 ok($res eq "%sok", "got answer w/min %s from ver %s"); 73 >, $nam1, $val2, $nam1, $val2, $val1, 74 $nam2, $val1, $nam2, $nam2, $val1, $val2); 75 } 76 77 eval "$prog"; 78 $@ and do { Pe "eval error: %s", $@; }; 79 80 } 81 82 83 done_testing(); 84 # vim: ts=2 sw=2 ai number foldcolumn=1
Putting the test cases & package construction into a BEGIN loop seemed simple enough, but after some time, I'm not seeing some of the issue it is complaining about:
> cls;perl t/t09.t eval error: Missing right curly or square bracket at (eval 12) line 34 +, at end of line syntax error at (eval 12) line 34, at EOF ok 1 - undef for res: wanted ver 0.1.1 from ver 0.0.5 Use of uninitialized value $res in string eq at (eval 14) line 6. not ok 2 - got answer w/min 0.0.5 from ver 0.1.1 # Failed test 'got answer w/min 0.0.5 from ver 0.1.1' # at (eval 14) line 6. ok 3 - undef for res: wanted ver 0.000101 from ver 5e-06 ok 4 - got answer w/min 5e-06 from ver 0.000101 ok 5 - undef for res: wanted ver  from ver Use of uninitialized value $res in string eq at (eval 14) line 18. not ok 6 - got answer w/min from ver  # Failed test 'got answer w/min from ver ' # at (eval 14) line 18. ok 7 - undef for res: wanted ver 1.5 from ver 1.1 Use of uninitialized value $res in string eq at (eval 14) line 24. not ok 8 - got answer w/min 1.1 from ver 1.5 # Failed test 'got answer w/min 1.1 from ver 1.5' # at (eval 14) line 24. ok 9 - undef for res: wanted ver  # from ver  Use of uninitialized value $res in string eq at (eval 14) line 32. not ok 10 - got answer w/min  from ver  # # Failed test 'got answer w/min  from ver  # ' # at (eval 14) line 32. ok 11 - undef for res: wanted ver 001010 from ver 000005 Use of uninitialized value $res in string eq at (eval 14) line 39. not ok 12 - got answer w/min 000005 from ver 001010 # Failed test 'got answer w/min 000005 from ver 001010' # at (eval 14) line 39. ok 13 - undef for res: wanted ver 3.1 from ver 3.0014 Use of uninitialized value $res in string eq at (eval 14) line 45. not ok 14 - got answer w/min 3.0014 from ver 3.1 # Failed test 'got answer w/min 3.0014 from ver 3.1' # at (eval 14) line 45. ok 15 - undef for res: wanted ver 3.1 from ver 3.0014 Use of uninitialized value $res in string eq at (eval 14) line 51. not ok 16 - got answer w/min 3.0014 from ver 3.1 # Failed test 'got answer w/min 3.0014 from ver 3.1' # at (eval 14) line 51. 1..16 # Looks like you failed 7 tests of 16.
Not the least of which is 'why' or what or where am I missing a bracket on the 12 iteration through the loop? I really don't know if the rest are created by that or what, but....hoping if I can knock a few down the rest might more easily fall into place.

Clue sticks appreciated...& thnx! Darn Murpy: "No attempt to refactor shall go unpunished!"

Replies are listed 'Best First'.
Re: What am I breaking?
by bliako (Monsignor) on May 09, 2019 at 19:25 UTC

    In our @num2nam = (... [       six =>    0.1.1], ...) not quoting the values (e.g. 0.1.1) results in unprintable characters (0.1.1 concatenates ascii 0, 1 and 1 to a string) that confuse eval. After fixing it, you will only have to find why $res is undefined.

    Edit: I am slightly out of my depth here as I was not aware of the "version strings" before haukex's Re^2: What am I breaking?. Although quoting the version strings may have fixed the problem, there is the danger of short-circuiting the test logic. Perhaps one can sprintf() those naked version strings using the special sprintf formatter mentioned by AnomalousMonk.

    bw, bliako

        question: how does one sprintf() version strings?

      Hitting the nail askance you did!

      This should replace the table and results in 0 errors/everything working:

      our @num2nam = ( [ qw(zero 0 )], [ qw(one '0.0.5')], [ qw(two '0.1.1')], [ qw(three 0.000005)], [ qw(four 0.000101)], [ qw(five 0.0.5)], [ qw(six 0.1.1)], [ qw(seven 1.10)], [ qw(eight 1.5)], [ qw(nine 0.1.5)], [ qw(ten 0.1.10)], [ qw(eleven '000005')], [ qw(twelve '001010')], [ qw(thirteen 3.0014)], [ qw(fourteen 3.1)], [ qw(fifteen '3.0014')], [ qw(sixteen '3.1')], );
      Those items were being dequoted twice, so the ones that need to be quoted had to be quoted twice, and the ones that didn't still needed quoting once.

      Thanks for the hint!

      In light of them intentionally being 'version strings', are they still a problem?

      As far as I know, they should result a string with (if ^@=NUL), like '^@^A^A^@^@^@^@^@'. It may not be standardized or desirable, but this is a test program to test/verify how such things are handled. I.e. I wouldn't want such things to cause a core-breach or similar :-).

        Probably you should not modify the quotation of the version strings in the array. Can you just use the "vector flag" mentioned by node:AnomalousMonk for the unquoted version strings only and the "string formatter - %s" for the quoted cases? See also my edited previous answer.

      No, it's fine -- cuz what I meant by hitting the nail askance -- is that eval really didn't like binary embedded in the source it was 'eval'ing -- as you mentioned. That section was being 'eval'ed twice, once by the new code that looped through the table to create the packages, and second, in the 'use pkg X.Y.Z;' code because you can't use an expression with 'use', so the only way to put in the version I wanted was have the eval "evaluate" the expression so it would behave normally.

      My "hints" were that in some of the version strings I had quoted them and had done so deliberately, while in some of the I had not done so (again deliberately) -- and that the final test resulted in some tests that were quoted strings, while others used the 'binary' (as formed by the vector) value of the version string.

      That's when I put it together -- why didn't the binary cause problems in original code -- because it is only turned into binary as it is eval'ed in the test case. Since I was evaling it twice, my first eval had to result in both a quoted (the qw('quoted string')) and a non-quoted value (qw(vec.tor)) for the different test cases.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1233521]
Approved by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (4)
As of 2024-04-19 04:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found