Dancer-Plugin-RPC-RESTISH
view release on metacpan or search on metacpan
example/lib/Example/EndpointConfig.pm view on Meta::CPAN
package Example::EndpointConfig;
use Moo;
use Scalar::Util qw/ blessed /;
=head1 NAME
Example::EndpointConfig - Takes away the details of L<Dancer::Plugin::RPC>
=head1 SYNOPSIS
use Dancer ':syntax';
use Bread::Board;
use Example::EndpointConfig { plugins => ['RPC::JSONRPC', 'RPC::XMLRPC'] };
my $config = Example::EndpointConfig->new(
publish => 'pod',
bread_board => container(
app => as {
container apis => as {
service 'Example::API::MetaCpan' => as (
class => 'Example::API::MetaCpan',
dependencies => {
# attributes needed for instantiation
# or objects from the same container
mc_client => '../clients/Client::MetaCpan',
},
),
};
container clients => as {
service 'Client::MetaCpan' => as (
class => 'Client::MetaCpan',
dependencies => {
base_uri => literal config->{base_uri},
),
};
};
),
);
$config->register_endpoint('RPC::JSONRPC' => '/metacpan');
$config->register_endpoint('RPC::XMLRPC' => '/metacpan');
=head1 ATTRIBUTES
=head2 publish [required]
This attribute can have the value of B<config> or B<pod>, it will be bassed to
L<Dancer::Plugin::RPC>
=head2 callback [optional]
This attribute is passed directly to L<Dancer::Plugin::RPC>
=head2 bread_board [required]
This is an instatiated L<Bread::Board::Container> object, that defines the
components of this service and their interaction.
=head2 code_wrapper [optional/lazy]
The code-wrapper is passed to L<Dancer::Plugin::RPC>. The default code-wrapper
uses the L<Bread::Board::Container> to spawn the code for the
Remote-Procedure-Call.
=head2 plugin_arguments [optional]
This hashref is directly passed to L<Dancer::Plugin::RPC>
=cut
has publish => (
is => 'ro',
isa => sub { $_[0] =~ m/^(?:config|pod)$/ },
required => 1
);
has callback => (
is => 'ro',
isa => sub { ref($_[0]) eq 'CODE' || !defined($_[0]) },
required => 0
);
has bread_board => (
is => 'ro',
isa => sub { blessed($_[0]) eq 'Bread::Board::Container' },
required => 1
);
has code_wrapper => (
is => 'lazy',
isa => sub { ref($_[0]) eq 'CODE' },
);
has plugin_arguments => (
is => 'ro',
isa => sub { ref($_[0]) eq 'HASH' || !defined($_[0]) },
required => 0,
);
my %_plugin_info;
use Dancer::RPCPlugin::PluginNames;
sub import {
# Make sure all plugins are loaded before calling
# `use Example::EndpointConfig;`
my @loaded_plugins = map {
(my $module = $_) =~ s{/}{::}g;
$module =~ s{.pm$}{};
$module
} grep { m{^Dancer/Plugin/RPC/} } keys %INC;
for my $full_plugin (@loaded_plugins) {
(my $plugin = $full_plugin) =~ s{^Dancer::Plugin::}{};
eval "use $full_plugin";
die "Cannot load $full_plugin ($plugin): $@" if $@;
(my $plugin_name = $plugin) =~ s{RPC::(\w+)}{\L$1};
$_plugin_info{$plugin} = {
name => $plugin_name,
registrar => $full_plugin->can($plugin_name),
};
}
}
=head1 DESCRIPTION
=cut
sub _build_code_wrapper {
my $self = shift;
return sub {
my ($code, $package, $method, @arguments) = @_;
my $instance = $self->bread_board->resolve(service => "apis/$package");
return $instance->$code(@arguments);
};
}
sub _registrar_for_plugin {
my $self = shift;
my ($plugin) = @_;
return $_plugin_info{$plugin}{registrar} // die "Cannot find plugin '$plugin'";
}
=head2 endpoint_config($path)
Returns a config-hash for the C<Dancer::Plugin::RPC::*> plugins.
=cut
sub endpoint_config {
my $self = shift;
my ($path) = @_;
return {
publish => $self->publish,
code_wrapper => $self->code_wrapper,
(defined $self->callback
? (callback => $self->callback)
: ()
),
(defined $self->plugin_arguments
? (%{ $self->plugin_arguments })
: ()
),
};
}
=head2 register_endpoint($plugin, $path)
=cut
sub register_endpoint {
my $self = shift;
my ($plugin, $path) = @_;
my $registrar = $self->_registrar_for_plugin($plugin);
$registrar->($path, $self->endpoint_config($path));
}
use namespace::autoclean;
1;
=head1 COPYRIGHT
(c) MMXIX - Abe Timmerman <abeltje@cpan.org>
=cut
( run in 0.935 second using v1.01-cache-2.11-cpan-0bd6704ced7 )