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