I guess I'm not really sure what your use case is.
If your code is mostly object-oriented, you can take advantage of type constraints in any of the major OO frameworks. That automatically covers you for object constructors and accessors.
Then if you want to check the parameters passed to method calls and function calls, you can re-use the same type constraint checking, courtesy of things like Type::Params. For example, if you want to check that your add function has been passed two numbers:
use feature qw(state); # Perl 5.10+
use Type::Params qw(compile);
use Types::Standard qw(Num);
sub add {
state $check = compile( Num, Num );
my ($x, $y) = $check->(@_); # will croak if not passed two numbers
my $sum = $x + $y;
return $sum;
}
If you want to check that certain variables are sane within your function, not just the parameters that are passed as input, then you can still do this with type constraints:
use feature qw(state); # Perl 5.10+
use Type::Params qw(compile);
use Types::Standard qw(Num);
sub add {
state $check = compile( Num, Num );
my ($x, $y) = $check->(@_); # will croak if not passed two numbers
my $sum = $x + $y;
Num->assert_return( $sum );
}
Though frankly, if you keep your function definitions short and simple, this is rarely necessary.
Then you just come down to a handful of sanity checks that go beyond what type constraints would normally do.
use feature qw(state); # Perl 5.10+
use Type::Params qw(compile);
use Types::Standard qw(ArrayRef);
use Carp;
use PerlX::Assert;
sub zip {
state $check = compile( ArrayRef, ArrayRef );
my ($x, $y) = $check->(@_);
# An additional check on input.
# Carp is a pretty appropriate way of dealing with this.
#
croak "Arrays must be same length" unless @$x == @$y;
my @z = map { [$x->[$i], $y->[$i]] } 0 .. $#$x;
# These assertions check the internal logic of our
# function, so using Carp makes less sense. It's not
# the caller's fault if they fail. Here an assertion
# feature makes sense. And because we believe
# our logic to be correct, it's hopefully okay to
# optimize this away in the production environment.
#
assert '@z has same length as @$x' { @z == @$x };
assert '@z has same length as @$y' { @z == @$y };
# \@z should be an arrayref of arrayrefs.
#
ArrayRef->of(ArrayRef)->assert_valid( \@z );
}
I don't see what the point of adding a big Test::Builder-like framework on top of this would be. What can it cover which the above cannot? |