File Coverage

blib/lib/Poz/Types/union.pm
Criterion Covered Total %
statement 58 59 98.3
branch 14 16 87.5
condition 3 3 100.0
subroutine 12 12 100.0
pod 5 5 100.0
total 92 95 96.8


line stmt bran cond sub pod time code
1             package Poz::Types::union;
2 11     11   184 use 5.032;
  11         39  
3 11     11   57 use strict;
  11         18  
  11         267  
4 11     11   41 use warnings;
  11         19  
  11         478  
5 11     11   51 use Carp ();
  11         26  
  11         281  
6 11     11   48 use Try::Tiny;
  11         19  
  11         908  
7 11     11   60 use parent 'Poz::Types';
  11         20  
  11         61  
8              
9             sub new {
10 6     6 1 19 my ($class, @validators) = @_;
11 6         17 for my $validator (@validators) {
12 12 50       69 if (!$validator->isa('Poz::Types')) {
13 0         0 Carp::croak("Invalid validator: is not a subclass of Poz::Types");
14             }
15             }
16 6         49 my $self = bless {
17             __validators__ => \@validators,
18             __rules__ => [],
19             __optional__ => 0,
20             __default__ => undef,
21             }, $class;
22 6         50 return $self;
23             }
24              
25             sub parse {
26 26     26 1 393 my ($self, $data) = @_;
27 26         78 my ($valid, $errors) = $self->safe_parse($data);
28 26 100       69 if ($errors) {
29 7         21 my $error_message = _errors_to_string($errors);
30 7         101 Carp::croak($error_message);
31             }
32 19         92 return $valid;
33             }
34              
35             sub safe_parse {
36 26 50   26 1 74 Carp::croak "Must handle error" unless wantarray;
37              
38 26         56 my ($self, $data) = @_;
39 26         46 my @errors = ();
40 26 100 100     173 if (defined $self->{__default__} && !defined $data) {
41 2         5 $data = $self->{__default__};
42             }
43 26 100       66 if (!defined $data) {
44 4 100       14 if ($self->{__optional__}) {
    100          
45 1         5 return (undef, undef);
46 6         23 } elsif (grep {ref $_ eq 'Poz::Types::null'} @{$self->{__validators__}}) {
  3         11  
47 2         6 return (undef, undef);
48             } else {
49 1         3 push @errors, "Required";
50             }
51             } else {
52 22         35 for my $validator (@{$self->{__validators__}}) {
  22         61  
53 35         166 my ($v, $e) = $validator->safe_parse($data);
54 35 100       91 if (!$e) {
55 16         83 return ($v, undef);
56             }
57 19         56 push @errors, $e;
58             }
59             }
60 7         46 return (undef, [@errors]);
61             }
62              
63             sub _errors_to_string {
64 7     7   12 my ($errors) = @_;
65 7         12 my @error_messages = ();
66 7         18 for my $error (@$errors) {
67 13         26 push @error_messages, $error;
68             }
69 7         37 return join(", ", @error_messages) . ' for union value';
70             }
71              
72             sub optional {
73 2     2 1 5 my ($self) = @_;
74 2         6 $self->{__optional__} = 1;
75 2         6 return $self;
76             }
77              
78             sub default {
79 2     2 1 7 my ($self, $default) = @_;
80 2         5 $self->{__default__} = $default;
81 2         6 return $self;
82             }
83              
84             1;
85              
86             =head1 NAME
87              
88             Poz::Types::union - Union type for multiple validators in Poz
89              
90             =head1 SYNOPSIS
91              
92             use Poz::Builder;
93             use Poz::Types;
94              
95             my $builder = Poz::Builder->new;
96             my $validator = $builder->union(
97             $builder->number->multipleOf(3),
98             $builder->number->multipleOf(5),
99             );
100              
101             my $valid = $validator->parse(6); # 6 is multiple of 3 and 5
102             my $invalid = $validator->parse(8); # 8 is not multiple of 3 or 5
103              
104             =head1 DESCRIPTION
105              
106             This module provides a way to validate a value against multiple validators. The value is considered valid if it passes any of the validators.
107              
108             =head1 METHODS
109              
110             =head2 new
111              
112             my $validator = Poz::Types::union->new(@validators);
113            
114             Creates a new union validator with the given validators.
115              
116             =head2 parse
117              
118             my $valid = $validator->parse($value);
119              
120             Validates the given value against the defined rules. Throws an error if the value is invalid.
121              
122             =head2 safe_parse
123              
124             my ($valid, $errors) = $validator->safe_parse($value);
125              
126             Validates the given value against the defined rules. If the value is valid, it returns the parsed value. If the value is invalid, it returns the validation errors.
127              
128             =head2 optional
129              
130             $validator->optional;
131              
132             Marks the value as optional.
133              
134             =head2 default
135              
136             $validator->default($default);
137              
138             Sets the default value for the validator.
139              
140             =head1 LICENSE
141              
142             Copyright (C) ytnobody.
143              
144             This library is free software; you can redistribute it and/or modify
145             it under the same terms as Perl itself.
146              
147             =head1 AUTHOR
148              
149             ytnobody E<lt>ytnobody@gmail.comE<gt>
150              
151             =cut
152