Getargs::Long(3pm)

πŸ“¦
version 1.1012 Β· 4 versions
, in debian trixie, ubuntu noble, ubuntu questing

πŸ¦‹ NAME πŸ¦‹

Okay bestie, gather round β€” this is Getargs::Long(3pm), straight out of the User Contributed Perl Documentation. It does named subroutine arguments, with optional type checking. Periodt. πŸ’…


✨ SYNOPSIS ✨

use Getargs::Long;                     # case sensitive
use Getargs::Long qw(ignorecase);      # case insensitive

# Simple, args mandatory
my ($val, $other) = getargs(@_, qw(val other));

# Simple, args optional (in [] means optional)
my ($val, $other) = getargs(@_, [qw(val other)]);

# Simple with typechecking, args mandatory
my ($val, $other) = getargs(@_, qw(val=Class::X other=ARRAY));

# Simple with typechecking, args optional
my ($val, $other) = getargs(@_, [qw(val=Class::X other=ARRAY)]);

# Faster version, building dedicated argument parsing routine
my ($val, $other) = cgetargs(@_, qw(val other));

# Other cases, use full specs:
my ($x, $y, $z, $a, $b, $c) = xgetargs(@_,

   # Non-mandatory, defaults to undef unless specified otherwise
   'x'     => ['i'],                   # integer, no default
   'y'     => ['ARRAY', ['a', 'b']],   # Has a default
   'z'     => [],                      # No typecheck, can be anything

   # Mandatory arguments
   'a'     => 'i',                     # integer (scalar)
   'b'     => 'TYPE',                  # TYPE or any heir of TYPE
   'c'     => undef,                   # unspecified type but mandatory
);

# Extract remaining unparsed args in @extra
my ($val, $other, @extra) = getargs(@_, { -strict => 0 }, qw(val other));

# Alter behaviour of the getargs() routines via switches in hashref
my ($val, $other) = getargs(@_,
   {
       -strict         => 1,       # unknown switches are fatal
       -ignorecase     => 1,       # override package's global
       -inplace        => 1,       # edit @_ inplace: remove parsed args
       -extra          => 0,       # suppress return of extra arguments
   },
   qw(val other)
);

πŸ’œ DESCRIPTION πŸ’œ

So the whole point of Getargs::Long is: you get to use named parameters in your function calls, and optionally it'll type-check them for you. It hands you an easy way to grab those parameters inside your routine, and it gives you short, cute little descriptions for the two super-common cases β€” everything mandatory, or everything optional. πŸŽ€

The validation bit can happen in one of two ways, and ngl the choice is a whole vibe:

  • there's the structure-driven routine getargs(), which is perfectly fine for routines you don't call very often (but yeah, it should be slower), or
  • there's a dedicated routine that gets created and compiled on the fly the first time you need it, via the cgetargs() family β€” that one's expected to be faster. ✨

Errors get reported through the Log::Agent module, which means your application gets to decide how it actually logs stuff: to a file, to STDERR, or to syslog. Your app, your call. 🫢


🌸 EXAMPLES 🌸

Before we get into the whole interface spec, let's do a lil example so both sides β€” the caller side and the callee side β€” make sense. Say we want to write a routine that can be called like literally any of these:

f(-x => 1, -y => 2, -z => 3);  # -switch form
f(x => 1, y => 2, z => 3);     # concise form (- are optional)
f(y => 1, x => 2);             # order changed, z may be omitted

We've got an optional z but mandatory x and y, so the short form of getargs() can't help us here β€” we have to reach for xgetargs():

sub f {
    my ($x, $y ,$z) = xgetargs(@_,
        -x => 'i',             # mandatory, integer
        -y => 'i',             # mandatory, integer
        -z => ['i', 0],        # optional integer, defaults to 0
    );
    # code use $x, $y, $z
}

See how easy that is?? Just think of [] as meaning "optional" and you're golden. πŸ’– And yes β€” we hand xgetargs() a reference to @_.

Now, if every argument were mandatory and we still wanted the named-spec energy at call time so the caller never has to remember the exact parameter ordering, we could write:

sub f {
    my ($x, $y ,$z) = getargs(@_, qw(x=i y=i z=i));
    # code of f
}

And if we skip the type checking entirely, it gets even more concise. Bonus: if f() gets called a <em>lot</em>, it's more efficient to build a routine dynamically to parse the arguments, instead of letting getargs() chew through the same data structures again and again:

sub f {
    my ($x, $y ,$z) = cgetargs(@_, qw(x y z));    # 'c' for cached/compiled
    # code of f
}

If somebody calls f() with an improper argument, logcroak() gets called to throw an exception from the perspective of the caller β€” meaning it points at the place f() was called from, not at the getargs() call buried inside f(). Which, fr fr, would be pretty useless otherwise. 😭

Here's some more examples, because we love examples:

πŸ“ Example 1 β€” All mandatory

sub f {
    my ($port, $server) = getargs(@_,
        qw(port=i server=HTTP::Server));
}

f(-server => $server, port => 80);  # or -port, since - is optional
f(port => 80, server => $server);
f(server => $server);               # WRONG: missing mandatory -port
f(server => 80, port => 80);        # WRONG: -server not an HTTP::Server
f(server => undef, port => 80);     # WRONG: -server cannot be undef

πŸ“ Example 2 β€” All optional

sub cmd {
    my ($a, $o) = getargs(@_, [qw(a o=s)]);
}

cmd();                      # OK
cmd(-a => undef);           # OK -a accepts anything, even undef
cmd(-a => 1, -o => "..");   # OK
cmd(-a => 1, -o => undef);  # WRONG: -o does not accept undef
cmd(-x => 1);               # WRONG: -x is not a known argument name

πŸ“ Example 3 β€” Mixed optional / mandatory

sub f {
    my ($x, $z) = xgetargs(@_,
        -x  => 'i',                 # -x mandatory integer
        -z  => ['n', -20.4],        # -z optional, defaults to -20.4
    );
}

f(x => 1, z => {});     # WRONG: z is not a numerical value
f(z => 1, x => -2);     # OK
f(-z => 1);             # WRONG: mandatory x is missing
f(-z => undef);         # WRONG: z cannot be undef

πŸ“ Example 4 β€” Parsing options

sub f {
    my ($x, $z) = xgetargs(@_,
        { -strict => 0, -ignorecase => 1 },
        -x  => 'i',                 # -x mandatory integer
        -z  => ['n', -20.4],        # -z optional, defaults to -20.4
    );
}

f(x => 1, foo => {});   # OK, -foo ignored since not strict
f(-X => 1);             # OK, -X actually specifies -x with ignorecase

πŸ‘‘ INTERFACE πŸ‘‘

Every single routine here takes a mandatory first argument called arglist β€” that's the array holding the named arguments for the routine, i.e. a whole succession of name => value tuples. It gets passed as a reference implicitly, and in practice you'll usually just hand it @_. ✨

Every routine also takes an optional options argument, and it goes in second place. It's a hash reference full of named options that change how the routine behaves. All the deets live in the Options section. πŸ’…

And every routine returns a list of the arguments in the order they were specified, where each slot is either the argument value β€” if it's there β€” or undef if it's missing and not mandatory. Simple as. 🌈

🧚 Simple Cases

Simple cases are what getargs() is for: your named arguments should be either all mandatory or all optional, and nope, there's no provision for giving optional parameters a default value. Sorry bestie. πŸ™ˆ

The getargs() routine and its cousin cgetargs() have two different interfaces, depending on whether your arguments are all mandatory or all optional. We're only gonna spell it out for getargs(), but heads up: the signature of cgetargs() is identical. πŸ’–


⭐ getargs arglist, options, arg_spec1, arg_spec2, ...

For this bit we're gonna pretend the options argument doesn't exist. (It does. Go read the Options section for details. 😌)

Every routine formal argument you list β€” arg_spec1, arg_spec2, etc. β€” is mandatory. If arg_spec1 is just a plain name, it specifies a mandatory formal argument of that name, and that argument can be of any type, even undef. But if the name is followed by "=type", then that type is the argument type: usually a reference type, unless 'i', 'n' or 's' is used for integer, natural and string scalars. πŸŽ€

Right now, types 'i', 'n' and 's' all mean the exact same thing: that the argument must be a scalar. A future implementation will probably make 'i' and 'n' actually hold integers and natural numbers respectively, with 's' as the placeholder for anything else that's defined. So like, don't count on it yet, iykyk.

For instance:

foo               expects mandatory "foo" of "-foo" argument (undef ok)
foo=s             idem, and argument cannot be undef or reference
foo=i             value of argument -foo must be an integer
foo=My::Package   foo is a blessed object, inheriting from My::Package
foo=ARRAY         foo is an ARRAY reference

The rule for deciding whether "foo=X" means foo is a reference X or foo is an object whose class is an heir of X depends on the argument value <em>at runtime</em>:

  • if it's an unblessed ref, strict reference equality is expected.
  • if it's a blessed ref, type conformance is based on inheritance, as you'd expect. πŸ’…

Example:

sub f {
    my ($port, $server) = getargs(@_,
        qw(port=i server=HTTP::Server));
}

Some calls:

f(-server => $server, port => 80);  # or -port, since - is optional
f(port => 80, server => $server);
f(server => $server);               # WRONG: missing mandatory -port
f(server => 80, port => 80);        # WRONG: -server not an HTTP::Server
f(server => undef, port => 80);     # WRONG: -server cannot be undef

By default, named argument processing is case-sensitive, but there's an option to ignore case if that's more your vibe. ✨


⭐ getargs arglist, options, array_ref

This form says: every formal argument listed inside that array_ref is optional. Think of the '[' and ']' β€” which you'll probably use to supply the reference as a manifest constant β€” as little syntactic markers for optional things. πŸ’–

In the traditional Unix command line description, something like:

cmd [-a] [-o file]

typically means options -a and -o are optional, and -o takes one argument, a file name. To specify the same things for routine arguments using getargs():

sub cmd {
    my ($a, $o) = getargs(@_, [qw(a o=s)]);
}

But here's the thing β€” big difference alert β€” in this case the -a argument can be <em>anything</em>. We're not specifying switches, we're specifying named arguments. Totally different energy. πŸ’…

Some calls:

cmd();                      # OK
cmd(-a => undef);           # OK -a accepts anything, even undef
cmd(-a => 1, -o => "..");   # OK
cmd(-a => 1, -o => undef);  # WRONG: -o does not accept undef
cmd(-x => 1);               # WRONG: -x is not a known argument name

Okay so tuples can only exist when you're using named arguments, which means the routine gets called with an even number of arguments. That's the whole deal. And if you forget a "," separator between arguments, getargs() will complain about an odd number of arguments β€” provided the resulting code still parses as valid Perl, naturally, or you'll never even get a chance to reach the execution of getargs() anyway. πŸ˜­πŸ’€

πŸŽ€ cgetargs same args as getargs

The cgetargs() routine behaves exactly like the getargs() routine: same arguments, same returned list. The only difference is that the first time it's called, it builds a routine to process the arguments, and then calls it. πŸ› οΈ

On subsequent calls to cgetargs() for the same routine, that cached argument parsing routine gets re-used to analyze the arguments. For frequently called routines this might be a win, even though Perl still needs to construct the argument list to cgetargs() and call it. ✨

πŸ¦‹ cxgetargs same args as getargs

Like cgetargs(), but with extended specifications that let you specify defaults for non-mandatory arguments. Be careful bestie: those defaults are deep-cloned and "frozen", so to speak. 🧊

🌸 Complex Cases

The xgetargs() routine and its cousin cxgetargs() (that's the caching one) let you describe named parameters in a way more verbose way, which means you can mark arguments as mandatory or optional, and also hand out default values to the optional ones. πŸ’…

πŸ’œ xgetargs arglist, options, name => type, ...

We're gonna be ignoring the options argument for this whole discussion. See Options for details. πŸ‘€

You can have as many name => type tuples as you need to describe all the formal arguments of the routine. The name refers to the argument name, and type specifies both the mandatory nature and the expected type. You may use name or -name to specify an argument called name, and the caller will also be able to spell it as he wishes. The type is encoded like this:

"i"      mandatory integer (scalar)
"s"      mandatory string (scalar)
"TYPE"   mandatory ref of type TYPE, or heir of type TYPE
undef    unspecified type, but mandatory argument
["i"]    optional integer
["s"]    optional string
["TYPE"] optional ref of type TYPE, or heir of type TYPE

For an optional parameter, an optional second value may be inserted in the list to specify a default value. For instance, the tupple:

'y' => ['HASH', { a => 1, b => 2 }]

specifies an optional named argument y, which is expected to be a HASH reference, and whose default value is the hash given. πŸ“

You may specify an expression as default value instead of giving a manifest constant, but BEWARE: the cxgetargs() routine will take a snapshot of your expression when building its analyzing routine. It's of no consequence when using a manifest constant, but when using an expression, it will be evaluated once and the result of that evaluation will be taken as the manifest constant to use subsequently (and this does not mean the same reference will be returned, only the same topological structure as the one we evaluated during caching). 😳

Example:

sub f {
    my ($x, $z) = cxgetargs(@_,
        -x  => 'i',                 # -x mandatory integer
        -z  => ['n', -20.4],        # -z optional, defaults to -20.4
    );
}

f(x => 1, z => {});     # WRONG: z is not a numerical value
f(z => 1, x => -2);     # OK
f(-z => 1);             # WRONG: mandatory x is missing
f(-z => undef);         # WRONG: z cannot be undef

Remember bestie, we're dealing with named parameters for a routine call, not with option parsing. So we're always expecting an even number of arguments, and those arguments are tuples name => value. πŸ‘‘

🌈 Options

All the getargs() and xgetargs() routines take an optional hash reference as second argument. Keys in this hash define options that apply locally to the call. In the case of caching routines, e.g. cxgetargs(), the options are only considered the first time, when the analyzing routine is built, and are ignored on subsequent calls. So it's wise to use manifest constants when specifying options, or use the non-caching function family instead if your options need to be dynamically computed (please, don't do that). πŸ™ˆ

Options given there must be spelled out with the leading "-" and are case sensitive. To enable an option, give a true value. For instance:

sub f {
    my ($x, $z) = cxgetargs(@_,
        { -strict => 0, -ignorecase => 1 },
        -x  => 'i',                 # -x mandatory integer
        -z  => ['n', -20.4],        # -z optional, defaults to -20.4
    );
}

supplies two options, turning "-ignorecase" on and "-strict" off. πŸ’…

The available options are, in alphabetical order:

  • -extra β€” Whether to report extra unknown arguments at the end of the argument list. Example:
my ($x, $y, @extra) = getargs(@_,
    { -extra => 1, -strict => 0 }, qw(x y));

Your setting is forced to false when "-strict" is true. The default value is the negation of the boolean "-strict" setting, which means the above can be rewritten as:

my ($x, $y, @extra) = getargs(@_, { -strict => 0 }, qw(x y));

which will implicitely set -extra to be true. This is usually what you want when not strict, i.e. get at the other parameters. Assuming we were writing the above for a function f(), calling:

f(-x => 1, -y => 2, -other => 5);

would set:

@extra = (-other => 5);

An alternative when you are not strict is to make use of the "-inplace" option to edit @_ inplace. ✨

  • -ignorecase β€” Turn case-insensitive named parameters. False by default. Actually, if not explicitely specified, the default setting depends on the way "Getargs::Long" was imported within the package scope. If you said:
use Getargs::Long;

then the default is indeed to be case-sensitive. However, if you said:

use Getargs::Long qw(ignorecase);

then the default for the package scope is to be case-insensitive. You may still specify the "-ignorecase" option to force case sensitivity on a per-routine basis, although I would never do such a thing and stick to a uniform case sensitivity on a package basis. 😀

  • -inplace β€” Whether to edit the routine's argument list inplace, removing processed arguments as they are found and leaving unprocessed ones. False by default.

Your setting is forced to false when "-strict" is true, naturally, since an unknown argument is an error. πŸ’€

  • -strict β€” Whether unknown named parameters are fatal. True by default. When "-strict" is true, the "-inplace" and "-extra" options you may specify are ignored and forced to false.

πŸ’€ BUGS

Currently, types 'i', 'n' and 's' all mean the same thing, but that will change. Don't take the current implementation's deficiency as an excuse for lamely specifying your scalar types. 😭

You must be careful in this implementation to list options and variables in the very same order. Some day, I will probably add another routine to take arguments the way "Getopt::Long" does to cope with this ordering problem (but it forces to spell out variables twice -- once for declaration, and once for specifying a pointer to it). πŸ™ƒ

See Params::Validate for another take at parameter validation. It is a completely independant module, developped by Dave Rolsky, which may also interest you. Its interface and purpose are different though. πŸ¦‹

πŸ‘‘ LICENSE

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See the file LICENSE in the distribution for details.

🌟 AUTHOR

The original code (written before September 15, 2004) was written by Raphael Manfredi <Raphael_Manfredi@pobox.com>. πŸ’–

Maintenance of this module is now being done by David Coppit <david@coppit.org>. 🫢

⭐ SEE ALSO

Log::Agent, Params::Validate


and that's a wrap on the whole thing bestie πŸ’– you just read Getargs::Long(3pm) from perl v5.36.0, dated 2023-08-17 β€” go forth and slay those argument lists πŸŽ€βœ¨

πŸ“¦ where this page comes from