File Coverage

blib/lib/Params/Get.pm
Criterion Covered Total %
statement 73 78 93.5
branch 42 48 87.5
condition 23 24 95.8
subroutine 6 6 100.0
pod 1 1 100.0
total 145 157 92.3


line stmt bran cond sub pod time code
1             package Params::Get;
2              
3 5     5   614266 use strict;
  5         6  
  5         152  
4 5     5   24 use warnings;
  5         6  
  5         184  
5              
6 5     5   46 use Carp;
  5         6  
  5         297  
7 5     5   2880 use Devel::Confess;
  5         49517  
  5         17  
8 5     5   351 use Scalar::Util;
  5         8  
  5         3533  
9              
10             our @ISA = qw(Exporter);
11             our @EXPORT_OK = qw(get_params);
12              
13             =head1 NAME
14              
15             Params::Get - Get the parameters to a subroutine in any way you want
16              
17             =head1 VERSION
18              
19             Version 0.14
20              
21             =cut
22              
23             our $VERSION = '0.14';
24              
25             =head1 DESCRIPTION
26              
27             Exports a single function, C, which returns a given value.
28              
29             When used hand-in-hand with L and L,
30             you should be able to formally specify the input and output sets for a method.
31              
32             =head1 SYNOPSIS
33              
34             use Params::Get;
35             use Params::Validate::Strict;
36              
37             sub where_am_i
38             {
39             my $params = Params::Validate::Strict::validate_strict({
40             args => Params::Get::get_params(undef, \@_),
41             schema => {
42             'latitude' => {
43             type => 'number',
44             min => -90,
45             max => 90
46             }, 'longitude' => {
47             type => 'number',
48             min => -180,
49             max => 180
50             }
51             }
52             });
53              
54             print 'You are at ', $params->{'latitude'}, ', ', $params->{'longitude'}, "\n";
55             }
56              
57             where_am_i(latitude => 0.3, longitude => 124);
58             where_am_i({ latitude => 3.14, longitude => -155 });
59              
60             =head1 METHODS
61              
62             =head2 get_params
63              
64             Parse the arguments given to a function.
65             Processes arguments passed to methods and ensures they are in a usable format,
66             allowing the caller to call the function in any way that they want
67             e.g. `foo('bar')`, `foo(arg => 'bar')`, `foo({ arg => 'bar' })` all mean the same
68             when called with
69              
70             get_params('arg', @_);
71              
72             or
73              
74             get_params('arg', \@_);
75              
76             Some people like this sort of model, which is also supported.
77              
78             use MyClass;
79              
80             my $str = 'hello world';
81             my $obj = MyClass->new($str, { type => 'string' });
82              
83             package MyClass;
84              
85             use Params::Get;
86              
87             sub new {
88             my $class = shift;
89             my $rc = Params::Get::get_params('value', \@_);
90              
91             return bless $rc, $class;
92             }
93              
94             =head2 The C<$default> Parameter
95              
96             The first argument is the C<$default> parameter controls how single-argument calls are interpreted and provides
97             a default key name for parameter extraction in those cases.
98              
99             When no arguments are provided with a defined C<$default>:
100              
101             get_params('required'); # Throws usage error
102              
103             The function requires either arguments or an undefined C<$default>.
104              
105             =head3 Usage Examples
106              
107             =over 2
108              
109             =item * Simple scalar parameter:
110              
111             sub set_country {
112             my $params = get_params('country', @_);
113             # Accepts: set_country('US')
114             # Returns: { country => 'US' }
115             }
116              
117             =item * Object constructor with options:
118              
119             sub new {
120             my $class = shift;
121             my $params = get_params('value', @_);
122             # Accepts: MyClass->new($object)
123             # Accepts: MyClass->new($object, { option => 'value' })
124             # Returns: { value => $object } or { value => $object, option => 'value' }
125             }
126              
127             =item * Hash parameter:
128              
129             sub configure {
130             my $params = get_params('config', @_);
131             # Accepts: configure({ db => 'mysql', host => 'localhost' })
132             # Returns: { config => { db => 'mysql', host => 'localhost' } }
133             }
134              
135             =item * Without default (named parameters only):
136              
137             sub process {
138             my $params = get_params(undef, @_);
139             # Accepts: process(name => 'John', age => 30)
140             # Returns: { name => 'John', age => 30 }
141             }
142              
143             =back
144              
145             =head3 Caveats
146              
147             =over 2
148              
149             =item * When C<$default> is defined and no arguments are provided, an error is thrown
150              
151             =item * There's no way to specify that a default parameter is optional
152              
153             =item * Single hash references always bypass the default parameter naming
154              
155             =back
156              
157             =cut
158              
159             sub get_params
160             {
161             # Directly return hash reference if the only parameter is a hash reference
162 57 100 100 57 1 648613 return $_[0] if((scalar(@_) == 1) && (ref($_[0]) eq 'HASH')); # Note - doesn't check if "default" was given
163              
164 55         106 my $default = shift;
165              
166 55 50       137 if(ref($default)) {
167 0         0 Carp::croak(__PACKAGE__, '::get_params: $default must be a scalar');
168             }
169              
170 55         99 my $args;
171             my $array_ref;
172 55 100 100     232 if((scalar(@_) == 1) && (ref($_[0]) eq 'ARRAY')) {
173 19 100 100     45 if($default && (scalar(@{$_[0]}) == 2) && (@{$_[0]}[0] eq $default) && (!ref(@{$_[0]}[1]))) {
  14   100     53  
  8   100     36  
  3         30  
174             # in main:
175             # routine('country' => 'US');
176             # in routine():
177             # $params = Params::Get::get_params('country', \@);
178 2         4 return { $default => @{$_[0]}[1] };
  2         43  
179             }
180 17         30 $args = $_[0];
181 17         24 $array_ref = 1;
182             } else {
183 36         65 $args = \@_;
184             }
185              
186 53         65 my $num_args = scalar(@{$args});
  53         79  
187              
188             # Populate %rc based on the number and type of arguments
189 53 100       136 if($num_args == 1) {
190 29 100       60 if(defined($default)) {
191 17 100       48 if(!ref($args->[0])) {
192             # %rc = ($default => shift);
193 5         63 return { $default => $args->[0] };
194             }
195 12 100       34 if(ref($args->[0]) eq 'ARRAY') {
196 1         4 return { $default => $args->[0] };
197             }
198 11 100       32 if(ref($args->[0]) eq 'SCALAR') {
199 3         9 return { $default => ${$args->[0]} };
  3         26  
200             }
201 8 100       21 if(ref($args->[0]) eq 'CODE') {
202 2         16 return { $default => $args->[0] };
203             }
204 6 100       23 if(Scalar::Util::blessed($args->[0])) {
205 2         18 return { $default => $args->[0] };
206             }
207             }
208 16 100       27 if(!defined($args->[0])) {
209 1         5 return;
210             }
211 15 100       36 if(ref($args->[0]) eq 'REF') {
212 1         2 $args->[0] = ${$args->[0]};
  1         2  
213             }
214 15 100       29 if(ref($args->[0]) eq 'HASH') {
215 13         80 return $args->[0];
216             }
217 2 100 66     8 if((ref($args->[0]) eq 'ARRAY') && (scalar(@{$args->[0]}) == 0)) {
  1         3  
218             # in main:
219             # routine('countries' => []);
220             # in routine():
221             # $params = Params::Get::get_params('countries', \@);
222 1 50       3 if(defined($default)) {
223 0         0 return { $default => [] }
224             }
225 1         2 return $args->[0];
226             }
227 1         18 Carp::croak('Usage: ', __PACKAGE__, '->', (caller(1))[3], '()');
228             }
229 24 100       43 if($num_args == 0) {
230 7 100       48 if(defined($default)) {
231             # if(defined($_[0]) && (ref($_[0]) eq 'ARRAY')) {
232             # FIXME
233             # return { $default => [] };
234             # }
235             # FIXME: No means to say that the default is optional
236             # Carp::croak('Usage: ', __PACKAGE__, '->', (caller(1))[3], "($default => \$val)");
237 4         82 Carp::croak(Devel::Confess::longmess("Usage: ", __PACKAGE__, '->', (caller(1))[3], "($default => \$val)"));
238             }
239 3         10 return;
240             }
241 17 100 100     83 if(($num_args == 2) && (ref($args->[1]) eq 'HASH')) {
242 4 50       10 if(defined($default)) {
243 4 50       3 if(scalar keys %{$args->[1]}) {
  4         11  
244 4 50       17 if($args->[0] eq $default) {
245 0         0 return { $default => $args->[1] };
246             }
247             # Obj->new('foo', { 'key1' => 'val1' } - set foo to the mandatory first argument, and the rest are options
248             return {
249             $default => $args->[0],
250 4         7 %{$args->[1]}
  4         22  
251             };
252             }
253             # Obj->new(foo => {}) - set foo to be an empty hash
254 0         0 return { $default => $args->[1] }
255             }
256             }
257              
258 13 100 100     45 if($array_ref && defined($default)) {
259 4         27 return { $default => $args };
260             }
261 9 50       40 if(($num_args % 2) == 0) {
262 9         12 my %rc = @{$args};
  9         34  
263 9         45 return \%rc;
264             }
265              
266 0           Carp::croak('Usage: ', __PACKAGE__, '->', (caller(1))[3], '()');
267             }
268              
269             =head1 AUTHOR
270              
271             Nigel Horne, C<< >>
272              
273             =head1 BUGS
274              
275             Sometimes giving an array ref rather than array fails.
276              
277             =head1 SEE ALSO
278              
279             =over 4
280              
281             =item * L
282              
283             =item * L
284              
285             =item * L
286              
287             =item * L
288              
289             =back
290              
291             =head1 SUPPORT
292              
293             This module is provided as-is without any warranty.
294              
295             Please report any bugs or feature requests to C,
296             or through the web interface at
297             L.
298             I will be notified, and then you'll
299             automatically be notified of progress on your bug as I make changes.
300              
301             You can find documentation for this module with the perldoc command.
302              
303             perldoc Params::Get
304              
305             You can also look for information at:
306              
307             =over 4
308              
309             =item * MetaCPAN
310              
311             L
312              
313             =item * RT: CPAN's request tracker
314              
315             L
316              
317             =item * CPAN Testers' Matrix
318              
319             L
320              
321             =item * CPAN Testers Dependencies
322              
323             L
324              
325             =back
326              
327             =head1 LICENCE AND COPYRIGHT
328              
329             Copyright 2025-2026 Nigel Horne.
330              
331             Usage is subject to the GPL2 licence terms.
332             If you use it,
333             please let me know.
334              
335             =cut
336              
337             1;