Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Bug in YAML::Any - What to do?

by bv (Friar)
on Dec 14, 2009 at 22:51 UTC ( [id://812779]=perlquestion: print w/replies, xml ) Need Help??

bv has asked for the wisdom of the Perl Monks concerning the following question:

So I found what I believe to be a bug in YAML::Any, specifically in the Dump function, but I suspect that the nearly identical code in DumpFile, Load, and LoadFile are also buggy. The intention of the code in question is to apply the settings of the $YAML::Option global options to the chosen implementation of YAML (in my case, YAML::XS). Here is the code, with my debug statements marked:

sub Dump { no strict 'refs'; my $implementation = __PACKAGE__->implementation; my $debug; # My own debug variable for my $option (@dump_options) { my $var = "$implementation\::$option"; $debug = $var if $var =~/UseCode/; #the option I wish to set my $value = $$var; local $$var; # <-- PROBLEM! Local to "for", not "sub" $$var = defined $value ? $value : ${"YAML::$option"}; # Here I print out the option in each iteration of the loop print STDERR "$debug = $$debug\n"; } # And the final value: print STDERR "FINAL: $debug = $$debug\n"; return &{"$implementation\::Dump"}(@_); }

My test code:

#!/usr/bin/perl use strict; use warnings; use YAML::Any; local $YAML::UseCode=1; my $input = sub { print "Enter a value: "; return chomp (my $ret = <>); }; print Dump $input; __END__ Name "YAML::UseCode" used only once: possible typo at test.pl line 7. YAML::XS::UseCode = 1 YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = YAML::XS::UseCode = FINAL: YAML::XS::UseCode = --- !!perl/code '{ "DUMMY" }'

The "Name used only once" warning is not the issue, since I get the same warning when setting $YAML::XS::UseCode directly, and the output is what I would expect (The output of B::Deparse on the CODE reference);

What I believe is the issue is that each global option is localized within the for loop, and immediately returns to its previous value upon the next iteration. What I need is a solution to localize the value such that it stays set for the function call that is returned in the last line. So my questions are twofold:

  1. How do I set the value for $YAML::UseCode and have it apply to whatever implementation YAML::Any has chosen, AND
  2. How do I go about getting this (I think) bug fixed in YAML::Any?

Thanks much! My environment: YAML-0.70, YAML-LibYAML-0.32, "This is perl, v5.10.0 built for i486-linux-gnu-thread-multi"

UPDATE: My workaround is to use YAML::Any's implementation() method and cheat with strict refs:

#!/usr/bin/perl use warnings; use YAML::Any; local ${YAML::Any->implementation()."::UseCode"}=1; # can't use strict before this because of refs use strict;


@_=qw; Just another Perl hacker,; ;$_=q=print "@_"= and eval;

Replies are listed 'Best First'.
Re: Bug in YAML::Any - What to do?
by ikegami (Patriarch) on Dec 15, 2009 at 00:01 UTC
    Icky hack (local ... for ...;):
    sub Dump { my @opts; for my $option (@dump_options) { no strict 'refs'; my $ref = \${$implementation.'::'.$option}; push @opts, [ $ref => defined($$ref) ? $$ref : ${"YAML::$option"}, ]; } local ${$_->[0]} = $_->[1] for @opts; return &{"$implementation\::Dump"}; }

    Sticking to something that won't break:

    { package YAML::OnScopeExit; sub DESTROY { ${ shift() }->() } } sub _on_scope_exit(&) { my ($sub) = @_; return bless(\$sub, 'YAML::OnScopeExit'); } sub Dump { my @opts; for my $option (@dump_options) { no strict 'refs'; my $ref = \${$implementation.'::'.$option}; push @opts, [ $ref => defined($$ref) ? $$ref : ${"YAML::$option"}, $$ref, ]; } my $sentinel = _on_scope_exit { ${$_->[0]} = $_->[2] for @opts; }; ${$_->[0]} = $_->[1] for @opts; return &{"$implementation\::Dump"}; }

    Both untested.

Re: Bug in YAML::Any - What to do?
by zwon (Abbot) on Dec 14, 2009 at 23:30 UTC
    How do I go about getting this (I think) bug fixed in YAML::Any?

    Go to YAML::Any cpan page, follow "Report Bug" link and submit bug description. If you can fix the bug attach the patch. It is a good idea to check that this bag has not yet been reported by somebody else, there are a lot of bugs in the YAML::Any RT.

Re: Bug in YAML::Any - What to do?
by Anonymous Monk on Dec 14, 2009 at 23:23 UTC
    yup, thats a bug, to fix you can put references into array, then local
    sub Dump { my @vals ; my @opts ; for my $option (@dump_options) { no strict 'refs'; my $var = \${"$implementation\::$option"}; push @opts, $var; push @vals, defined $value ? $value : ${"YAML::$option"}; } local (@opts) = @vals; return &{"$implementation\::Dump"}(@_); }

      That attempts to localise @opts, not the scalars referenced by the elements of @opts.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (6)
As of 2024-04-16 17:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found