NAME
Attribute::Contract - Design by contract via Perl attributes
SYNOPSIS
package Interface;
use AttributeContract;
sub do_smth :ContractRequires(VALUE, @ANY?) :ContractEnsures(VALUE) {
...;
}
package Implementation;
use base 'Interface';
use AttributeContract;
sub do_smth {
my $self = shift;
my ($foo, @rest) = @_;
return 1;
}
Implementaion->do_smth('hi', 'there'); # works
Implementaion->do_smth(); # croaks!
Implementaion->do_smth(sub {}); # croaks!
DESCRIPTION
Attribute::Contract by using Perl attributes allows you to specify contract (Design by Contract) for every method in your class. You can check incoming and outgoing values by specifying ContractRequires
and ContractEnsures
attributes.
It's the most useful for interfaces or abstract classes when you want to control whether your implementation follows the same interface and respects the Liskov substitution principle.
This module does not check the actual types like Str
, Int
etc, but the Perl data types like scalars, arrays, hashes, references and so on. When the type does not match a Carp's confess
function will be called with detailed information like:
0 param(s) passed, at least 1 param(s) is required
Why attributes? They feel and look natural and are applied during compile time.
TYPES
Scalar types
ANY
Any scalar value is accepted.
VALUE
Anything but not a reference.
REF
A non blessed reference to anything.
REF(SCALAR)
A reference to scalar.
REF(ARRAY)
A reference to array.
REF(HASH)
A reference to hash.
REF(Regexp)
A reference to regular expression.
OBJECT
A blessed reference.
OBJECT(ISA)
A blessed reference with specified isa.
Greedy types
Types that eat all the elements. Can be specified at the end of the elements list for manual unpacking. @
stands for arrays and %
stands for hashes. All the scalar types can be used to specify the types of the elements.
@ARRAY
@VALUE
Which could mean something like:
$object->method(1, 2, 3, 4);
%HASH
%ANY
Which could mean something like:
$object->method(foo => 'bar', 'baz' => \123);
It also checks that the number of elements is even.
MULTIPLE VALUES
Use ,
when specifying several arguments.
VALUE,ANY,REF(CODE),@VALUE
Which could mean something like:
$object->method($foo, \@array, sub { ... }, 1, 2, 3);
ALTERNATIVES
Use |
when specifying an alternative type.
VALUE|REF(VALUE)
Which could mean something like:
$object->method($foo);
or
$object->method(\$foo);
Alternatives can be really deep, like this one:
@(REF(HASH|CODE)|VALUE)
Which is an array of references to hash or code or simple value.
OPTIONAL VALUES
Use ?
when specifying an optional value.
VALUE,VALUE?
Which could mean something like:
$object->method('foo');
or
$object->method('foo', 'bar');
IMPLEMENTATION
Inheritance
By default all the contracts are inherited. Just don't forget to use
Attribute::Contract in the derived class. But if no methods are override then even using
this module is not needed.
Caching
During the compile time for every contract a Perl subroutine is built and evaled. If the methods share the same contract they use the same checking code reference. This speeds up the checking and saves some memory.
Error reporting
Errors are as specific as possible. On error you will get a meaningful message and a stack trace.
SWITCHING OFF
You can switch off contract checking by specifying an environment variable NO_ATTRIBUTE_CONTRACT
.
DEVELOPMENT
Repository
http://github.com/vti/attribute-contract
AUTHOR
Viacheslav Tykhanovskyi, vti@cpan.org
.
COPYRIGHT AND LICENSE
Copyright (C) 2012, Viacheslav Tykhanovskyi
This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.