package Perinci::Sub::ConvertArgs::Argv;
our $DATE = '2019-04-15'; # DATE
our $VERSION = '0.110'; # VERSION
use 5.010001;
use strict;
use warnings;
use Data::Sah::Util::Type qw(is_simple);
use Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(convert_args_to_argv);
our %SPEC;
sub _json {
require JSON;
state $json = JSON->new->allow_nonref;
$json->encode($_[0]);
}
sub _encode {
ref($_[0]) ? _json($_[0]) : $_[0];
}
$SPEC{convert_args_to_argv} = {
v => 1.1,
summary => 'Convert hash arguments to command-line options (and arguments)',
description => <<'_',
Convert hash arguments to command-line arguments. This is the reverse of
`Perinci::Sub::GetArgs::Argv::get_args_from_argv`.
Note: currently the function expects schemas in metadata to be normalized
already.
_
args => {
args => {req=>1, schema=>'hash*', pos=>0},
meta => {req=>0, schema=>'hash*', pos=>1},
use_pos => {
summary => 'Whether to use positional arguments',
schema => 'bool',
description => <<'_',
For example, given this metadata:
{
v => 1.1,
args => {
arg1 => {pos=>0, req=>1},
arg2 => {pos=>1},
arg3 => {},
},
}
then under `use_pos=0` the hash `{arg1=>1, arg2=>2, arg3=>'a b'}` will be
converted to `['--arg1', 1, '--arg2', 2, '--arg3', 'a b']`. Meanwhile if
`use_pos=1` the same hash will be converted to `[1, 2, '--arg3', 'a b']`.
_
},
},
};
sub convert_args_to_argv {
my %fargs = @_;
my $iargs = $fargs{args} or return [400, "Please specify args"];
my $meta = $fargs{meta} // {v=>1.1};
my $args_prop = $meta->{args} // {};
my $v = $meta->{v} // 1.0;
return [412, "Sorry, only metadata version 1.1 is supported (yours: $v)"]
unless $v == 1.1;
my @argv;
my %iargs = %$iargs; # copy 'coz we will delete them one by one as we fill
if ($fargs{use_pos}) {
for my $arg (sort {$args_prop->{$a}{pos} <=> $args_prop->{$b}{pos}}
grep {defined $args_prop->{$_}{pos}} keys %iargs) {
my $pos = $args_prop->{$arg}{pos};
if ($args_prop->{$arg}{slurpy} // $args_prop->{$arg}{greedy}) {
my $sch = $args_prop->{$arg}{schema};
my $is_array_of_simple = $sch && $sch->[0] eq 'array' &&
is_simple($sch->[1]{of} // $sch->[1]{each_elem});
for my $el (@{ $iargs{$arg} }) {
$argv[$pos] = $is_array_of_simple ? $el : _encode($el);
$pos++;
}
} else {
$argv[$pos] = _encode($iargs{$arg});
}
delete $iargs{$arg};
}
}
for (sort keys %iargs) {
my $sch = $args_prop->{$_}{schema};
my $is_bool = $sch && $sch->[0] eq 'bool';
my $is_array_of_simple = $sch && $sch->[0] eq 'array' &&
$sch->[1]{of} && is_simple($sch->[1]{of});
my $is_hash_of_simple = $sch && $sch->[0] eq 'hash' &&
is_simple($sch->[1]{of} // $sch->[1]{each_value} // $sch->[1]{each_elem});
my $can_be_comma_separated = $is_array_of_simple &&
$sch->[1]{of}[0] =~ /\A(int|float)\z/; # XXX as well as other simple types that cannot contain commas
my $opt = $_; $opt =~ s/_/-/g;
my $dashopt = length($opt) > 1 ? "--$opt" : "-$opt";
if ($is_bool) {
if ($iargs{$_}) {
push @argv, $dashopt;
} else {
push @argv, "--no$opt";
}
} elsif ($can_be_comma_separated) {
push @argv, "$dashopt", join(",", @{ $iargs{$_} });
} elsif ($is_array_of_simple) {
for (@{ $iargs{$_} }) {
push @argv, "$dashopt", $_;
}
} elsif ($is_hash_of_simple) {
my $arg = $iargs{$_};
for (sort keys %$arg) {
push @argv, "$dashopt", "$_=$arg->{$_}";
}
} else {
if (ref $iargs{$_}) {
push @argv, "$dashopt-json", _encode($iargs{$_});
} else {
push @argv, $dashopt, "$iargs{$_}";
}
}
}
[200, "OK", \@argv];
}
1;
# ABSTRACT: Convert hash arguments to command-line options (and arguments)
__END__
=pod
=encoding UTF-8
=head1 NAME
Perinci::Sub::ConvertArgs::Argv - Convert hash arguments to command-line options (and arguments)
=head1 VERSION
This document describes version 0.110 of Perinci::Sub::ConvertArgs::Argv (from Perl distribution Perinci-Sub-ConvertArgs-Argv), released on 2019-04-15.
=head1 SYNOPSIS
use Perinci::Sub::ConvertArgs::Argv qw(convert_args_to_argv);
my $res = convert_args_to_argv(args=>\%args, meta=>$meta, ...);
=head1 FUNCTIONS
=head2 convert_args_to_argv
Usage:
convert_args_to_argv(%args) -> [status, msg, payload, meta]
Convert hash arguments to command-line options (and arguments).
Convert hash arguments to command-line arguments. This is the reverse of
C<Perinci::Sub::GetArgs::Argv::get_args_from_argv>.
Note: currently the function expects schemas in metadata to be normalized
already.
This function is not exported by default, but exportable.
Arguments ('*' denotes required arguments):
=over 4
=item * B<args>* => I<hash>
=item * B<meta> => I<hash>
=item * B<use_pos> => I<bool>
Whether to use positional arguments.
For example, given this metadata:
{
v => 1.1,
args => {
arg1 => {pos=>0, req=>1},
arg2 => {pos=>1},
arg3 => {},
},
}
then under C<use_pos=0> the hash C<< {arg1=E<gt>1, arg2=E<gt>2, arg3=E<gt>'a b'} >> will be
converted to C<['--arg1', 1, '--arg2', 2, '--arg3', 'a b']>. Meanwhile if
C<use_pos=1> the same hash will be converted to C<[1, 2, '--arg3', 'a b']>.
=back
Returns an enveloped result (an array).
First element (status) is an integer containing HTTP status code
(200 means OK, 4xx caller error, 5xx function error). Second element
(msg) is a string containing error message, or 'OK' if status is
200. Third element (payload) is optional, the actual result. Fourth
element (meta) is called result metadata and is optional, a hash
that contains extra information.
Return value: (any)
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Sub-ConvertArgs-Argv>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Perinci-Sub-ConvertArgs-Argv>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Sub-ConvertArgs-Argv>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Perinci::CmdLine>, which uses this module for presenting command-line
examples.
L<Perinci::Sub::GetArgs::Argv> which does the reverse: converting command-line
arguments to hash.
=head1 AUTHOR
perlancar <perlancar@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2019, 2016, 2015, 2014, 2013 by perlancar@cpan.org.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut