File Coverage

File:blib/lib/Params/Get.pm
Coverage:93.6%

linestmtbrancondsubtimecode
1package Params::Get;
2
3
5
5
5
258359
4
63
use strict;
4
5
5
5
7
3
80
use warnings;
5
6
5
5
5
9
4
100
use Carp;
7
5
5
5
1151
20274
10
use Devel::Confess;
8
5
5
5
149
5
1405
use Scalar::Util;
9
10our @ISA = qw(Exporter);
11our @EXPORT_OK = qw(get_params);
12
13 - 21
=head1 NAME

Params::Get - Get the parameters to a subroutine in any way you want

=head1 VERSION

Version 0.14

=cut
22
23our $VERSION = '0.14';
24
25 - 157
=head1 DESCRIPTION

Exports a single function, C<get_params>, which returns a given value.

When used hand-in-hand with L<Params::Validate::Strict> and L<Return::Set>,
you should be able to formally specify the input and output sets for a method.

=head1 SYNOPSIS

    use Params::Get;
    use Params::Validate::Strict;

    sub where_am_i
    {
        my $params = Params::Validate::Strict::validate_strict({
            args => Params::Get::get_params(undef, \@_),
            schema => {
                'latitude' => {
                    type => 'number',
                    min => -90,
                    max => 90
                }, 'longitude' => {
                    type => 'number',
                    min => -180,
                    max => 180
                }
            }
        });

        print 'You are at ', $params->{'latitude'}, ', ', $params->{'longitude'}, "\n";
    }

    where_am_i(latitude => 0.3, longitude => 124);
    where_am_i({ latitude => 3.14, longitude => -155 });

=head1  METHODS

=head2 get_params

Parse the arguments given to a function.
Processes arguments passed to methods and ensures they are in a usable format,
allowing the caller to call the function in any way that they want
e.g. `foo('bar')`, `foo(arg => 'bar')`, `foo({ arg => 'bar' })` all mean the same
when called with

    get_params('arg', @_);

or

    get_params('arg', \@_);

Some people like this sort of model, which is also supported.

    use MyClass;

    my $str = 'hello world';
    my $obj = MyClass->new($str, { type => 'string' });

    package MyClass;

    use Params::Get;

    sub new {
        my $class = shift;
        my $rc = Params::Get::get_params('value', \@_);

        return bless $rc, $class;
    }

=head2 The C<$default> Parameter

The first argument is the C<$default> parameter controls how single-argument calls are interpreted and provides
a default key name for parameter extraction in those cases.

When no arguments are provided with a defined C<$default>:

    get_params('required'); # Throws usage error

The function requires either arguments or an undefined C<$default>.

=head3 Usage Examples

=over 2

=item * Simple scalar parameter:

    sub set_country {
        my $params = get_params('country', @_);
        # Accepts: set_country('US')
        # Returns: { country => 'US' }
    }

=item * Object constructor with options:

    sub new {
        my $class = shift;
        my $params = get_params('value', @_);
        # Accepts: MyClass->new($object)
        # Accepts: MyClass->new($object, { option => 'value' })
        # Returns: { value => $object } or { value => $object, option => 'value' }
    }

=item * Hash parameter:

    sub configure {
        my $params = get_params('config', @_);
        # Accepts: configure({ db => 'mysql', host => 'localhost' })
        # Returns: { config => { db => 'mysql', host => 'localhost' } }
    }

=item * Without default (named parameters only):

    sub process {
        my $params = get_params(undef, @_);
        # Accepts: process(name => 'John', age => 30)
        # Returns: { name => 'John', age => 30 }
    }

=back

=head3 Caveats

=over 2

=item * When C<$default> is defined and no arguments are provided, an error is thrown

=item * There's no way to specify that a default parameter is optional

=item * Single hash references always bypass the default parameter naming

=back

=cut
158
159sub get_params
160{
161        # Directly return hash reference if the only parameter is a hash reference
162
60
388422
        return $_[0] if((scalar(@_) == 1) && (ref($_[0]) eq 'HASH'));   # Note - doesn't check if "default" was given
163
164
58
43
        my $default = shift;
165
166
58
75
        if(ref($default)) {
167
0
0
                Carp::croak(__PACKAGE__, '::get_params: $default must be a scalar');
168        }
169
170
58
31
        my $args;
171        my $array_ref;
172
58
92
        if((scalar(@_) == 1) && (ref($_[0]) eq 'ARRAY')) {
173
21
14
8
3
19
21
14
4
                if($default && (scalar(@{$_[0]}) == 2) && (@{$_[0]}[0] eq $default) && (!ref(@{$_[0]}[1]))) {
174                        # in main:
175                        #       routine('country' => 'US');
176                        # in routine():
177                        #       $params = Params::Get::get_params('country', \@);
178
2
2
2
4
                        return { $default => @{$_[0]}[1] };
179                }
180
19
9
                $args = $_[0];
181
19
13
                $array_ref = 1;
182        } else {
183
37
26
                $args = \@_;
184        }
185
186
56
56
34
38
        my $num_args = scalar(@{$args});
187
188        # Populate %rc based on the number and type of arguments
189
56
44
        if($num_args == 1) {
190
30
28
                if(defined($default)) {
191
17
19
                        if(!ref($args->[0])) {
192                                # %rc = ($default => shift);
193
5
16
                                return { $default => $args->[0] };
194                        }
195
12
10
                        if(ref($args->[0]) eq 'ARRAY') {
196
1
2
                                return { $default => $args->[0] };
197                        }
198
11
14
                        if(ref($args->[0]) eq 'SCALAR') {
199
3
3
3
6
                                return { $default => ${$args->[0]} };
200                        }
201
8
9
                        if(ref($args->[0]) eq 'CODE') {
202
2
7
                                return { $default => $args->[0] };
203                        }
204
6
8
                        if(Scalar::Util::blessed($args->[0])) {
205
2
7
                                return { $default => $args->[0] };
206                        }
207                }
208
17
17
                if(!defined($args->[0])) {
209
1
2
                        return;
210                }
211
16
15
                if(ref($args->[0]) eq 'REF') {
212
1
1
3
1
                        $args->[0] = ${$args->[0]};
213                }
214
16
18
                if(ref($args->[0]) eq 'HASH') {
215
14
23
                        return $args->[0];
216                }
217
2
1
5
1
                if((ref($args->[0]) eq 'ARRAY') && (scalar(@{$args->[0]}) == 0)) {
218                        # in main:
219                        #       routine('countries' => []);
220                        # in routine():
221                        #       $params = Params::Get::get_params('countries', \@);
222
1
1
                        if(defined($default)) {
223
0
0
                                return { $default => [] }
224                        }
225
1
2
                        return $args->[0];
226                }
227
1
7
                Carp::croak('Usage: ', __PACKAGE__, '->', (caller(1))[3], '()');
228        }
229
26
24
        if($num_args == 0) {
230
7
8
                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
33
                        Carp::croak(Devel::Confess::longmess("Usage: ", __PACKAGE__, '->', (caller(1))[3], "($default => \$val)"));
238                }
239
3
4
                return;
240        }
241
19
32
        if(($num_args == 2) && (ref($args->[1]) eq 'HASH')) {
242
5
4
                if(defined($default)) {
243
5
5
3
7
                        if(scalar keys %{$args->[1]}) {
244
5
5
                                if($args->[0] eq $default) {
245
1
2
                                        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
4
5
10
                                        %{$args->[1]}
251                                };
252                        }
253                        # Obj->new(foo => {}) - set foo to be an empty hash
254
0
0
                        return { $default => $args->[1] }
255                }
256        }
257
258
14
15
        if($array_ref && defined($default)) {
259
4
7
                return { $default => $args };
260        }
261
10
13
        if(($num_args % 2) == 0) {
262
10
10
6
14
                my %rc = @{$args};
263
10
20
                return \%rc;
264        }
265
266
0
        Carp::croak('Usage: ', __PACKAGE__, '->', (caller(1))[3], '()');
267}
268
269 - 335
=head1 AUTHOR

Nigel Horne, C<< <njh at nigelhorne.com> >>

=head1 BUGS

Sometimes giving an array ref rather than array fails.

=head1 SEE ALSO

=over 4

=item * L<Params::Smart>

=item * L<Params::Validate::Strict>

=item * L<Return::Set>

=item * L<Test Dashboard|https://nigelhorne.github.io/Params-Get/coverage/>

=back

=head1 SUPPORT

This module is provided as-is without any warranty.

Please report any bugs or feature requests to C<bug-params-get at rt.cpan.org>,
or through the web interface at
L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Params-Get>.
I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.

You can find documentation for this module with the perldoc command.

    perldoc Params::Get

You can also look for information at:

=over 4

=item * MetaCPAN

L<https://metacpan.org/dist/Params-Get>

=item * RT: CPAN's request tracker

L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=Params-Get>

=item * CPAN Testers' Matrix

L<http://matrix.cpantesters.org/?dist=Params-Get>

=item * CPAN Testers Dependencies

L<http://deps.cpantesters.org/?module=Params::Get>

=back

=head1 LICENCE AND COPYRIGHT

Copyright 2025-2026 Nigel Horne.

Usage is subject to the GPL2 licence terms.
If you use it,
please let me know.

=cut
336
3371;