++ed by:

1 non-PAUSE user.

Author image brian d foy


Data::Constraint - prototypical value checking


        use Data::Constraint;

        my $constraint = Data::Constraint->add_constraint(
                run         => sub { $_[1] =~ /Perl/ },
                description => "String should have 'Perl' in it";

        if( $constraint->check( 'Java' ) )


A constraint is some sort of condition on a datum. This module checks one condition against one value at a time, and I call the thing that checks that condition the "constraint". A constraint returns true or false, and that's it. It should have no side effects, it should not change program flow, and it should mind its own business. Let the thing that calls the constraint figure out what to do with it. I want something that says "yes" or "no" (and I discuss why this needs a fancy module later).

For instance, the constraint may state that the value has to be a number. The condition may be something that ensures the value does not have non-digits.

        $value =~ /^\d+\z/

The value may have additional constraints, such as a lower limit.

        $value > $minimum

Although I designed constraints to be a single condition, you may want to create contraints that check more than one thing.

        $value > $minimum and $value < $maximum

In the previous examples, we could tell what was wrong with the value if the return value was false: the value didn't satisfy it's single condition. If it was supposed to be all digits and wasn't, then it had non-digits. If it was supposed to be greater than the minimum value, but wasn't, it was less than (or equal to) the minimal value. With more than one condition, like the last example, I cannot tell which one failed. I might be able to say that a value of out of range, but I think it is nicer to know if the value should have been larger or smaller so I can pass that on to the user. Having said that, I give you enough rope to do what you wish.

Why I need a fancy, high-falutin' module

This module is a sub-class of Class::Prototyped. In brief, that means constraints are class-objects even if they don't look like they are. Each constraint is a self-contained class, and I can modify a constraint by adding data and behaviour without affecting any of the other constraints. I can also make a list of constraints that I store for later use (also known as "delayed" execution).

Several data may need the same conditions, so they can share the same constraint. Other data that need different constraints can get their own, or modify copies of ones that exist.

I can also associate several constraints with some data, and each one has its own constraint. In the compelling case for this module, I needed to generate different warnings for different failures.

Interacting with a constraint

I can get a constraint object by asking for it.

        my $constraint = Data::Constraint->get_by_name( $name );

If no constraint has that name, I get back the default constraint which always returns true. Or should it be false? I guess that depends on what you are doing.

If I don't know which constraints exist, I can get all the names. The names are just simple strings, so they have no magic. Maybe this should be a hash so you can immediately use the value of the key you want.

        my @names = Data::Constraint->get_all_names;

Once I have the constraint, I give it a value to check if

        $constraint->check( $value );

I can do this all in one step.

        Data::Constraint->get_by_name( $name )->check( $value );

Predefined constraints

I previously had some pre-loaded contraints (defined, ordinal, and test) but that got in the way of things that didn't want them. You can still find them defined in the test files though.

Adding a new constraint

Add a new constraint with the class method add_constraint. The first argument is the name you want to give the constraint. The rest of the arguments are optional, although I need to add a run key if I want the constraint to do anything useful: its value should be something that returns true when the value satisfies the condition (so a constant is probably not what you want). An anonymous subroutine is probably what you want.

                'run' => sub {...},
                [ @optional_arguments ],

Once I create the constraint, it exists forever (for now). I get back the constraint object:

        my $constraint = Data::Constraint->add_constraint( ... );

The object sticks around after $constraint goes out of scope. The $constraint is just a reference to the object. I can get another reference to it through get_by_name(). See "Deleting a constraint" if you want to get rid of them.

Modifying a constraint

Um, don't do that yet unless you know what you are doing.

Deleting a constraint

        Data::Constraint->delete_by_name( $name );


Doing anything you want

You wish! This module can't help you there.


check( VALUE )

Apply the constraint to the VALUE.

add_constraint( NAME, KEY-VALUES )

Added a constraint with name NAME. Possible keys and values:

        run            reference to subroutine to run
        description    string that decribes the constraint


                'run'       => sub {...},
                description => 'This is what I do",

Return a list of all the defined constraints.

get_by_name( CONSTRAINT_NAME )

Return the constraint with name CONSTRAINT_NAME. This is

delete_by_name( CONSTRAINT_NAME )

Delete the constraint with name CONSTRAINT_NAME. It's no longer available.


Delete all the constraints, even the default ones.


Return the description. The default description is the empty string. You should supply your own description with add_constraint.


Return the description. The default description is the empty string. You should supply your own description with add_constraint.


This source is in Github:



brian d foy, <bdfoy@cpan.org>


Copyright © 2004-2021, brian d foy <bdfoy@cpan.org>. All rights reserved.

This program is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.