Subject: | __compose_pass_or_skip |
Date: | Sat, 14 Apr 2007 23:56:59 -0400 |
To: | <bug-Brick [...] rt.cpan.org> |
From: | Andrew Gianni <agianni [...] buffalo.edu> |
I'm having trouble getting logged into RT on CPAN, so I'll try the email
interface. I've found what I consider to be a bug in __compose_pass_or_skip.
My problem is that when I try to use it in creation of selectors I get fatal
errors as would otherwise only be thrown by a constraint. I have put
together an updated version of the method as well as a test that will point
out my problem with the existing implementation, which is corrected by my
update.
Currently test four fails in my test, which is the primary issue causing me
trouble. The main thing I changed is that the only action taken within the
closure is to return when something succeeds. It also keeps track of
coderefs that die so it can avoid a final fatal error at the end if nothing
passed; i.e. if it's made up of nothing but selectors, it will act as a
selector itself. The only think I'm not certain of is what the functionality
should be if one were to include both selector and constraint bricks within
a call to __compose_pass_or_skip. In the case of both of our implementations
it would create a fatal error, which would give constraining bricks more
"prescience" as it were. I'm comfortable with this notion, although I have
yet to run into a situation where I would want to do such a thing with
__compose_pass_or_skip.
Please let me know what you think:
The test:
#!/perl
use strict;
use warnings;
use Carp;
use English qw( no_match_vars );
use Brick;
use Test::More qw( no_plan );
my $brick = Brick->new();
my $bucket = $brick->create_bucket();
my $coderef = $bucket->__compose_pass_or_skip(
sub { croak { message => "failing1" } },
sub { return 1; },
);
eval{ $coderef->() };
ok ( ( not $EVAL_ERROR ), 'success with one croak and one return 1' );
$coderef = $bucket->__compose_pass_or_skip(
sub { return 0; },
sub { return 1; },
);
eval{ $coderef->() };
ok ( ( not $EVAL_ERROR ), 'success with one return 0 and one return 1' );
$coderef = $bucket->__compose_pass_or_skip(
sub { croak { message => "failing1" } },
sub { croak { message => "failing2" } },
);
eval{ $coderef->() };
ok ( $EVAL_ERROR, 'error generated with two croaks' );
# THIS FAILS WITH THE CURRENT VERSION
$coderef = $bucket->__compose_pass_or_skip(
sub { return; },
sub { return; },
);
my $result = eval{ $coderef->() };
ok ( ( not $EVAL_ERROR ), 'not eval error with two return 0' );
ok ( ( not $result ), 'returns 0' );
The update:
sub __compose_pass_or_skip
{
my( $bucket, @subs ) = @_;
if( grep { ref $_ ne ref sub {} } @subs )
{
croak "Got something else when expecting code ref!";
return sub {};
}
my @caller = $bucket->__caller_chain_as_list();
my $sub = $bucket->add_to_bucket( {
code => sub {
my @dies = ();
foreach my $sub ( @subs )
{
my $result = eval { $sub->( @_ ) };
my $at = $@;
return $result if $result;
push @dies, $sub if ref $at and $at;
}
if ( scalar @dies ) {
die {
message => "Nothing worked! Unexpected failure of
all branches",
handler => $caller[0]{'sub'},
errors => \@dies,
};
}
else {
return;
}
},
});
$bucket->comprise( $sub, @subs );
return $sub;
}