in reply to Re: Problem: Lazy Hash Evaluation
in thread Problem: Lazy Hash Evaluation

> If the problem is that the value used_by is only present when you dump
That's exactly the problem.

> There's nothing about perl to magically invent this used_by value
I was expecting it to be produced as part of the output of scan_deps() and the subrountine generic_rv_test() is therefore testing that it was produced.

The only thing that I can think of that might explain this is that the data stucture $rv hasn't been completely filled out, as a result of scan_deps(), before it's used by generic_rv_test() except in the case when I dump $rv. However, that strikes me as being unlikely.

> You ought to show your cards.
I assume you mean give you the full code so here it is:

The test script (4-pluggable_fake.t)"

#!/usr/bin/perl use Module::ScanDeps; use strict; use warnings; use Test::More qw(no_plan); # no_plan because the number of objects in + the dependency tree (and hence the number of tests) can change use T::Utils; use lib qw(t/data/pluggable); if (eval {require Module::Pluggable}) { my $rv = scan_deps( files => ['t/data/pluggable/Foo.pm'], recurse => 1, ); my @deps = qw(Pluggable.pm Foo/Plugin/Bar.pm Foo/Plugin/Baz.pm); generic_rv_test($rv, ['t/data/pluggable/Foo.pm'], \@deps); # my @used_by = @{$rv->{'Pluggable.pm'}{used_by}}; # warn "Pluggable.pm used_by: @used_by\n"; # use Data::Dump qw(dump); # print dump $rv; } else { diag("Module::Pluggable not installed, skipping all tests"); } __END__

NB if I uncomment either of the two groups of comments in the above I get the used_by => ["Foo.pm"], line I'm testing for and all is OK.

The complete generic_rv_test subrountine:

use strict; use warnings; package T::Utils; use vars qw( $VERSION @ISA @EXPORT ); require Exporter; use Test::More; @ISA=qw(Exporter); $VERSION = '0.1'; @EXPORT = qw( generic_rv_test ); my $test = Test::More->builder; sub import { my($self) = shift; my $pack = caller; $test->exported_to($pack); $self->export_to_level(1, $self, @EXPORT); } sub _path_to_filename { my $file = shift @_; my ($vol, $dir, $key) = File::Spec->splitpath($file); return $key; } sub generic_rv_test { my $rv = shift; my $array_ref = shift; my @input_keys = sort @$array_ref; $array_ref = shift; my @known_deps = sort @$array_ref; my @used_by; my ($used_by_ok, $i); # sanity check input foreach my $input (@input_keys) { !(grep {$_ eq $input} @known_deps) or die "\@input_keys overlaps + with \@known_deps\n"; } $test->ok(ref($rv) eq "HASH", "\$rv is a ref") or return; # check all input files and known deps correspond to an entry in r +v map {$_ = _path_to_filename($_)} @input_keys; map {$_ =~ s|\\|\/|go} (@input_keys, @known_deps); $test->ok(exists $rv->{$_}, "$_ is in rv") foreach (@input_keys, @ +known_deps); # Check general properties of the keys foreach my $key (keys %$rv) { $test->ok(((exists($rv->{$key}{key}) && $key eq $rv->{$key}{ke +y}) && (exists($rv->{$key}{file}) && $rv->{$key}{file} =~ +/(?:^|[\/\\])$key$/) && (exists($rv->{$key}{type}) && $rv->{$key}{type} =~ +/^(?:module|autoload|data|shared)$/)), "For $key: sub-key matches && file matches && type +matches module|autoload|data|shared"); if (exists($rv->{$key}{used_by})) { @used_by = sort @{$rv->{$key}{used_by}}; if ($#used_by + 1 > 0) { $used_by_ok = 1; if ($#used_by + 1 > 1) { for ($i=0; $i<$#used_by; $i++) { if ($used_by[$i] eq $used_by[$i+1]) { # relies + on @used_by being sorted earlier $used_by_ok = 0; last; } } } $test->ok($used_by_ok, "$key\'s used_by has no duplica +tes"); $used_by_ok = 1; foreach my $used_by (@used_by) { $used_by_ok &= exists($rv->{$used_by}); } $test->ok($used_by_ok, "All entries in $key\'s used_by + are themselves described in \$rv"); } else { print "array length: $#used_by\n"; $test->ok(0, "$key\'s used_by exists and isn't empty") +; } } else { $test->ok((grep {$_ eq $key} @input_keys) | ($key =~ m/Plu +gin/o), "used-by not defined so $key is one of the input files or is +a plugin"); # THIS IS WHERE THE TEST FAILS DUE TO THE MISSING USED_BY + INFORMATION } } } 1; __END__
And finally, the subroutine scan_deps comes from the CPAN module Module::ScanDeps.

Thanks for the help,
Adrian