File Coverage

blib/lib/Class/Params.pm
Criterion Covered Total %
statement 67 67 100.0
branch 24 24 100.0
condition 6 6 100.0
subroutine 11 11 100.0
pod 1 1 100.0
total 109 109 100.0


line stmt bran cond sub pod time code
1             package Class::Params;
2              
3 3     3   74335 use base qw(Exporter);
  3         17  
  3         405  
4 3     3   21 use strict;
  3         6  
  3         58  
5 3     3   12 use warnings;
  3         7  
  3         121  
6              
7 3     3   1511 use Error::Pure qw(err);
  3         35493  
  3         61  
8 3     3   173 use Readonly;
  3         7  
  3         139  
9 3     3   20 use Scalar::Util qw(blessed);
  3         5  
  3         2180  
10              
11             # Export.
12             Readonly::Array our @EXPORT_OK => qw(params);
13              
14             our $VERSION = 0.06;
15              
16             # Params processing.
17             sub params {
18 17     17 1 31804 my ($self, $def_hr, $params_ar) = @_;
19              
20             # Process params.
21 17         31 my @processed = ();
22 17         30 while (@{$params_ar}) {
  27         62  
23 17         26 my $key = shift @{$params_ar};
  17         27  
24 17         26 my $val = shift @{$params_ar};
  17         40  
25              
26             # Check key.
27 17 100       44 if (! $def_hr->{$key}->[0]) {
28 1         10 err "Unknown parameter '$key'.";
29             }
30              
31             # Check type.
32 16 100       38 if (! _check_type($val, $def_hr->{$key}->[2])) {
33 4         18 err "Bad parameter '$key' type.";
34             }
35              
36             # Check class.
37 12 100       27 if (! _check_class($val, $def_hr->{$key}->[1])) {
38 2         9 err "Bad parameter '$key' class.";
39             }
40              
41             # Add value to class.
42 10         26 $self->{$def_hr->{$key}->[0]} = $val;
43              
44             # Processed keys.
45 10         20 push @processed, $key;
46             }
47              
48             # Check requirement.
49 10 100       13 foreach my $req (map { $def_hr->{$_}->[3] ? $_ : () } keys %{$def_hr}) {
  11         37  
  10         32  
50 2 100       4 if (! grep { $req eq $_ } @processed) {
  2         8  
51 1         6 err "Parameter '$req' is required.";
52             }
53             }
54              
55 9         22 return;
56             }
57              
58             # Check type.
59             # Possible types: HASH, ARRAY, SCALAR.
60             sub _check_type {
61 16     16   29 my ($value, $type) = @_;
62              
63             # Multiple types.
64 16 100       40 if (ref $type eq 'ARRAY') {
65 7         12 foreach (@{$type}) {
  7         14  
66 12 100       18 if (_check_type_one($value, $_)) {
67 6         14 return 1;
68             }
69             }
70 1         3 return 0;
71              
72             # One type.
73             } else {
74 9         18 return _check_type_one($value, $type);
75             }
76             }
77              
78             # Check one type.
79             sub _check_type_one {
80 21     21   35 my ($value, $type) = @_;
81              
82 21 100 100     96 if (ref $value eq $type
83             || ref \$value eq $type) {
84              
85 12         40 return 1;
86             } else {
87 9         28 return 0;
88             }
89             }
90              
91             # Check class.
92             # Class: CLASS/undef.
93             sub _check_class {
94 18     18   31 my ($value, $class_name) = @_;
95              
96 18 100       28 if ($class_name) {
97              
98             # Array.
99 11 100       23 if (ref $value eq 'ARRAY') {
100 3         4 foreach (@{$value}) {
  3         7  
101 6 100       11 if (! _check_class($_, $class_name)) {
102 2         6 return 0;
103             }
104             }
105 1         2 return 1;
106             # One.
107             } else {
108 8         17 return _check_class_one($value, $class_name);
109             }
110             } else {
111 7         16 return 1;
112             }
113             }
114              
115             # Check ref to class.
116             sub _check_class_one {
117 8     8   12 my ($class, $class_name) = @_;
118              
119 8 100 100     56 if (! blessed($class) || ! $class->isa($class_name)) {
120 2         7 return 0;
121             } else {
122 6         20 return 1;
123             }
124             }
125              
126             1;
127              
128             =pod
129              
130             =encoding utf8
131              
132             =head1 NAME
133              
134             Class::Params - Parameter utils for constructor.
135              
136             =head1 SYNOPSIS
137              
138             use Class::Params qw(params);
139              
140             params($self, $def_hr, $params_ar);
141              
142             =head1 DEFINITION FORMAT
143              
144             There is hash with parameters.
145             internal_name => [real_name, class, possible_types, requirement]
146              
147             Example:
148             'par1' => ['_par1', undef, 'SCALAR', 1],
149             'par2' => ['_par2', undef, ['SCALAR', 'HASH'], 0],
150             'par3' => ['_par3', 'Class', ['SCALAR', 'Class'], 0],
151              
152             =head1 SUBROUTINES
153              
154             =head2 C
155              
156             params($self, $def_hr, $params_ar);
157              
158             Check for structure over definition and save input data to $self.
159              
160             Parameters:
161              
162             $self - Structure, for data save.
163             $def_hr - Definition hash ref.
164             $params_ar - Reference to array of key-value pairs.
165              
166             Returns undef.
167              
168             =head1 ERRORS
169              
170             params():
171             Bad parameter '%s' type.
172             Parameter '%s' is required.
173             Unknown parameter '%s'.
174              
175             =head1 EXAMPLE1
176              
177             use strict;
178             use warnings;
179              
180             use Class::Params qw(params);
181              
182             # Definition.
183             my $self = {};
184             my $def_hr = {
185             'par' => ['_par', undef, 'SCALAR', 1],
186             };
187              
188             # Check.
189             # output_structure, definition, array of pairs (key, value).
190             params($self, $def_hr, ['bad_par', 1]);
191              
192             # Output:
193             # Unknown parameter 'bad_par'.
194              
195             =head1 EXAMPLE2
196              
197             use strict;
198             use warnings;
199              
200             use Class::Params qw(params);
201             use Data::Printer;
202              
203             # Definition.
204             my $self = {};
205             my $def_hr = {
206             'par' => ['_par', undef, 'SCALAR', 1],
207             };
208              
209             # Check.
210             # output_structure, definition, array of pairs (key, value).
211             params($self, $def_hr, ['par', 1]);
212              
213             # Dump $self.
214             p $self;
215              
216             # Output:
217             # \ {
218             # _par 1
219             # }
220              
221             =head1 EXAMPLE3
222              
223             use strict;
224             use warnings;
225              
226             use Class::Params qw(params);
227              
228             # Definition.
229             my $self = {};
230             my $def_hr = {
231             'par' => ['_par', 'Moo', ['ARRAY', 'Moo'], 0],
232             };
233              
234             # Fake class.
235             my $moo = bless {}, 'Moo';
236              
237             # Check bad 'par' parameter which has bad 'bar' scalar.
238             params($self, $def_hr, ['par', [$moo, 'bar']]);
239              
240             # Output like:
241             # Bad parameter 'par' class.
242              
243             =head1 EXAMPLE4
244              
245             use strict;
246             use warnings;
247              
248             use Class::Params qw(params);
249             use Data::Printer;
250              
251             # Definition.
252             my $self = {};
253             my $def_hr = {
254             'par' => ['_par', 'Moo', ['ARRAY', 'Moo'], 0],
255             };
256              
257             # Fake class.
258             my $moo = bless {}, 'Moo';
259              
260             # Check right 'par' parameter which has array of 'Moo' objects.
261             params($self, $def_hr, ['par', [$moo, $moo]]);
262              
263             # Dump $self.
264             p $self;
265              
266             # Output like:
267             # \ {
268             # _par [
269             # [0] Moo {
270             # public methods (0)
271             # private methods (0)
272             # internals: {}
273             # },
274             # [1] var{_par}[0]
275             # ]
276             # }
277              
278             =head1 DEPENDENCIES
279              
280             L,
281             L,
282             L,
283             L.
284              
285             =head1 REPOSITORY
286              
287             L
288              
289             =head1 AUTHOR
290              
291             Michal Josef Špaček L
292              
293             =head1 LICENSE AND COPYRIGHT
294              
295             © Michal Josef Špaček 2011-2021
296              
297             BSD 2-Clause License
298              
299             =head1 VERSION
300              
301             0.06
302              
303             =cut