File Coverage

blib/lib/Kelp/Module.pm
Criterion Covered Total %
statement 28 29 96.5
branch 4 4 100.0
condition 3 3 100.0
subroutine 7 8 87.5
pod 2 3 66.6
total 44 47 93.6


line stmt bran cond sub pod time code
1             package Kelp::Module;
2              
3 41     41   27726 use Kelp::Base;
  41         91  
  41         349  
4 41     41   454 use Carp;
  41         110  
  41         13354  
5              
6             our @CARP_NOT = qw(Kelp);
7              
8             attr -app => sub { die "app is required" };
9              
10             sub new
11             {
12 207     207 0 911634 my $self = shift->SUPER::new(@_);
13 207         1110 $self->app;
14 206         797 return $self;
15             }
16              
17             # Override this to register items
18             sub build
19             {
20 0     0 1 0 my ($self, %args) = @_;
21             }
22              
23             sub register
24             {
25 252     252 1 42798 my ($self, %items) = @_;
26 252         1271 while (my ($name, $item) = each(%items)) {
27 41     41   325 no strict 'refs';
  41         78  
  41         1969  
28 41     41   209 no warnings 'redefine';
  41         135  
  41         14847  
29              
30 363         1011 my $app = ref $self->app;
31 363         851 my $glob = "${app}::$name";
32              
33             # Manually check if the glob is being redefined
34 363 100 100     1443 if (!$ENV{KELP_REDEFINE} && $self->app->can($name)) {
35 17         237 croak "Redefining of $glob not allowed";
36             }
37              
38 346 100       1005 if (ref $item eq 'CODE') {
39 171         302 *{$glob} = $item;
  171         1711  
40             }
41             else {
42 175         517 $self->app->{$name} = $item;
43 175     642   1654 *{$glob} = sub { $_[0]->{$name} }
  642         11925  
44 175         733 }
45             }
46             }
47              
48             1;
49              
50             __END__
51              
52             =pod
53              
54             =head1 NAME
55              
56             Kelp::Module - Base class for Kelp modules
57              
58             =head1 SYNOPSIS
59              
60             package Kelp::Module::MyModule;
61             use parent 'Kelp::Module';
62              
63             sub build {
64             my ( $self, %args ) = @_;
65             $self->register( greet => sub { print "Hi there." } );
66             }
67              
68             =head1 DESCRIPTION
69              
70             Provides the base class for creating Kelp modules. Creating a Kelp module means
71             extending this class and overriding the C<build> method.
72             Kelp modules usually C<register> a new method into the web application.
73              
74             =head2 Registering methods
75              
76             Modules use the L</register> method to register new methods into the underlying
77             web application. All the registrations are done in the L</build> subroutine.
78             All types of values can be registered and then accessed as a read-only attribute
79             from the web app. The simplest thing you can register is a scalar value:
80              
81             First...
82              
83             # lib/Kelp/Module/Month.pm
84             package Kelp::Module::Month;
85             use Kelp::Base 'Kelp::Module';
86              
87             sub build {
88             my ( $self, %args ) = @_;
89             $self->register( month => 'October' );
90             }
91              
92             Then ...
93              
94             # lib/MyApp.pm
95             package MyApp;
96             use parent 'Kelp';
97              
98             sub build {
99             my $self = shift;
100             $self->load_module("Month");
101             }
102              
103             sub is_it_october_yet {
104             my $self = shift;
105             if ( $self->month eq 'October' ) {
106             return "It is October";
107             }
108             return "Not yet.";
109             }
110              
111             The above example doesn't do anything meaningful, but it's a good
112             way to show how to create and use Kelp modules. Pay attention to the next
113             example, as it will show you how to register an anonymous subroutine:
114              
115             package Kelp::Module::Date;
116             use Kelp::Base 'Kelp::Module';
117             use DateTime;
118              
119             sub build {
120             my ( $self, %args ) = @_;
121             $self->register(
122             date => sub {
123             return DateTime->from_epoch( epoch => time );
124             }
125             );
126             }
127              
128             Now, each time you use C<$self-E<gt>date> in the web application, you will create
129             a new C<DateTime> object for the current time.
130              
131             It is more practical to register an already created object. Consider this
132             example, which uses C<Redis>, initializes an instance of it and registers it as
133             a method in the web app:
134              
135             package Kelp::Module::Redis;
136             use Kelp::Base 'Kelp::Module';
137             use Redis;
138              
139             sub build {
140             my ( $self, %args ) = @_;
141             my $redis = Redis->new(%args);
142             $self->register( redis => $redis );
143             }
144              
145             =head2 Passing arguments to your module
146              
147             The arguments for all modules are taken from the configuration. If you want to
148             pass arguments for your C<Redis> module (example above), you will have to have a
149             structure in your config, similar to this:
150              
151             Example of C<conf/myapp.pl>:
152              
153             {
154             # Load module Redis on start
155             modules => ['Redis'],
156             modules_init => {
157             Redis => {
158             server => '192.168.0.1:6379',
159             encoding => 'UTF-8',
160             password => 'boo'
161             }
162             }
163             };
164              
165             The hash specified by C<Redis> will be sent as C<%args> in the C<build> method
166             of the module.
167              
168             =head2 Loading modules that live outside of the Kelp::Module namespace
169              
170             Kelp will automatically prefix all modules with C<Kelp::Module>, so a module name
171             C<Redis> should live in C<Kelp::Module::Redis>.
172             To use fully qualified modules that live outside of the C<Kelp::Module> namespace,
173             prefix the name with a plus sign.
174              
175             {
176             # Load a module that lives outside of Kelp::Module
177             modules => ["+Fully::Qualified::Name"],
178             modules_init => {
179             "+Fully::Qualified::Name" => {...}
180             }
181             };
182              
183             =head1 METHODS
184              
185             =head2 build
186              
187             C<build( %args )>
188              
189             Each module must override this one in order to register new methods. The
190             C<%args> hash will be taken from the configuration.
191              
192             =head2 register
193              
194             C<register( %items )>
195              
196             Registers one or many methods into the web application.
197              
198             $self->register(
199             json => JSON->new,
200             yaml => YAML->new
201             );
202              
203             =cut
204