File Coverage

blib/lib/Kelp/Module/Symbiosis/Base.pm
Criterion Covered Total %
statement 15 16 93.7
branch 1 2 50.0
condition n/a
subroutine 5 6 83.3
pod 4 4 100.0
total 25 28 89.2


line stmt bran cond sub pod time code
1             package Kelp::Module::Symbiosis::Base;
2             $Kelp::Module::Symbiosis::Base::VERSION = '2.11';
3 9     9   9969 use Kelp::Base qw(Kelp::Module);
  9         17  
  9         79  
4 9     9   2235 use KelpX::Symbiosis::Util;
  9         15  
  9         2816  
5              
6             attr -middleware => sub { [] };
7              
8             # should likely be overriden for a more suitable name
9             # won't break backcompat though
10 5     5 1 73 sub name { ref shift }
11              
12             sub run
13             {
14 12     12 1 34 my ($self) = shift;
15              
16 12         98 my $app = $self->psgi(@_);
17 12         123 return KelpX::Symbiosis::Util::wrap($self, $app);
18             }
19              
20             sub psgi
21             {
22 0     0 1 0 die __PACKAGE__ . " - psgi needs to be reimplemented";
23             }
24              
25             sub build
26             {
27 14     14 1 108627 my ($self, %args) = @_;
28              
29 14 50       66 die 'Symbiosis needs to be loaded before ' . $self->name
30             unless $self->app->can('symbiosis');
31              
32 14         192 KelpX::Symbiosis::Util::load_middleware($self, %args);
33              
34 14         37 $self->app->symbiosis->_link($self->name, $self, $args{mount});
35 14         66 return;
36             }
37              
38             1;
39             __END__
40              
41             =head1 NAME
42              
43             Kelp::Module::Symbiosis::Base - Base class for symbiotic modules
44              
45             =head1 SYNOPSIS
46              
47             package Kelp::Module::MyModule;
48              
49             use Kelp::Base qw(Kelp::Module::Symbiosis::Base);
50              
51             sub psgi
52             {
53             # write code that returns psgi application without middlewares
54             }
55              
56             sub build
57             {
58             my ($self, %args) = @_;
59             $self->SUPER::build(%args);
60              
61             # write initialization code as usual
62             $self->register(some_method => sub { ... });
63             }
64              
65             =head1 DESCRIPTION
66              
67             This class serves as a base for a Kelp module that is supposed to be ran as a standalone Plack application (mounted separately). It takes care of middleware management, mounting into Symbiosis manager and some basic initialization chores. To write a new module that introduces a standalone Plack application as a Kelp module, simply extend this class and override methods: C<psgi build name> (see below for details).
68              
69             =head2 Purpose
70              
71             It is a base for Kelp modules that are meant to be used with Symbiosis - it inherits from L<Kelp::Module>. It can also come very handy because of the built in middleware handling and access to Kelp application's configuration.
72              
73             =head1 METHODS
74              
75             =head2 run
76              
77             sig: run($self)
78              
79             Calls I<psgi()> and wraps its contents in middlewares. Returns a Plack application.
80              
81             =head2 psgi
82              
83             sig: psgi($self, @more_data)
84              
85             By default, this method will throw an exception. It has to be replaced with an actual application producing code in the child class. The resulting application will be wrapped in middlewares from config in I<run()>.
86              
87             B<Must be reimplemented> in a module.
88              
89             =head2 build
90              
91             sig: build($self, %args)
92              
93             Standard Kelp module building method. When reimplementing it's best to call parent's implementation, as middleware initialization happens in base implementation.
94              
95             B<Should be reimplemented> in a module. If it isn't, no extra methods will be added to the Kelp instance, but all the middleware and module registration in Symbiosis will happen anyway.
96              
97             =head2 name
98              
99             sig: name($self)
100              
101             I<new in 1.10>
102              
103             Returns a name of a module - a string. This name will be available in L<Kelp::Module::Symbiosis/loaded> hash as a key, containing the module instance as a value.
104              
105             B<Should be reimplemented> in a module. If it isn't, it will return the name of the package.
106              
107             =head2 middleware
108              
109             sig: middleware($self)
110              
111             Returns an array containing all the middlewares in format: C<[ middleware_class, { middleware_config } ]>. By default, this config comes from module configuration.
112              
113             =head1 CONFIGURATION
114              
115             example configuration could look like this (for L<Kelp::Module::WebSocket::AnyEvent>):
116              
117             modules => [qw/JSON Symbiosis WebSocket::AnyEvent/],
118             modules_init => {
119             Symbiosis => {
120             mount => undef, # kelp will be mounted manually under different path
121             },
122             "WebSocket::AnyEvent" => {
123             serializer => "json",
124             middleware => [qw/Recorder/],
125             middleware_init => {
126             Recorder => { output => "~/recorder.out" },
127             }
128             },
129             }
130              
131             =head2 middleware, middleware_init
132              
133             Middleware specs for this application - see above example. Every module basing on this class can specify its own set of middlewares. They are configured exactly the same as middlewares in Kelp. There's currently no standarized way to retrieve middleware configurations from Kelp into another application (to wrap that application in the same middleware as Kelp), so custom code is needed if such need arise.
134              
135             =head2 mount
136              
137             modules_init => {
138             "Symbiotic::Module" => {
139             mount => '/path',
140             ...
141             },
142             }
143              
144             I<new in 1.10>
145              
146             Should be a string value. If specified, the module will be automatically mounted under that path - there will be no need to call that explicitly, and it will work like: C<< $kelp->symbiosis->mount($path => $module); >>.
147              
148             =head1 SEE ALSO
149              
150             =over 2
151              
152             =item * L<Kelp::Module::Symbiosis>, the module manager
153              
154             =back
155