Sub::Contract

Sub::Contract module offers pragmatic contract programming for Perl.
Download

Sub::Contract Ranking & Summary

Advertisement

  • Rating:
  • License:
  • Perl Artistic License
  • Price:
  • FREE
  • Publisher Name:
  • Erwan Lemonnier
  • Publisher web site:
  • http://search.cpan.org/~erwan/Sub-Contract-0.09/lib/Sub/Contract.pm

Sub::Contract Tags


Sub::Contract Description

Sub::Contract module offers pragmatic contract programming for Perl. Sub::Contract module offers pragmatic contract programming for Perl.SYNOPSISFirst of all, you should define a library of pseudo-type constraints. A type constraint is a subroutine that returns true if the argument if of the right type, and returns false or croaks if not. Example: use Regexp::Common; # test that variable is an integer sub is_integer { my $i = shift; return 0 if (!defined $i); return 0 if (ref $i ne ""); return 0 if ($i !~ /^$RE{num}{int}$/); return 1; } sub is_shortdate { ... } sub is_account_number { ... } sub is_amount { ... } # and so on...To contract a function 'surface' that takes a list of 2 integers and returns 1 integer: use Sub::Contract qw(contract); contract('surface') ->in(&is_integer, &is_integer) ->out(&is_integer) ->enable; sub surface { # no need to validate arguments anymore! # just implement the logic: return $_ * $_; }Since the result of 'surface' is a function of its input arguments only, we may want to memoize (cache) it: contract('surface') ->in(&is_integer, &is_integer) ->out(&is_integer) ->memoize ->enable;If 'surface' took a hash of 2 integers instead, with the keys 'height' and 'width': use Sub::Contract qw(contract); contract('surface') ->in(height => &is_integer, width => &is_integer) ->out(&is_integer) ->enable; sub surface { my %args = @_; return $args{height}* $args{width}; }Of course, a real life example is more likly to look like: use Sub::Contract qw(contract is_a); # contract the method 'send_money' from class 'My::Account' contract("send_money") ->in( is_a('My::Account'), to => is_a('My::Account'), amount => &is_integer, date => &is_date ) ->out( is_a('My::StatusCode') ) ->enable; # and a call to 'send_money' may look like: my $account1 = new My::Account("you"); my $account2 = new My::Account("me"); $account1->send_money( to => $account2, amount => 1000, date => "2008-06-16" );To make an argument of return value free of constraint, just set its constraint to undef: contract("send_money") ->in( undef, # no need to check self to => is_a('My::Account'), amount => undef, # amount may be whatever date => &is_date ) ->enable;You can also declare invariants, pre- and post-conditions as in usual contract programming implementations: contract('foo') ->pre( &validate_state_before ) ->post( &validate_state_after ) ->invariant( &validate_state ) ->enable;To turn off all contracts within namespaces matching '^My::Account::.*$' use Sub::Contract::Pool qw(get_contract_pool); my $pool = get_contract_pool(); foreach my $contract ($pool->find_contracts_matching("My::Account::.*")) { $contract->disable; }You may list contracts during runtime, modify them and recompile them dynamically, or just turn them off. See 'Sub::Contract::Pool' for details. Requirements: · Perl


Sub::Contract Related Software