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             $Kelp::Module::Symbiosis::Base::VERSION = '1.13';
2             use Kelp::Base qw(Kelp::Module);
3 5     5   3911 use Kelp::Module::Symbiosis::_Util;
  5         11  
  5         24  
4 5     5   804  
  5         8  
  5         1194  
5             attr -middleware => sub { [] };
6              
7             # should likely be overriden for a more suitable name
8             # won't break backcompat though
9              
10 3     3 1 38 {
11             my ($self) = shift;
12              
13             my $app = $self->psgi(@_);
14 27     27 1 48 return Kelp::Module::Symbiosis::_Util::wrap($self, $app);
15             }
16 27         93  
17 27         215 {
18             die __PACKAGE__ . " - psgi needs to be reimplemented";
19             }
20              
21             {
22 0     0 1 0 my ($self, %args) = @_;
23              
24             die 'Kelp::Module::Symbiosis needs to be loaded before ' . ref $self
25             unless $self->app->can('symbiosis');
26              
27 8     8 1 47022 Kelp::Module::Symbiosis::_Util::load_middleware($self, %args);
28              
29 8 50       22 $self->app->symbiosis->_link($self->name, $self, $args{mount});
30             return;
31             }
32 8         72  
33             1;
34 8         19  
35 8         21 =head1 NAME
36              
37             Kelp::Module::Symbiosis::Base - Base class for symbiotic modules
38              
39             =head1 SYNOPSIS
40              
41             package Kelp::Module::MyModule;
42              
43             use Kelp::Base qw(Kelp::Module::Symbiosis::Base);
44              
45             sub psgi
46             {
47             # write code that returns psgi application without middlewares
48             }
49              
50             sub build
51             {
52             my ($self, %args) = @_;
53             $self->SUPER::build(%args);
54              
55             # write initialization code as usual
56             $self->register(some_method => sub { ... });
57             }
58              
59             =head1 DESCRIPTION
60              
61             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).
62              
63             =head2 Purpose
64              
65             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.
66              
67             =head1 METHODS
68              
69             =head2 run
70              
71             sig: run($self)
72              
73             Calls I<psgi()> and wraps its contents in middlewares. Returns a Plack application.
74              
75             =head2 psgi
76              
77             sig: psgi($self, @more_data)
78              
79             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()>.
80              
81             B<Must be reimplemented> in a module.
82              
83             =head2 build
84              
85             sig: build($self, %args)
86              
87             Standard Kelp module building method. When reimplementing it's best to call parent's implementation, as middleware initialization happens in base implementation.
88              
89             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.
90              
91             =head2 name
92              
93             sig: name($self)
94              
95             I<new in 1.10>
96              
97             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.
98              
99             B<Should be reimplemented> in a module. If it isn't, it will return the name of the package.
100              
101             =head2 middleware
102              
103             sig: middleware($self)
104              
105             Returns an array containing all the middlewares in format: C<[ middleware_class, { middleware_config } ]>. By default, this config comes from module configuration.
106              
107             =head1 CONFIGURATION
108              
109             example configuration could look like this (for L<Kelp::Module::WebSocket::AnyEvent>):
110              
111             modules => [qw/JSON Symbiosis WebSocket::AnyEvent/],
112             modules_init => {
113             Symbiosis => {
114             mount => undef, # kelp will be mounted manually under different path
115             },
116             "WebSocket::AnyEvent" => {
117             serializer => "json",
118             middleware => [qw/Recorder/],
119             middleware_init => {
120             Recorder => { output => "~/recorder.out" },
121             }
122             },
123             }
124              
125             =head2 middleware, middleware_init
126              
127             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.
128              
129             =head2 mount
130              
131             modules_init => {
132             "Symbiotic::Module" => {
133             mount => '/path',
134             ...
135             },
136             }
137              
138             I<new in 1.10>
139              
140             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); >>.
141              
142             =head1 SEE ALSO
143              
144             =over 2
145              
146             =item * L<Kelp::Module::Symbiosis>, the module manager
147              
148             =back
149