File Coverage

blib/lib/Brick/Result.pm
Criterion Covered Total %
statement 18 105 17.1
branch 0 42 0.0
condition 0 6 0.0
subroutine 6 12 50.0
pod 6 6 100.0
total 30 171 17.5


line stmt bran cond sub pod time code
1             package Brick::Result;
2 2     2   2464 use strict;
  2         5  
  2         78  
3              
4 2     2   12 use vars qw($VERSION);
  2         5  
  2         99  
5              
6 2     2   13 use Carp qw(carp croak);
  2         4  
  2         263  
7              
8             $VERSION = '0.228';
9              
10             =encoding utf8
11              
12             =head1 NAME
13              
14             Brick::Result - the result of applying a profile
15              
16             =head1 SYNOPSIS
17              
18             use Brick;
19              
20             my $result = $brick->apply( $Profile, $Input );
21              
22             $result->explain;
23              
24             =head1 DESCRIPTION
25              
26             This class provides methods to turn the data structure returned
27             by apply() into a useable form for particular situations.
28              
29              
30             =head2 Class methods
31              
32             =over 4
33              
34             =item result_item_class
35              
36             Loads and returns the class name to use for the elements of the Results
37             data structure.
38              
39             =cut
40              
41 0     0 1   sub result_item_class { require Brick::Result::Item; 'Brick::Result::Item' };
  0            
42              
43             =back
44              
45             =head2 Instance methods
46              
47             =over
48              
49             =item explain
50              
51             Create a string the shows the result in an outline form.
52              
53             =cut
54              
55              
56             # for the $pair thing in explain
57 2     2   16 use constant LEVEL => 0;
  2         7  
  2         188  
58 2     2   18 use constant MESSAGE => 1;
  2         5  
  2         727  
59              
60              
61             sub explain
62             {
63 0     0 1   my( $result_set ) = @_;
64              
65 0           my $str = '';
66              
67 0           foreach my $element ( @$result_set )
68             {
69 0           my $level = 0;
70              
71 0           $str .= "$$element[0]: " . do {
72 0 0         if( $element->passed ) { "passed " }
  0 0          
    0          
73 0           elsif( $element->is_validation_error ) { "failed " }
74 0           elsif( $element->is_code_error ) { "code error in " }
75             };
76              
77 0           $str .= $element->get_method() . "\n";
78              
79 0 0         if( $element->passed )
80             {
81 0           $str .= "\n";
82 0           next;
83             }
84              
85             # this descends into the error tree (without using recursion
86 0           my @uses = ( [ $level, $element->get_messages ] );
87              
88 0           while( my $pair = shift @uses )
89             {
90             # is it a single error or a composition?
91 0 0         if( ! ref $pair->[ MESSAGE ] )
    0          
    0          
92             {
93 0           $str .= $pair->[ MESSAGE ] . "foo";
94             }
95             elsif( ! ref $pair->[ MESSAGE ] eq ref {} )
96             {
97 0           next;
98             }
99             elsif( exists $pair->[ MESSAGE ]->{errors} )
100             {
101             # something else to process, but put it back into @uses
102             unshift @uses, map {
103 0           [ $pair->[ LEVEL ] + 1, $_ ]
104 0           } @{ $pair->[ MESSAGE ]->{errors} };
  0            
105             }
106             else
107             {
108             # this could come back as an array ref instead of a string
109 2     2   17 no warnings 'uninitialized';
  2         6  
  2         1524  
110             $str .= "\t" . #x $pair->[ LEVEL ] .
111 0           join( ": ", @{ $pair->[ MESSAGE ]
112 0           }{qw(failed_field handler message)} ) . "\n";
113             }
114              
115             }
116              
117 0           $str.= "\n";
118             }
119              
120 0           $str;
121             }
122              
123             =item flatten
124              
125             Collapse the result structure to an array of flat hashes.
126              
127             =cut
128              
129             sub flatten
130             {
131 0     0 1   my( $result_set ) = @_;
132              
133 0           my $str = '';
134              
135 0           my @flatten;
136              
137 0           foreach my $element ( @$result_set ) # one element per profile element
138             {
139 0           bless $element, $result_set->result_item_class;
140 0 0         next if $element->passed;
141 0           my $constraint = $element->get_method;
142              
143 0           my @uses = ( $element->get_messages );
144              
145 0           while( my $hash = shift @uses )
146             {
147 0 0         if( ! ref $hash eq ref {} )
148             {
149 0           carp "Non-hash reference in messages result key! Skipping";
150 0           next;
151             }
152              
153             # is it a single error or a composition?
154 0 0         unless( ref $hash )
    0          
155             {
156 0           next;
157             }
158 0           elsif( exists $hash->{errors} )
159             {
160 0           unshift @uses, @{ $hash->{errors} };
  0            
161             }
162             else
163             {
164 0           push @flatten, { %$hash, constraint => $constraint };
165             }
166              
167             }
168              
169             }
170              
171 0           \@flatten;
172             }
173              
174             =item flatten_by_field
175              
176             Similar to flatten, but keyed by the field that failed the constraint.
177              
178             =cut
179              
180             sub flatten_by_field
181             {
182 0     0 1   my( $result_set ) = @_;
183              
184 0           my $str = '';
185              
186 0           my %flatten;
187             my %Seen;
188              
189 0           foreach my $element ( @$result_set ) # one element per profile element
190             {
191 0 0         next if $element->passed;
192 0           my $constraint = $element->get_method;
193              
194 0           my @uses = ( $element->get_messages );
195              
196 0           while( my $hash = shift @uses )
197             {
198             # is it a single error or a composition?
199 0 0         unless( ref $hash )
    0          
200             {
201 0           next;
202             }
203 0           elsif( exists $hash->{errors} )
204             {
205 0           unshift @uses, @{ $hash->{errors} };
  0            
206             }
207             else
208             {
209 0           my $field = $hash->{failed_field};
210 0 0 0       next if $hash->{handler} and $Seen{$field}{$hash->{handler}}++;
211 0 0         $flatten{ $field } = [] unless exists $flatten{ $field };
212 0           push @{ $flatten{ $field } },
  0            
213             { %$hash, constraint => $constraint };
214 0           $Seen{$field}{$hash->{handler}}++;
215             }
216              
217             }
218              
219             }
220              
221 0           \%flatten;
222             }
223              
224             =item flatten_by
225              
226             Similar to flatten, but keyed by the hash key named in the argument list.
227              
228             =cut
229              
230             sub flatten_by
231             {
232 0     0 1   my( $result_set, $key ) = @_;
233              
234 0           my $str = '';
235              
236 0           my %flatten;
237             my %Seen;
238              
239 0           foreach my $element ( @$result_set ) # one element per profile element
240             {
241 0 0         next if $element->passed;
242 0           my $constraint = $element->get_method;
243              
244 0           my @uses = ( $element->get_messages );
245              
246 0           while( my $hash = shift @uses )
247             {
248             # is it a single error or a composition?
249 0 0         unless( ref $hash )
    0          
250             {
251 0           next;
252             }
253 0           elsif( exists $hash->{errors} )
254             {
255 0           unshift @uses, @{ $hash->{errors} };
  0            
256             }
257             else
258             {
259 0           my $field = $hash->{$key};
260 0 0 0       next if $hash->{handler} and $Seen{$field}{$hash->{handler}}++;
261 0 0         $flatten{ $field } = [] unless exists $flatten{ $field };
262 0           push @{ $flatten{ $field } },
  0            
263             { %$hash, constraint => $constraint };
264 0           $Seen{$field}{$hash->{handler}}++;
265             }
266              
267             }
268              
269             }
270              
271 0           \%flatten;
272             }
273              
274             =item dump
275              
276             What should this do?
277              
278             =cut
279              
280 0     0 1   sub dump { croak "Not yet implemented" }
281              
282             =back
283              
284             =head1 TO DO
285              
286             TBA
287              
288             =head1 SEE ALSO
289              
290             L, L
291              
292             =head1 SOURCE AVAILABILITY
293              
294             This source is in Github:
295              
296             https://github.com/briandfoy/brick
297              
298             =head1 AUTHOR
299              
300             brian d foy, C<< >>
301              
302             =head1 COPYRIGHT
303              
304             Copyright © 2007-2018, brian d foy . All rights reserved.
305              
306             You may redistribute this under the terms of the Artistic License 2.0.
307              
308             =cut
309              
310             1;