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