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