File Coverage

blib/lib/MooseX/Role/Validatable.pm
Criterion Covered Total %
statement 51 63 80.9
branch 10 18 55.5
condition n/a
subroutine 14 18 77.7
pod 10 10 100.0
total 85 109 77.9


line stmt bran cond sub pod time code
1             package MooseX::Role::Validatable;
2              
3 1     1   860 use Moose::Role;
  1         4334  
  1         3  
4 1     1   5230 use MooseX::Role::Validatable::Error;
  1         4  
  1         45  
5              
6             our $VERSION = '0.10';
7              
8 1     1   7 use Class::Load qw/load_class/;
  1         2  
  1         50  
9 1     1   6 use Carp qw(confess);
  1         2  
  1         41  
10 1     1   4 use Scalar::Util qw/blessed/;
  1         2  
  1         535  
11              
12             has '_init_errors' => (
13             is => 'ro',
14             isa => 'ArrayRef',
15             init_arg => undef,
16             default => sub { return [] },
17             );
18             has '_validation_errors' => (
19             is => 'ro',
20             isa => 'ArrayRef',
21             init_arg => undef,
22             default => sub { return [] },
23             );
24              
25             has 'error_class' => (
26             is => 'ro',
27             default => sub { 'MooseX::Role::Validatable::Error' },
28             trigger => sub {
29             my $self = shift;
30             load_class($self->error_class);
31             });
32              
33             has validation_methods => (
34             is => 'ro',
35             isa => 'ArrayRef[Str]',
36             lazy_build => 1,
37             );
38              
39             sub _build_validation_methods {
40 1     1   1 my $self = shift;
41 1         4 return [grep { $_ =~ /^_validate_/ } ($self->meta->get_all_method_names)];
  37         1970  
42             }
43              
44             sub all_errors {
45 3     3 1 6 my $self = shift;
46 3         5 return (@{$self->{_init_errors}}, @{$self->{_validation_errors}});
  3         6  
  3         9  
47             }
48              
49             sub all_init_errors {
50 1     1 1 3 return @{(shift)->{_init_errors}};
  1         35  
51             }
52              
53             sub all_validation_errors {
54 0     0 1 0 return @{(shift)->{_validation_errors}};
  0         0  
55             }
56              
57             sub passes_validation {
58 2     2 1 4 my $self = shift;
59 2         5 my @all_errors = $self->all_errors;
60 2 50       13 return (scalar @all_errors) ? 0 : 1;
61             }
62              
63             sub should_alert {
64 0     0 1 0 my $self = shift;
65 0 0       0 return (grep { $_->alert } ($self->all_errors)) ? 1 : 0;
  0         0  
66             }
67              
68             sub confirm_validity {
69 1     1 1 2 my $self = shift;
70             $self->{_validation_errors} = [
71 2         14 map { $self->_errfilter($_) }
72 1         2 map { $self->$_ } @{$self->validation_methods}];
  2         10  
  1         30  
73 1         5 return $self->passes_validation;
74             }
75              
76             sub add_errors {
77 1     1 1 63 my ($self, @errors) = @_;
78 1         2 push @{$self->{_init_errors}}, map { $self->_errfilter($_) } @errors;
  1         3  
  1         2  
79 1         13 return scalar @errors;
80             }
81              
82             sub initialized_correctly {
83 2     2 1 779 my $self = shift;
84 2 100       4 return (@{$self->{_init_errors}}) ? 0 : 1;
  2         11  
85             }
86              
87             sub all_errors_by_severity {
88 0     0 1 0 my $self = shift;
89 0         0 return (sort { $b->severity <=> $a->severity } ($self->all_errors));
  0         0  
90             }
91              
92             sub primary_validation_error {
93 0     0 1 0 my $self = shift;
94              
95 0         0 my @errors = $self->all_errors_by_severity;
96 0 0       0 return unless @errors;
97              
98             # We may wish to do something with perm v. transient here at some point.
99 0         0 return $errors[0];
100             }
101              
102             sub _errfilter {
103 3     3   6 my ($self, $error) = @_;
104 3 50       10 return $error if blessed($error);
105              
106 3 100       9 $error = {message => $error} unless ref($error); # when it's a string
107              
108 3 50       9 confess "Cannot add validation error which is not blessed nor hashref" unless ref($error) eq 'HASH';
109 3 100       7 $error->{message_to_client} = $error->{message} unless exists $error->{message_to_client};
110 3 50       14 $error->{set_by} = caller(1) unless exists $error->{set_by};
111 3         72 return $self->error_class->new($error);
112             }
113              
114 1     1   6 no Moose::Role;
  1         2  
  1         7  
115              
116             1;
117             __END__
118              
119             =encoding utf-8
120              
121             =head1 NAME
122              
123             MooseX::Role::Validatable - Role to add validation to a class
124              
125             =head1 SYNOPSIS
126              
127             package MyClass;
128              
129             use Moose;
130             with 'MooseX::Role::Validatable';
131              
132             has 'attr1' => (is => 'ro', lazy_build => 1);
133              
134             sub _build_attr1 {
135             my $self = shift;
136              
137             # Note initialization errors
138             $self->add_errors( {
139             message => 'Error: blabla',
140             message_to_client => 'Something is wrong!'
141             } ) if 'blabla';
142             }
143              
144             sub _validate_some_other_errors { # _validate_*
145             my $self = shift;
146              
147             my @errors;
148             push @errors, {
149             message => '...',
150             message_to_client => '...',
151             };
152              
153             return @errors;
154             }
155              
156             ## use
157             my $ex = MyClass->new();
158              
159             if (not $ex->initialized_correctly) {
160             my @errors = $ex->all_init_errors();
161             ...; # We didn't even start with good data.
162             }
163              
164             if (not $ex->confirm_validity) { # does not pass those _validate_*
165             my @errors = $ex->all_errors();
166             ...;
167             }
168              
169             =head1 DESCRIPTION
170              
171             MooseX::Role::Validatable is a Moo/Moose role which provides a standard way to add validation to a class.
172              
173             =head1 METHODS
174              
175             =head2 initialized_correctly
176              
177             no error when init the object (no add_errors is called)
178              
179             =head2 add_errors
180              
181             $self->add_errors(...)
182              
183             add errors on those lazy attributes or sub BUILD
184              
185             =head2 confirm_validity
186              
187             run all those B<_validate_*> messages and returns true if no error found.
188              
189             =head2 all_errors
190              
191             An array of the errors currently noted. combined with B<all_init_errors> and B<all_validation_errors>
192              
193             all errors including below methods are instance of error_class, default to L<MooseX::Role::Validatable::Error>
194              
195             =head2 all_init_errors
196              
197             all errors on init
198              
199             =head2 all_validation_errors
200              
201             all errors on validation
202              
203             =head2 all_errors_by_severity
204              
205             order by severity
206              
207             =head2 primary_validation_error
208              
209             the first error of B<all_errors_by_severity>
210              
211             =head2 validation_methods
212              
213             A list of all validation methods available on this object.
214             This can be auto-generated from all methods which begin with
215             "_validate_" which is especially helpful in devleoping new validations.
216              
217             You may wish to set this list directly on the object, if
218             you create and validate a lot of static objects.
219              
220             =head2 error_class
221              
222             default to L<MooseX::Role::Validatable::Error>, override by
223              
224             has '+error_class' => (is => 'ro', default => sub { 'My::Validatable::Error' });
225              
226             # or
227             ->new(error_class => 'My::Validatable::Error');
228              
229             =head2 passes_validation
230              
231             =head2 should_alert
232              
233             =head1 AUTHOR
234              
235             Binary.com E<lt>fayland@binary.comE<gt>
236              
237             =head1 COPYRIGHT
238              
239             Copyright 2014- Binary.com
240              
241             =head1 LICENSE
242              
243             This library is free software; you can redistribute it and/or modify
244             it under the same terms as Perl itself.
245              
246             =head1 SEE ALSO
247              
248             =cut