The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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.