McBain
view release on metacpan or search on metacpan
lib/McBain.pm view on Meta::CPAN
=back
=head2 get( $route, %opts )
Shortcut for C<provide( 'GET', $route, %opts )>
=head2 post( $route, %opts )
Shortcut for C<provide( 'POST', $route, %opts )>
=head2 put( $route, %opts )
Shortcut for C<provide( 'PUT', $route, %opts )>
=head2 del( $route, %opts )
Shortcut for C<provide( 'DELETE', $route, %opts )>
=head2 pre_route( $cb->( $self, $meth_and_route, \%params ) )
=head2 post_route( $cb->( $self, $meth_and_route, \$ret ) )
Define a post_route method to run before/after every request to a route in the
defining topic. See L</"PRE-ROUTES AND POST-ROUTES"> for details.
=head1 METHODS
The following methods will be available on importing classes/objects:
=head2 call( @args )
Calls the API, requesting the execution of a certain route. This is the
main way your API is used. The arguments it expects to receive and its
behavior are dependent on the L<McBain runner|"MCBAIN RUNNERS"> used. Refer to the docs
of the runner you wish to use for more information.
=head2 forward( $namespace, [ \%params ] )
For usage from within API methods; this simply calls a method of the
the API with the provided parameters (if any) and returns the result.
With C<forward()>, an API method can call other API methods or even
itself (for recursive operations).
C<$namespace> is the method and route to execute, in the format C<< <METHOD>:<ROUTE> >>,
where C<METHOD> is one of C<GET>, C<POST>, C<PUT>, C<DELETE>, and C<ROUTE>
starts with a forward slash.
=head2 is_root( )
Returns a true value if the module is the root topic of the API.
Mostly used internally and in L<McBain runner|"MCBAIN RUNNERS"> modules.
=cut
our %INFO;
sub import {
my $target = caller;
return if $target eq 'main';
my $me = shift;
strict->import;
warnings->import(FATAL => 'all');
return if $INFO{$target};
# find the root of this API (if it's not this class)
my $root = _find_root($target);
# create the routes hash for $root
$INFO{$root} ||= {};
# were there any options passed?
if (scalar @_) {
my %opts = map { s/^-//; $_ => 1 } @_;
# apply the options to the root package
$INFO{$root}->{_opts} = \%opts;
}
# figure out the topic name from this class
my $topic = '/';
unless ($target eq $root) {
my $rel_name = ($target =~ m/^${root}::(.+)$/)[0];
$topic = '/'.lc($rel_name);
$topic =~ s!::!/!g;
}
no strict 'refs';
# export the is_root() subroutine to the target topic,
# so that it knows whether it is the root of the API
# or not
*{"${target}::is_root"} = sub {
exists $INFO{$target};
};
if ($target eq $root) {
*{"${target}::import"} = sub {
my $t = caller;
shift;
my $runner = scalar @_ ? 'McBain::'.ucfirst(substr($_[0], 1)) : 'McBain::Directly';
eval "require $runner";
croak "Can't load runner module $runner: $@"
if $@;
$INFO{$root}->{_runner} = $runner;
# let the runner module do needed initializations,
# as the init method usually needs the is_root subroutine,
# this statement must come after exporting is_root()
$runner->init($target);
};
}
# export the provide subroutine to the target topic,
# so that it can define routes and methods.
*{"${target}::provide"} = sub {
my ($method, $name) = (shift, shift);
my %opts = @_;
# make sure the route starts and ends
# with a slash, and prefix it with the topic
( run in 1.266 second using v1.01-cache-2.11-cpan-7fcb06a456a )