NAME
    Perinci::Access::InProcess - Use Rinci access protocol (Riap) to access
    Perl code

VERSION
    version 0.46

SYNOPSIS
     # in Your/Module.pm

     package My::Module;
     our %SPEC;

     $SPEC{mult2} = {
         v => 1.1,
         summary => 'Multiple two numbers',
         args => {
             a => { schema=>'float*', req=>1, pos=>0 },
             b => { schema=>'float*', req=>1, pos=>1 },
         },
         examples => [
             {args=>{a=>2, b=>3}, result=>6},
         ],
     };
     sub mult2 {
         my %args = @_;
         [200, "OK", $args{a} * $args{b}];
     }

     $SPEC{multn} = {
         v => 1.1,
         summary => 'Multiple many numbers',
         args => {
             n => { schema=>[array=>{of=>'float*'}], req=>1, pos=>0, greedy=>1 },
         },
     };
     sub multn {
         my %args = @_;
         my @n = @{$args{n}};
         my $res = 0;
         if (@n) {
             $res = shift(@n);
             $res *= $_ while $_ = shift(@n);
         }
         return [200, "OK", $res];
     }

     1;

     # in another file

     use Perinci::Access::InProcess;
     my $pa = Perinci::Access::Process->new();

     # list all functions in package
     my $res = $pa->request(list => '/My/Module/', {type=>'function'});
     # -> [200, "OK", ['pl:/My/Module/mult2', 'pl:/My/Module/multn']]

     # call function
     my $res = $pa->request(call => 'pl:/My/Module/mult2', {args=>{a=>2, b=>3}});
     # -> [200, "OK", 6]

     # get function metadata
     $res = $pa->request(meta => '/Foo/Bar/multn');
     # -> [200, "OK", {v=>1.1, summary=>'Multiple many numbers', ...}]

DESCRIPTION
    This class implements Rinci access protocol (Riap) to access local Perl
    code. This might seem like a long-winded and slow way to access things
    that are already accessible from Perl like functions and metadata (in
    %SPEC). Indeed, if you do not need Riap, you can access your module just
    like any normal Perl module.

    Supported features:

    *   Basic Riap actions

        These include "info", "actions", "meta", "list", and "call" actions.

    *   Transaction/undo

        According to Rinci::Transaction.

    *   Function wrapping

        Wrapping is used to convert argument passing style, produce result
        envelope, add argument validation, as well as numerous other
        functionalities. See Perinci::Sub::Wrapper for more details on
        wrapping. The default behavior will call wrapped functions.

    *   Custom location of metadata

        By default, metadata are assumed to be stored embedded in Perl
        source code in %SPEC package variables (with keys matching function
        names, $variable names, or ":package" for the package metadata
        itself).

        You can override "get_meta()" to provide custom behavior. For
        example, you can store metadata in separate file or database.

    *   Custom code entity tree

        By default, tree are formed by traversing Perl packages and their
        contents, for example if a "list" action is requested on uri
        "/Foo/Bar/" then the contents of package "Foo::Bar" and its
        subpackages will be traversed for the entities.

        You can override "action_list()" to provide custom behavior. For
        example, you can lookup from the database.

    *   Progress indicator

        Functions can express that they do progress updating through the
        "features" property in its metadata:

         features => {
             progress => 1,
             ...
         }

        For these functions, periai will then pass a special argument
        "-progress" containing Progress::Any object. Functions can update
        progress using this object.

  How request is processed
    User calls "$pa->request($action => $uri, \%extras)". Internally, the
    method creates a hash $req which contains Riap request keys as well as
    internal information about the Riap request (the latter will be prefixed
    with dash "-"). Initially it will contain "action" and "uri" (converted
    to URI object) and the %extras keys from the request() arguments sent by
    the user.

    Internal "_parse_uri()" method will be called to parse "uri" into
    "-uri_dir" (the "dir" part), "-uri_leaf" (the "basename" part), and
    "-perl_package". Forbidden or invalid paths will cause this method to
    return an enveloped error response and the request to stop. For example,
    if "uri" is "/Foo/Bar/" then "-uri_dir" is "/Foo/Bar/" and "-uri_leaf"
    is an empty string. If "uri" is "/Foo/Bar/baz" then "-uri_dir" is
    "/Foo/Bar/" while "-uri_leaf" is "baz". "-uri_dir" will be used for the
    "list" action. In both cases, "-perl_package" will be set to "Foo::Bar".

    The code entity type is then determined currently using a few simple
    heuristic rules: if "-uri_leaf" is empty string, type is "package". If
    "-uri_leaf" begins with "[$%@]", type is "variable". Otherwise, type is
    "function". "-type" will be set.

    After this, the appropriate "action_ACTION()" method will be called. For
    example if action is "meta" then "action_meta()" method will be called,
    with $req as the argument. This will in turn, depending on the action,
    either call "get_meta()" (for example if action is "meta") or
    "get_code()" (for example if action is "call"), also with $req as the
    argument. "get_meta()" and "get_code()" should return nothing on
    success, and set either "-meta" (a defhash containing Rinci metadata) or
    "-code" (a coderef), respectively. On error, they must return an
    enveloped error response.

    "get_meta()" or "get_code()" might call "_load_module()" to load Perl
    modules if the "load" attribute is set to true.

METHODS
  PKG->new(%attrs) => OBJ
    Instantiate object. Known attributes:

    *   load => BOOL (default: 1)

        Whether to load Perl modules that are requested.

    *   after_load => CODE

        If set, code will be executed the first time Perl module is
        successfully loaded.

    *   wrap => BOOL (default: 1)

        If set to false, then wil use original subroutine and metadata
        instead of wrapped ones, for example if you are very concerned about
        performance (do not want to add another eval {} and subroutine call
        introduced by wrapping) or do not need the functionality provided by
        the wrapper (e.g. your function does not die and already validates
        its arguments, you do not want Sah schemas in the metadata to be
        normalized, etc).

        Wrapping is implemented inside "get_meta()" and "get_code()".

    *   extra_wrapper_args => HASH

        If set, will be passed to Perinci::Sub::Wrapper's wrap_sub() when
        wrapping subroutines. Some applications of this include: adding
        "timeout" or "result_postfilter" properties to functions.

        This is only relevant if you enable "wrap".

    *   extra_wrapper_convert => HASH

        If set, will be passed to Perinci::Sub::Wrapper wrap_sub()'s
        "convert" argument when wrapping subroutines. Some applications of
        this include: changing "default_lang" of metadata.

        This is only relevant if you enable "wrap".

    *   cache_size => INT (default: 100)

        Specify cache size (in number of items). Cache saves the result of
        function wrapping so future requests to the same function need not
        involve wrapping again. Setting this to 0 disables caching.

        Caching is implemented inside "get_meta()" and "get_code()" so you
        might want to implement your own caching if you override those.

    *   allow_paths => REGEX|STR|ARRAY

        If defined, only requests with "uri" matching specified path will be
        allowed. Can be a string (e.g. "/spanel/api/") or regex (e.g.
        "qr{^/[^/]+/api/}") or an array of those.

    *   deny_paths => REGEX|STR|ARRAY

        If defined, requests with "uri" matching specified path will be
        denied. Like "allow_paths", value can be a string (e.g.
        "/spanel/api/") or regex (e.g. "qr{^/[^/]+/api/}") or an array of
        those.

    *   use_tx => BOOL (default: 0)

        Whether to allow transaction requests from client. Since this can
        cause the server to store transaction/undo data, this must be
        explicitly allowed.

        You need to install Perinci::Tx::Manager for transaction support
        (unless you are using another transaction manager).

    *   custom_tx_manager => STR|CODE

        Can be set to a string (class name) or a code that is expected to
        return a transaction manager class.

        By default, Perinci::Tx::Manager is instantiated and maintained (not
        reinstantiated on every request), but if "custom_tx_manager" is a
        coderef, it will be called on each request to get transaction
        manager. This can be used to instantiate Perinci::Tx::Manager in a
        custom way, e.g. specifying per-user transaction data directory and
        limits, which needs to be done on a per-request basis.

  $pa->request($action => $server_url, \%extra) => $res
    Process Riap request and return enveloped result. $server_url will be
    used as the Riap request key 'uri', as there is no server in this case.

  $pa->parse_url($server_url) => HASH
FAQ
  Why wrap?
    The wrapping process accomplishes several things, among others: checking
    of metadata, normalization of schemas in metadata, also argument
    validation and exception trapping in function.

    The function wrapping introduces a small overhead when performing a sub
    call (typically around several to tens of microseconds on an Intel Core
    i5 1.7GHz notebook). This is usually smaller than the overhead of
    Perinci::Access::InProcess itself (typically in the range of 100
    microseconds). But if you are concerned about the wrapping overhead, see
    the "use_wrapped_sub" option.

  Why %SPEC?
    The name was first chosen when during Sub::Spec era, so it stuck.

SEE ALSO
    Riap, Rinci

AUTHOR
    Steven Haryanto <stevenharyanto@gmail.com>

COPYRIGHT AND LICENSE
    This software is copyright (c) 2013 by Steven Haryanto.

    This is free software; you can redistribute it and/or modify it under
    the same terms as the Perl 5 programming language system itself.

