File Coverage

blib/lib/Declare/Constraints/Simple.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Declare::Constraints::Simple - Declarative Validation of Data Structures
4              
5             =cut
6              
7             package Declare::Constraints::Simple;
8 13     13   427426 use warnings;
  13         32  
  13         460  
9 13     13   76 use strict;
  13         27  
  13         661  
10              
11 13     13   83 use base 'Declare::Constraints::Simple::Library::Exportable';
  13         26  
  13         10108  
12              
13             our $VERSION = 0.03;
14              
15             =head1 SYNOPSIS
16              
17             use Declare::Constraints::Simple-All;
18              
19             my $profile = IsHashRef(
20             -keys => HasLength,
21             -values => IsArrayRef( IsObject ));
22              
23             my $result1 = $profile->(undef);
24             print $result1->message, "\n"; # 'Not a HashRef'
25              
26             my $result2 = $profile->({foo => [23]});
27              
28             print $result2->message, "\n"; # 'Not an Object'
29              
30             print $result2->path, "\n";
31             # 'IsHashRef[val foo].IsArrayRef[0].IsObject'
32              
33             =head1 DESCRIPTION
34              
35             The main purpose of this module is to provide an easy way to build a
36             profile to validate a data structure. It does this by giving you a set of
37             declarative keywords in the importing namespace.
38              
39             =head1 USAGE
40              
41             This is just a brief intro. For details read the documents mentioned in
42             L.
43              
44             =head2 Constraint Import
45              
46             use Declare::Constraints::Simple-All;
47              
48             The above command imports all constraint generators in the library into
49             the current namespace. If you want only a selection, use C:
50              
51             use Declare::Constraints::Simple
52             Only => qw(IsInt Matches And);
53              
54             You can find all constraints (and constraint-like generators, like
55             operators. In fact, C above is an operator. They're both implemented
56             equally, so the distinction is a merely philosophical one) documented in
57             the L pod. In that document you
58             will also find the exact parameters for their usage, so this here is just
59             a brief Intro and not a coverage of all possibilities.
60              
61             =head2 Building a Profile
62              
63             You can use these constraints by building a tree that describes what data
64             structure you expect. Every constraint can be used as sub-constraint, as
65             parent, if it accepts other constraints, or stand-alone. If you'd just
66             say
67              
68             my $check = IsInt;
69             print "yes!\n" if $check->(23);
70              
71             it will work too. This also allows predefining tree segments, and nesting
72             them:
73              
74             my $id_to_objects = IsArrayRef(IsObject);
75              
76             Here C<$id_to_objects> would give it's OK on an array reference
77             containing a list of objects. But what if we now decide that we actually
78             want a hashref containing two lists of objects? Behold:
79              
80             my $object_lists =
81             IsHashRef( HasAllKeys( qw(good bad) ),
82             OnHashKeys( good => $id_to_objects,
83             bad => $id_to_objects ));
84              
85             As you can see, constraints like C and C allow you
86             to apply constraints to their keys and values. With this, you can step
87             down in the data structure.
88              
89             =head2 Applying a Profile to a Data Structure
90              
91             Constraints return just code references that can be applied to one value
92             (and only one value) like this:
93              
94             my $result = $object_lists->($value);
95              
96             After this call C<$result> contains a
97             L object. The first think one wants
98             to know is if the validation succeeded:
99              
100             if ($result->is_valid) { ... }
101              
102             This is pretty straight forward. To shorten things the result object also
103             Ls it's Cean context. This means you can alternatively
104             just say
105              
106             if ($result) { ... }
107              
108             However, if the result indicates a invalid data structure, we have a few
109             options to find out what went wrong. There's a human parsable message in
110             the C accessor. You can override these by forcing it to a
111             message in a subtree with the C declaration. The C
112             contains the name of the chain of constraints up to the point of failure.
113              
114             You can use the C accessor for a joined string path representing
115             the stack.
116              
117             =head2 Creating your own Libraries
118              
119             You can declare a package as a library with
120              
121             use Declare::Constraints::Simple-Library;
122              
123             which will install the base class and helper methods to define
124             constraints. For a complete list read the documentation in
125             L. You can use other
126             libraries as base classes to include their constraints in your export
127             possibilities. This means that with a package setup like
128              
129             package MyLibrary;
130             use warnings;
131             use strict;
132              
133             use Declare::Constraints::Simple-Library;
134             use base 'Declare::Constraints::Simple::Library';
135              
136             constraint 'MyConstraint',
137             sub { return _result(($_[0] >= 12), 'Value too small') };
138              
139             1;
140              
141             you can do
142              
143             use MyLibrary-All;
144              
145             and have all constraints, from the default library and yours from above,
146             installed into your requesting namespace. You can override a constraint
147             just by redeclaring it in a subclass.
148              
149             =head2 Scoping
150              
151             Sometimes you want to validate parts of a data structure depending on
152             another part of it. As of version 2.0 you can declare scopes and store
153             results in them. Here is a complete example:
154              
155             my $constraint =
156             Scope('foo',
157             And(
158             HasAllKeys( qw(cmd data) ),
159             OnHashKeys(
160             cmd => Or( SetResult('foo', 'cmd_a',
161             IsEq('FOO_A')),
162             SetResult('foo', 'cmd_b',
163             IsEq('FOO_B')) ),
164             data => Or( And( IsValid('foo', 'cmd_a'),
165             IsArrayRef( IsInt )),
166             And( IsValid('foo', 'cmd_b'),
167             IsRegex )) )));
168              
169             This profile would accept a hash references with the keys C and
170             C. If C is set to C, then C has to be an array
171             ref of integers. But if C is set to C, a regular expression
172             is expected.
173              
174             =head1 SEE ALSO
175              
176             L,
177             L,
178             L,
179             L
180              
181             =head1 REQUIRES
182              
183             L, L, L, L,
184             L and L (for build).
185              
186             =head1 TODO
187              
188             =over
189              
190             =item *
191              
192             Examples.
193              
194             =item *
195              
196             A list of questions that might come up, together with their answers.
197              
198             =item *
199              
200             A C constraint that takes a code reference.
201              
202             =item *
203              
204             Create stack objects that stringify to the current form, but can hold
205             more data.
206              
207             =item *
208              
209             Give the C constraint the ability to get the generated
210             constraint inserted in the message. A possibility would be to replace
211             __Value__ and __Message__. It might also accept code references, which
212             return strings.
213              
214             =item *
215              
216             Allow the C constraint to accept further constraints. One
217             might like to check, for example, the refaddr of a closure.
218              
219             =item *
220              
221             A C constraint that takes a regex and can apply other
222             constraints to the matches.
223              
224             =item *
225              
226             ???
227              
228             =item *
229              
230             Profit.
231              
232             =back
233              
234             =head1 INSTALLATION
235              
236             perl Makefile.PL
237             make
238             make test
239             make install
240              
241             For details read L.
242              
243             =head1 AUTHOR
244              
245             Robert 'phaylon' Sedlacek Cphaylon@dunkelheit.atE>
246              
247             =head1 LICENSE AND COPYRIGHT
248              
249             This module is free software, you can redistribute it and/or modify it
250             under the same terms as perl itself.
251              
252             =cut
253              
254             1;