File: README

package info (click to toggle)
libdeclare-constraints-simple-perl 0.03-1.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, sid
  • size: 300 kB
  • sloc: perl: 2,068; makefile: 2
file content (204 lines) | stat: -rw-r--r-- 7,054 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
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.