#!perl

our $DATE = '2017-07-10'; # DATE
our $VERSION = '0.37'; # VERSION

use 5.010001;
use strict;
use warnings;

use App::riap;

my $shell = App::riap->new;

$shell->cmdloop;

1;
# ABSTRACT: Riap command-line client shell
# PODNAME: riap

__END__

=pod

=encoding UTF-8

=head1 NAME

riap - Riap command-line client shell

=head1 VERSION

version 0.37

=head1 SYNOPSIS

 % riap --help
 % riap [opts] <uri>

Invoking:

 # URI defaults to 'pl:/', which is the local Perl realm
 % riap

 # ditto, but specify initial "pwd"
 % riap /Calendar/Indonesia/Holiday
 % riap pl:/Calendar/Indonesia/Holiday

 # access remote API starting point
 % riap https://cpanlists.org/api/
 % riap http://gudangapi.com/ga/

An example session:

 riap> pwd
 /

 riap> cd /spanel/api

 riap> ls
 account/
 disk_usage/
 mysql/
 pgsql/
 plan/
 ...

 riap> cd account/shared/query

 riap> pwd
 /spanel/api/account/shared/query

 riap> ls -l
 create_account     function
 delete_accounts    function
 suspend_account    function
 unsuspend_account  function

 # execute a Riap function like it is an executable program
 riap> list_accounts --nodisabled --nomigrated
 andi
 budi
 jamal
 titin
 ujang

 riap> ../modify/delete_account --help

 riap> exit

=head1 DESCRIPTION

A Riap client in the form of a simple interactive command-line shell (as opposed
to L<Perinci::Access> which is a Perl library, or L<peri-run> and L<peri-access>
which are non-interactive command-line interface). Provides a convenient way to
explore API services which use the L<Riap> protocol or explore Perl modules
which have L<Rinci> metadata.

Example API services that you can (or will be able to) test this with:

=over

=item * cpanlists.org at L<https://cpanlists.org/api/>

=item * gudangdata.org at L<https://gudangdata.org/gd/>

=item * gudangapi.com at L<https://gudangapi.com/ga/>

=item * Any server using the Spanel control panel software

The API daemon listens at the Unix socket at C</var/run/spanel/apid.sock> or at
TCP C<https://localhost:1010>.

=back

Example Perl libraries you can test this with (you need to install them first):
L<Text::sprintfn>, L<Git::Bunch>, L<Calendar::Indonesia::Holiday>,
L<Perinci::Examples>. Try to search for CPAN distributions which specify
L<Rinci> as their prerequisites.

Within the shell, you can browse packages and functions as if they were
directories and executable files (using commands like C<cd>, C<ls>, C<pwd>). You
can call functions like they were command-line programs, by passing command-line
parameters for function arguments.

See L</"COMMANDS"> for list of known commands.

=head1 OPTIONS

=over

=item * --help

Show short help message.

=item * --user=S

Supply HTTP authentication user. You can also set this via environment
L<PERINCI_HTTP_USER> (see L<Perinci::Access> for more details) or from inside
the shell via C<< set user <S> >>.

=item * --password=S

Supply HTTP authentication password. You can also set this via environment
L<PERINCI_HTTP_PASSWORD> (see L<Perinci::Access> for more details) or from
inside the shell via C<< set password <S> >>.

Using the command-line option is not recommended because of security issue
(command-line commands/arguments are usually visible to all users on the system
via commands like B<ps>).

=back

=head1 COMMANDS

=head2 help [command]

Display help message.

=head2 exit

=head2 pwd

Print the current directory (package). When you first enter the shell, current
directory is set to C</>.

=head2 cd [path]

Change directory (package). You can use relative notation (C<../foo>) like in a
Unix filesystem.

=head2 doc <path>

Perform C<meta> Riap request and format the result as text.

=head2 ls [options] [path ...]

List of content of directory (package) or other code entities by performing
C<list> Riap request. If C<path> is not specified, will list the current
directory (package).

Options:

=over

=item * --long (-l)

Add C<< detail => 1 >> to the Riap request, which will return more details.

=back

=head2 list

Alias for C<ls>.

=head2 info [path]

Perform C<info> Riap request on an entity at C<path>.

=head2 request [options] <action> <path> [extra]

Perform Riap request to a code entity at C<path>. Extra request keys can be
specified in C<extra>.

Examples:

 riap> request call /Package/Sub/somefunc '{"args":{"a":1, "b":2}}'
 riap> request list /Package/Sub/somefunc '{"detail":1}'

=head2 call [options] <path> [args]

Perform C<call> Riap request. Note that C<call> command is actually optional:
the shell performs call requests by default on paths.

Examples:

 riap> call /Package/Sub/somefunc '{"foo":1, "bar":2}'

which is equivalent to:

 riap> /Package/Sub/somefunc --foo 1 --bar 2

=head2 set <name> <value>

If invoked without any argument, will list all known settings. If C<name> is
specified but C<value> is not, will show value for that particular setting. If
C<name> and C<value> is both specified, will set a setting's value.

=head1 SETTINGS

Settings are configuration and regulate how the shell behaves.

=head2 user => str

For HTTP authentication.

=head2 password => str

For HTTP authentication.

=head2 output_format => str (default: C<text>)

Set output format for command results. The same formatting is used by
L<Perinci::CmdLine>. See that module or L<Perinci::Result::Format> for more
details.

=head2 debug_riap => bool (default: 0)

Whether to show raw Riap requests and responses being sent to/received from the
server.

=head2 debug_completion => bool (default: 0)

Whether to show debugging information when doing tab completion.

=head2 debug_time_command => bool (default: 0)

Whether to show how long a command takes.

=head2 cache_period => int (default: 300)

Number of seconds to cache Riap results from server, to speed up things like tab
completion.

=head1 FAQ

=head2 The prompt looks rather garbled (e.g. extra " m >" character)!

It looks to be an issue with L<Term::ReadLine::Perl>. Try installing
L<Term::ReadLine::Gnu> instead.

=head2 How do I redirect output to files?

B<riap> is meant to be a simple shell, not a full-blown Unix shell. Besides, a
syntax like this:

 riap> call /Package/Sub/somefunc > /path/to/file

will be confusing since paths map to code entity URIs in B<riap>, not filesystem
paths.

But something like a setting might be implemented if this is a popular feature
request.

=head2 What about variables, aliases, looping, or $other_Unix_shell_feature?

Again, B<riap> is meant to be a simple shell, not a full-blown Unix shell. To do
those things, you are better off using L<peri-run> or L<peri-access> and
incorporate them in a Unix shell script. For example you can write these two
short scripts:

 # list-accounts
 #!/bin/sh
 peri-access call https://yourservice.com/api/Account/list

 # delete-account (input sanitizing is left as exercise for the readers)
 #!/bin/sh
 peri-access call "https://yourservice.com/api/Account/delete?account=$1"

and then write:

 # delete all accounts
 for a in `list-accounts`; do
     delete-account "$a"
 done

=head1 ENVIRONMENT

=head2 PERINCI_HTTP_USER => str

If set, can be used to set C<user> setting (but priority lower than command-line
option C<--user>).

=head2 PERINCI_HTTP_PASSWORD => str

If set, can be used to set C<password> setting (but priority lower than
command-line option C<--password>). This is usually more secure to use than
command-line option, because command-line option is usually visible from all
users on the system via commands like C<ps>.

=head2 RIAP_HISTFILE => str (default: C<~/.riap_history>)

Specify location of command history file. Like in shells, can be set to empty
string to disable history loading/saving.

=head2 RIAPRC => str (default: C<~/.riaprc>)

Specify location of settings file.

=head1 FILES

=head2 C<~/.riap_history>

Command history file.

=head2 C<~/.riaprc>

Settings file (L<IOD> format).

=head1 AUTHOR

perlancar <perlancar@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2017, 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
