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 )