dly has asked for the wisdom of the Perl Monks concerning the following question:
I've coded up a simple exception class (similar to Exception::Class). While testing its throw() method, I've hit a bizarre problem where the if (grep ... statement returns false when it should return true. I have used this cool grep idiom before. It's basically a short way to see if one element is in an array. I also tried replacing the grep with the equivelent smart match, but that also didn't work. For some reason I cannot figure out, perl is unable to properly dereference @{$exception_param{$exception_type}}. I think I'm using the correct syntax, and there are no syntax errors.
Below is Exception.pm with unneeded code and pod removed
package Exception; use warnings; use strict; # Enable Perl 6 knock offs. use 5.010; use Carp; use Exporter 'import'; our @EXPORT_OK = qw(create_exception delete_exception); # Global stores for all exceptions. # NOTE: In this module each exception is just a Exception class, # and not it's own class; instead the data about each exception is cre +ated with # create_exception() and destroyed with delete_exception() while being + stored in # %exception_{desc,param}. state %exception_desc; state %exception_param; # It is a hash of hashes. Each key in the first hash is the name or t +ype of # exception, while the key in the second hash is 'description' for the + type's # description, or 'params' for the list of parameters that exception +takes. # Constructs new Exception objects in order to throw exceptions # coupled with die. For example: # die Exception->throw('SomeException'); sub throw { my($class, $exception_type, @params) = @_; croak <<EOC unless exception_exists($exception_type); You tried to throw an exception [$exception_type] that does not exist, + or has not been declared. You must define every exception before you try to +throw that exception. EOC # Build object now for use below. my $self = bless {_exception_type => $exception_type, _description => $exception_desc{$exception_type} }, $cla +ss; # shift off the name of the parameter. while (defined(my $param = shift @params)) { if (grep $param eq $_, @{$exception_param{$exception_type}}) { # Store parameter inside this exception object. $self->{$param} = (shift @params // croak <<EOC); You tried to throw an exception that had an uneven number of parameter +s and their values. The list of parameters you provide must be an even numb +er of parameters followed by their values as in a hash. (ex: 'exception' a = +> '1', b => '2', c => '3') EOC # Also, substitute this paramter for its value in this exc +eption's # description. #BUGALERT# be sure to test that this actually works. $self->{_description} =~ s/$param/$self->{$param}/g; } else { croak <<EOC; You tried to throw an exception with a paramter that the exception doe +s not accept. Your parameters [@params]. Accepted parameters [@{$exception_param{$exception_type}}]. EOC } } return $self; } # A subroutine to be optionally exported by Exception that adds # entries to %exception thereby creating new exceptions. Each class t +hat throws # exceptions must call this subroutine first to create those exception +s. sub create_exception { my ($exception_type, $description, @params) = @_; if (exception_exists($exception_type)) { warn <<EOW; You have redefined an exception. This might be an error, because they + should really only be defined just once. EOW } # Add this new exception to %exception_{desc,param}. $exception_desc{$exception_type} = $description, $exception_param{$exception_type} = [@params]; } # Checks to see if a given exception exists or not. sub exception_exists { my $exception_type = shift; if (exists $exception_desc{$exception_type} and exists $exception_param{$exception_type} ) { return "$exception_type exists!"; #return true } else { return 0; #return false } } 1;
Below is the code for exception.t with its unneeded code also removed, which tests Exception.pm using Test::More.
#!perl # exception.t tests all of Exception. use strict; use warnings; use diagnostics; use 5.010; use Test::More;# tests => '19'; BEGIN { use_ok('Exception', 'create_exception'); } # Test uneven params. # create exception w/params create_exception('ParameterException', 'description', 'param', 'param2 +'); evalok(sub {eval {die Exception->throw('TestException', param =>)};}, <<EOD, 'check throw()ing uneven params'); You tried to throw an exception that had an uneven number of parameter +s and their values. The list of parameters you provide must be an even numb +er of parameters followed by their values as in a hash. (ex: 'exception' a = +> '1', b => '2', c => '3') EOD done_testing(); # runs code, and validates the $@ error message. # Why make people install Test::Exception if this little bit of code i +s all # that's needed? sub evalok { my ($code, $expected_message, $test_name) = @_; $code->(); my $croak = $@; $croak =~ s/\sat.*\n$//; #remove cruft. is($croak, $expected_message, $test_name); }
Example output from running exception.t test file (use prove -v exception.t to run)
exception.t .. ok 1 - use Exception; not ok 2 - check throw()ing uneven params # Failed test 'check throw()ing uneven params' # at delme.t line 34. # got: 'You tried to throw an exception [TestException] that +does not exist, or has # not been declared. You must define every exception before you try t +o throw that # exception. # ' # expected: 'You tried to throw an exception that had an uneven nu +mber of parameters and # their values. The list of parameters you provide must be an even nu +mber of # parameters followed by their values as in a hash. (ex: 'exception' a + => '1', b # => '2', c => '3') # ' 1..2 # Looks like you failed 1 test of 2. Dubious, test returned 1 (wstat 256, 0x100) Failed 1/2 subtests Test Summary Report ------------------- exception.t (Wstat: 256 Tests: 2 Failed: 1) Failed test: 2 Non-zero exit status: 1 Files=1, Tests=2, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.07 cusr + 0.00 csys = 0.09 CPU) Result: FAIL
As shown in the example output above. The expected:... part is the error message that should be executed, but since the if statement is false when it should be true the other error message shown in got:... is displayed instead.
Thanks in advance for any help or insight into this weird problem you could provide.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: grep in if statement not working as expected
by JavaFan (Canon) on Sep 10, 2010 at 07:24 UTC | |
by dly (Beadle) on Sep 10, 2010 at 11:18 UTC |