
MooseX::Attribute::Dependent - Restrict attributes based on values of other attributes

version 1.1.2

package Address;
use Moose;
use MooseX::Attribute::Dependent;
has street => ( is => 'rw', dependency => All['city', 'zip'] );
has city => ( is => 'ro' );
has zip => ( is => 'ro', clearer => 'clear_zip' );
no MooseX::Attribute::Dependent;
Address->new( street => '10 Downing Street' );
# throws error
Address->new( street => '10 Downing Street', city => 'London' );
# throws error
Address->new( street => '10 Downing Street', city => 'London', zip => 'SW1A 2AA' );
# succeeds
my $address = Address->new;
$address->street('10 Downing Street');
# throws error
$address->city('London');
$address->zip('SW1A 2AA');
$address->street('10 Downing Street');
# succeeds

Moose type constraints restrict based on the value of the attribute. Using this module, attributes can have more complex constraints, which involve values of other attributes. It comes with a few constraints and can easily be extended.

All related attributes must have a value.
At least one related attribute must have a value.
None of the related attributes can have a value.
At least one of the related attributes cannot have a value.

To define your own dependency, first create a class to register your custom dependency. In this example, we want to restrict an attribute to values smaller than serveral other attributes.
package MyApp::Types;
use MooseX::Attribute::Dependency;
use List::MoreUtils ();
MooseX::Attribute::Dependency::register({
name => 'SmallerThan',
message => 'The value must be smaller than %s',
constraint => sub {
my ($attr_name, $params, @related) = @_;
return List::MoreUtils::all { $params->{$attr_name} < $params->{$_} } @related;
},
}
);
Then load MyApp::Types in your class before loading MooseX::Attribute::Dependent and set the dependency on an attribute.
package MyClass; use Moose; use MyApp::Types; use MooseX::Attribute::Dependent; has small => ( is => 'rw', dependency => SmallerThan['large'] ); has large => ( is => 'rw' ); MyClass->new( small => 10, large => 1); # dies MyClass->new( small => 1, large => 10); # lives
When creating your own dependency it is important to know that there is a difference in the parameters passed to the contraint function. If the object is in the process of being created (e.g. MyClass->new(...)) the second parameter is a hashref and consists of the parameters passed to new (actually the return value of BUILDARGS). If the accessor of an attribute with dependency is called to set a value (e.g. $object->small(10)), the second parameter is the object itself ($object).

Moritz Onken

This software is Copyright (c) 2011 by Moritz Onken.
This is free software, licensed under:
The (three-clause) BSD License