---
name: "Declare::Constraints::Simple"
section: "3pm"
platform: "linux"
package: "libdeclare-constraints-simple-perl"
version: "0.03-1.1"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/Declare::Constraints::Simple"
---

# Declare::Constraints::Simple(3pm)

Declarative Validation of Data Structures

## NAME

Declare::Constraints::Simple - Declarative Validation of Data Structures

## SYNOPSIS

```
  use Declare::Constraints::Simple-All;
  my $profile = IsHashRef(
                    -keys   => HasLength,
                    -values => IsArrayRef( IsObject ));
  my $result1 = $profile->(undef);
  print $result1->message, "\n";    # 'Not a HashRef'
  my $result2 = $profile->({foo => [23]});
  print $result2->message, "\n";    # 'Not an Object'
  print $result2->path, "\n";
                    # 'IsHashRef[val foo].IsArrayRef[0].IsObject'
```

## DESCRIPTION

The main purpose of this module is to provide an easy way to build a profile to validate a data structure. It does this by giving you a set of declarative keywords in the importing namespace.

## USAGE

This is just a brief intro. For details read the documents mentioned in "SEE ALSO".

### Constraint Import

```
  use Declare::Constraints::Simple-All;
```

The above command imports all constraint generators in the library into the current namespace. If you want only a selection, use `"only"`:

```
  use Declare::Constraints::Simple
      Only => qw(IsInt Matches And);
```

You can find all constraints (and constraint-like generators, like operators. In fact, `"And"` above is an operator. They're both implemented equally, so the distinction is a merely philosophical one) documented in the Declare::Constraints::Simple::Library pod. In that document you will also find the exact parameters for their usage, so this here is just a brief Intro and not a coverage of all possibilities.

### Building a Profile

You can use these constraints by building a tree that describes what data structure you expect. Every constraint can be used as sub-constraint, as parent, if it accepts other constraints, or stand-alone. If you'd just  say

```
  my $check = IsInt;
  print "yes!\n" if $check->(23);
```

it will work too. This also allows predefining tree segments, and nesting them:

```
  my $id_to_objects = IsArrayRef(IsObject);
```

Here `$id_to_objects` would give it's OK on an array reference  containing a list of objects. But what if we now decide that we actually  want a hashref containing two lists of objects? Behold:

```
  my $object_lists =
    IsHashRef( HasAllKeys( qw(good bad) ),
               OnHashKeys( good => $id_to_objects,
                           bad  => $id_to_objects ));
```

As you can see, constraints like `"IsArrayRef"` and `"IsHashRef"` allow you to apply constraints to their keys and values. With this, you can step down in the data structure.

### Applying a Profile to a Data Structure

Constraints return just code references that can be applied to one value (and only one value) like this:

```
  my $result = $object_lists->($value);
```

After this call `$result` contains a Declare::Constraints::Simple::Result object. The first think one wants to know is if the validation succeeded:

```
  if ($result->is_valid) { ... }
```

This is pretty straight forward. To shorten things the result object also overloads it's `"bool"`ean context. This means you can alternatively just say

```
  if ($result) { ... }
```

However, if the result indicates a invalid data structure, we have a few options to find out what went wrong. There's a human parsable message in the `"message"` accessor. You can override these by forcing it to a  message in a subtree with the `"Message"` declaration. The `"stack"`  contains the name of the chain of constraints up to the point of failure.

You can use the `"path"` accessor for a joined string path representing  the stack.

### Creating your own Libraries

You can declare a package as a library with

```
  use Declare::Constraints::Simple-Library;
```

which will install the base class and helper methods to define constraints. For a complete list read the documentation in Declare::Constraints::Simple::Library::Base. You can use other libraries as base classes to include their constraints in your export possibilities. This means that with a package setup like

```
  package MyLibrary;
  use warnings;
  use strict;
  use Declare::Constraints::Simple-Library;
  use base 'Declare::Constraints::Simple::Library';
  constraint 'MyConstraint',
    sub { return _result(($_[0] >= 12), 'Value too small') };
  1;
```

you can do

```
  use MyLibrary-All;
```

and have all constraints, from the default library and yours from above, installed into your requesting namespace. You can override a constraint just by redeclaring it in a subclass.

### Scoping

Sometimes you want to validate parts of a data structure depending on another part of it. As of version 2.0 you can declare scopes and store results in them. Here is a complete example:

```
  my $constraint =
    Scope('foo',
      And(
        HasAllKeys( qw(cmd data) ),
        OnHashKeys(
          cmd => Or( SetResult('foo', 'cmd_a',
                       IsEq('FOO_A')),
                     SetResult('foo', 'cmd_b',
                       IsEq('FOO_B')) ),
          data => Or( And( IsValid('foo', 'cmd_a'),
                           IsArrayRef( IsInt )),
                      And( IsValid('foo', 'cmd_b'),
                           IsRegex )) )));
```

This profile would accept a hash references with the keys `"cmd"` and `"data"`. If `"cmd"` is set to `"FOO_A"`, then `"data"` has to be an array  ref of integers. But if `"cmd"` is set to `"FOO_B"`, a regular expression  is expected.

## SEE ALSO

Declare::Constraints::Simple::Library,  Declare::Constraints::Simple::Result, Declare::Constraints::Simple::Base, Module::Install

## REQUIRES

Carp::Clan, aliased, Class::Inspector, Scalar::Util, overload and Test::More (for build).

## TODO

- •

  Examples.

- •

  A list of questions that might come up, together with their answers.

- •

  A `"Custom"` constraint that takes a code reference.

- •

  Create stack objects that stringify to the current form, but can hold more data.

- •

  Give the `"Message"` constraint the ability to get the generated  constraint inserted in the message. A possibility would be to replace  \_\_Value\_\_ and \_\_Message\_\_. It might also accept code references, which  return strings.

- •

  Allow the `"IsCodeRef"` constraint to accept further constraints. One  might like to check, for example, the refaddr of a closure.

- •

  A `"Captures"` constraint that takes a regex and can apply other constraints to the matches.

- •

  ???

- •

  Profit.

## INSTALLATION

```
  perl Makefile.PL
  make
  make test
  make install
```

For details read Module::Install.

## AUTHOR

Robert 'phaylon' Sedlacek `"<phaylon@dunkelheit.at>"`

## LICENSE AND COPYRIGHT

This module is free software, you can redistribute it and/or modify it  under the same terms as perl itself.
