NAME
Perinci::Access::InProcess - Use Rinci access protocol (Riap) to access Perl code
VERSION
version 0.39
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", ['/My/Module/mult2', '/My/Module/multn']]
# call function
my $res = $pa->request(call => '/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.
But Perinci::Access::InProcess (called periai for short) offers several benefits:
Custom location of metadata
Metadata can be placed not in
%SPEC
but elsewhere, like in another file or even database, or even by merging from several sources.Function wrapping
Can be used to convert argument passing style or produce result envelope, so you get a consistent interface.
Transaction/undo
This class implements Riap::Transaction.
Location of metadata
By default, the metadata should be put in %SPEC
package variable, in a key with the same name as the URI path leaf (use :package
for the package itself). For example, metadata for /Foo/Bar/$var
should be put in $Foo::Bar::SPEC{'$var'}
, /Foo/Bar/
in $Foo::Bar::SPEC{':package'}
. The metadata for the top-level namespace (/
) should be put in $main::SPEC{':package'}
.
If you want to put metadata elsewhere, you can pass meta_accessor
=> 'Custom_Class'
to constructor argument, or set this in your module:
our $PERINCI_META_ACCESSOR = 'Custom::Class';
The default accessor class is Perinci::MetaAccessor::Default. Alternatively, you can simply devise your own system to retrieve metadata which you can put in %SPEC
at the end.
Progress indicator
periai can also display progress indicator for function that does progress updating. Function expresses that it does progress updating through the features
property in its metadata:
features => {
progress => 1,
...
}
periai will then pass a special argument -progress
containing Progress::Any object.
METHODS
PKG->new(%attrs) => OBJ
Instantiate object. Known attributes:
meta_accessor => STR (default 'Perinci::MetaAccessor::Default')
load => BOOL (default 1)
Whether attempt to load modules using
require
.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.
after_load => CODE
If set, code will be executed the first time Perl module is successfully loaded.
use_wrapped_sub => BOOL (default: 1)
If set to false, then wil use original subroutine instead of wrapped one, 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, etc).
Can also be set on a per-entity basis by setting the
_perinci.access.inprocess.use_wrapped_sub
metadata property.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
orresult_postfilter
properties to functions.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.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.
Some notes:
Metadata returned by the 'meta' action has normalized schemas in them
Schemas in metadata (like in the
args
andreturn
property) are normalized by Perinci::Sub::Wrapper.
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
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.