File Coverage

blib/lib/Brick/General.pm
Criterion Covered Total %
statement 18 100 18.0
branch 0 18 0.0
condition 0 22 0.0
subroutine 6 30 20.0
pod 0 7 0.0
total 24 177 13.5


line stmt bran cond sub pod time code
1             package Brick::General;
2 5     5   56 use strict;
  5         8  
  5         154  
3              
4 5     5   43 use base qw(Exporter);
  5         9  
  5         515  
5 5     5   29 use vars qw($VERSION);
  5         7  
  5         278  
6              
7             $VERSION = '0.902';
8              
9             package Brick::Bucket;
10 5     5   27 use strict;
  5         6  
  5         110  
11              
12 5     5   51 use Carp qw(croak confess);
  5         9  
  5         3962  
13              
14             =encoding utf8
15              
16             =head1 NAME
17              
18             Brick::General - constraints for domain-nonspecific stuff
19              
20             =head1 SYNOPSIS
21              
22             use Brick;
23              
24             =head1 DESCRIPTION
25              
26             =head2 Single fields
27              
28             =over 4
29              
30             =item _is_blank( HASHREF )
31              
32              
33             =cut
34              
35             sub _is_blank
36             {
37 0     0     my( $bucket, $setup ) = @_;
38              
39 0           $setup->{fields} = [ $setup->{field} ];
40              
41 0           $bucket->_fields_are_blank( $setup );
42             }
43              
44             =item _is_true( HASHREF )
45              
46              
47             =cut
48              
49             sub _is_true
50             {
51 0     0     my( $bucket, $setup ) = @_;
52              
53 0           $setup->{fields} = [ $setup->{field} ];
54              
55 0           $bucket->_fields_are_true( $setup );
56             }
57              
58              
59             =item _is_defined( HASHREF )
60              
61              
62             =cut
63              
64             sub _is_defined
65             {
66 0     0     my( $bucket, $setup ) = @_;
67              
68 0           $setup->{fields} = [ $setup->{field} ];
69              
70 0           $bucket->_fields_are_defined( $setup );
71             }
72              
73             =back
74              
75             =head2 Multiple field conditions
76              
77             =over 4
78              
79             =item defined_fields( HASHREF )
80              
81             A wrapper around __fields_are_something to supply the code reference
82             to verify that each field for definedness. It takes the same input.
83              
84             =cut
85              
86              
87             sub defined_fields
88             {
89 0     0 0   my( $bucket, $setup ) = @_;
90              
91 0           my $sub = $bucket->_fields_are_defined( $setup );
92 0           $bucket->__make_constraint( $sub, $setup );
93             }
94              
95             =item true_fields( HASHREF )
96              
97             A wrapper around __fields_are_something to supply the code reference
98             to verify that each field for true values. It takes the same input.
99              
100             =cut
101              
102             sub true_fields
103             {
104 0     0 0   my( $bucket, $setup ) = @_;
105              
106 0           my $sub = $bucket->_fields_are_true( $setup );
107 0           $bucket->__make_constraint( $sub, $setup );
108             }
109              
110             =item false_fields( HASHREF )
111              
112             A wrapper around __fields_are_something to supply the code reference
113             to verify that each field for false values. It takes the same input.
114              
115             =cut
116              
117             sub false_fields
118             {
119 0     0 0   my( $bucket, $setup ) = @_;
120              
121 0           my $sub = $bucket->_fields_are_false( $setup );
122 0           $bucket->__make_constraint( $sub, $setup );
123             }
124              
125             =item blank_fields( HASHREF )
126              
127             A wrapper around __fields_are_something to supply the code reference
128             to verify that each field has blank values. It takes the same input.
129              
130             =cut
131              
132             sub blank_fields
133             {
134 0     0 0   my( $bucket, $setup ) = @_;
135              
136 0           my $sub = $bucket->_fields_are_blank( $setup );
137 0           $bucket->__make_constraint( $sub, $setup );
138             }
139              
140             =item exist_fields( HASHREF )
141              
142             A wrapper around __fields_are_something to supply the code reference
143             to verify that each field has blank values. It takes the same input.
144              
145             =cut
146              
147             sub exist_fields
148             {
149 0     0 0   my( $bucket, $setup ) = @_;
150              
151 0           my $sub = $bucket->_fields_exist( $setup );
152 0           $bucket->__make_constraint( $sub, $setup );
153             }
154              
155             =item allowed_fields( HASHREF )
156              
157             A wrapper around _remove_extra_fields to remove anything not in the
158             list of the key 'allowed_fields' in HASHREF.
159              
160             This constraint only cares about fields that do not belong in the
161             input. It does not, for instance, ensure that all the fields that
162             should be there are. Use required fields for that.
163              
164             =cut
165              
166             sub allowed_fields
167             {
168 0     0 0   my( $bucket, $setup ) = @_;
169              
170             my $filter_sub = $bucket->_remove_extra_fields(
171             {
172             %$setup,
173             filter_fields => $setup->{allowed_fields}
174             }
175 0           );
176              
177 0           $bucket->__make_constraint( $filter_sub, $setup );
178             }
179              
180             =item required_fields( HASHREF )
181              
182             A wrapper around _fields_are_defined_and_not_null_string to check for
183             the presence of the required fields. A required field must exist in
184             the input hash and have a defined value that is not the null string.
185              
186             =cut
187              
188             sub required_fields
189             {
190 0     0 0   my( $bucket, $setup ) = @_;
191              
192             my $sub = $bucket->_fields_are_defined_and_not_null_string(
193             {
194             %$setup,
195             fields => $setup->{required_fields},
196             }
197 0           );
198              
199 0           $bucket->__make_constraint( $sub, $setup );
200             }
201              
202             =item _fields_exist( HASHREF )
203              
204             fields - an anonymous array of fields that must exist in input
205              
206             If all of the fields satisfy the condition, it does not die. If some of the
207             fields do not satisfy the condition, it dies with a hash reference whose keys
208             are:
209              
210             message - message about the error
211             errors - anonymous array of fields that failed the condition
212             handler - anonymous array of fields that satisfy the condition
213              
214             If a code error occurs, it dies with a simple scalar.
215              
216             =cut
217              
218             sub _fields_exist
219             {
220 0     0     my( $bucket, $setup, $sub ) = @_;
221              
222 0           my @caller = $bucket->__caller_chain_as_list();
223              
224             #print STDERR Data::Dumper->Dump( [\@caller], [qw(caller)] );
225              
226 0 0 0       unless( eval { $setup->{fields}->isa( ref [] ) } or
  0            
227             UNIVERSAL::isa( $setup->{fields}, ref [] ) )
228             {
229 0           croak( "Argument to $caller[0]{'sub'} must be an anonymous array of field names!" );
230             }
231              
232             my $composed = $bucket->add_to_bucket ( {
233             name => $setup->{name} || $caller[0]{'sub'},
234             description => ( $setup->{description} || "Fields exist" ),
235             fields => [ $setup->{fields} ],
236             code => sub {
237 0     0     my @errors;
238             my @missing;
239 0           foreach my $f ( @{ $setup->{fields} } )
  0            
240             {
241 0 0         next if exists $_[0]->{ $f };
242              
243             push @errors, {
244 0   0       handler => $caller[1]{'sub'} || $caller[0]{'sub'},
245             message => "Field [$f] was not in input",
246             };
247              
248 0           push @missing, $f;
249             }
250              
251             die {
252             message => "These fields were missing in the input: [@missing]",
253             errors => \@errors,
254 0 0 0       handler => $caller[1]{'sub'} || $caller[0]{'sub'},
255             } if @missing;
256             },
257 0   0       } );
      0        
258              
259 0           $bucket->comprise( $composed, $sub );
260              
261 0           $composed;
262             }
263              
264             =item __fields_are_something( HASHREF, CODEREF )
265              
266             Applies CODEREF to all of the fields in HASHREF->{fields}.
267              
268             fields - an anonymous array of fields to apply CODEREF to
269             description - a textual description of the test (has default)
270             test_name - short (couple word) description of test (e.g. "defined")
271              
272             If all of the fields satisfy the condition, it does not die. If some of the
273             fields do not satisfy the condition, it dies with a hash reference whose keys
274             are:
275              
276             message - message about the error
277             errors - anonymous array of fields that failed the condition
278             handler - anonymous array of fields that satisfy the condition
279              
280             If a code error occurs, it dies with a simple scalar.
281              
282             =cut
283              
284             sub __fields_are_something
285             {
286 0     0     my( $bucket, $setup, $sub ) = @_;
287              
288 0           my @caller = $bucket->__caller_chain_as_list();
289              
290 0 0 0       unless( eval { $setup->{fields}->isa( ref [] ) } or
  0            
291             UNIVERSAL::isa( $setup->{fields}, ref [] ) )
292             {
293 0           croak( "Argument to $caller[0]{'sub'} must be an anonymous array of field names!" );
294             }
295              
296             my $composed = $bucket->add_to_bucket ( {
297             name => $setup->{name} || $caller[0]{'sub'},
298             description => ( $setup->{description} || "Fields exist" ),
299             fields => [ $setup->{fields} ],
300             code => sub {
301              
302             #print STDERR Data::Dumper->Dump( [$_[0]], [qw(input)] );
303 0     0     my @errors;
304             my @bad;
305 0           foreach my $f ( @{ $setup->{fields} } )
  0            
306             {
307 5     5   58 no warnings 'uninitialized';
  5         9  
  5         2639  
308             #print STDERR "Checking field $f ... ";
309 0           my $result = $sub->( $_[0]->{$f} );
310             #print STDERR "$result\n";
311 0           my $at = $@;
312              
313             push @errors, {
314 0 0         handler => $caller[1]{'sub'},
315             message => "Field [$f] was not $setup->{test_name}. It was [$_[0]->{$f}]",
316             } unless $result;
317              
318 0 0         push @bad, $f unless $result;
319             }
320              
321             die {
322             message => "Not all fields were $setup->{test_name}: [@bad]",
323             errors => \@errors,
324 0 0         handler => $caller[0]{'sub'},
325             } if @bad;
326              
327 0           return 1;
328             },
329 0   0       } );
      0        
330              
331 0           $bucket->comprise( $composed, $sub );
332              
333 0           $composed;
334             }
335              
336             =item _fields_are_defined_and_not_null_string( HASHREF )
337              
338             Check that all fields in HASHREF->{fields) are defined and
339             have a true value. See __fields_are_something for details.
340              
341             =cut
342              
343             sub _fields_are_defined_and_not_null_string
344             {
345 0     0     my( $bucket, $setup ) = @_;
346              
347             #print STDERR "_fields_are_defined_and_not_null_string: ", Data::Dumper->Dump( [$setup], [qw(setup)] );
348              
349 0           $setup->{test_name} = 'defined but not null';
350              
351 0 0   0     $bucket->__fields_are_something( $setup, sub { defined $_[0] and $_[0] ne '' } );
  0            
352             }
353              
354              
355             =item _fields_are_defined( HASHREF )
356              
357             Check that all fields in HASHREF->{fields) are defined. See
358             __fields_are_something for details.
359              
360             =cut
361              
362             sub _fields_are_defined
363             {
364 0     0     my( $bucket, $setup ) = @_;
365              
366 0           $setup->{test_name} = 'defined';
367              
368 0     0     $bucket->__fields_are_something( $setup, sub { defined $_[0] } );
  0            
369             }
370              
371             =item _fields_are_blank( HASHREF )
372              
373             Check that all fields in HASHREF->{fields) are blank (either
374             undefined or the empty string). See __fields_are_something for details.
375              
376             =cut
377              
378             sub _fields_are_blank
379             {
380 0     0     my( $bucket, $setup ) = @_;
381              
382 0           $setup->{test_name} = 'blank';
383              
384 0 0   0     $bucket->__fields_are_something( $setup, sub { ! defined $_[0] or $_[0] eq '' } );
  0            
385             }
386              
387             =item _fields_are_false( HASHREF )
388              
389             Check that all fields in HASHREF->{fields) are false (in the Perl
390             sense). See __fields_are_something for details.
391              
392             =cut
393              
394             sub _fields_are_false
395             {
396 0     0     my( $bucket, $setup ) = @_;
397              
398 0           $setup->{test_name} = 'false';
399              
400 0     0     $bucket->__fields_are_something( $setup, sub { ! $_[0] } );
  0            
401             }
402              
403             =item _fields_are_true( HASHREF )
404              
405             Check that all fields in HASHREF->{fields) are true (in the Perl
406             sense). See __fields_are_something for details.
407              
408             =cut
409              
410             sub _fields_are_true
411             {
412 0     0     my( $bucket, $setup ) = @_;
413              
414 0           $setup->{test_name} = 'true';
415              
416 0     0     $bucket->__fields_are_something( $setup, sub { $_[0] } );
  0            
417             }
418              
419             =back
420              
421             =head1 TO DO
422              
423             TBA
424              
425             =head1 SEE ALSO
426              
427             TBA
428              
429             =head1 SOURCE AVAILABILITY
430              
431             This source is in Github:
432              
433             https://github.com/briandfoy/brick
434              
435             =head1 AUTHOR
436              
437             brian d foy, C<< >>
438              
439             =head1 COPYRIGHT
440              
441             Copyright © 2007-2022, brian d foy . All rights reserved.
442              
443             You may redistribute this under the terms of the Artistic License 2.0.
444              
445             =cut
446              
447             1;