| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Kelp::Less; |
|
2
|
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
2426
|
use Kelp; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
17
|
|
|
4
|
2
|
|
|
2
|
|
15
|
use Kelp::Base -strict; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our @EXPORT = qw/ |
|
7
|
|
|
|
|
|
|
app |
|
8
|
|
|
|
|
|
|
attr |
|
9
|
|
|
|
|
|
|
config |
|
10
|
|
|
|
|
|
|
del |
|
11
|
|
|
|
|
|
|
debug |
|
12
|
|
|
|
|
|
|
error |
|
13
|
|
|
|
|
|
|
get |
|
14
|
|
|
|
|
|
|
module |
|
15
|
|
|
|
|
|
|
named |
|
16
|
|
|
|
|
|
|
param |
|
17
|
|
|
|
|
|
|
post |
|
18
|
|
|
|
|
|
|
put |
|
19
|
|
|
|
|
|
|
req |
|
20
|
|
|
|
|
|
|
res |
|
21
|
|
|
|
|
|
|
route |
|
22
|
|
|
|
|
|
|
run |
|
23
|
|
|
|
|
|
|
session |
|
24
|
|
|
|
|
|
|
stash |
|
25
|
|
|
|
|
|
|
template |
|
26
|
|
|
|
|
|
|
view |
|
27
|
|
|
|
|
|
|
/; |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
our $app; |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
sub import { |
|
32
|
2
|
|
|
2
|
|
13
|
my $class = shift; |
|
33
|
2
|
|
|
|
|
5
|
my $caller = caller; |
|
34
|
2
|
|
|
2
|
|
301
|
no strict 'refs'; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
1692
|
|
|
35
|
2
|
|
|
|
|
6
|
for my $sub (@EXPORT) { |
|
36
|
40
|
|
|
|
|
1674
|
*{"${caller}::$sub"} = eval("\\\&$sub"); |
|
|
40
|
|
|
|
|
285
|
|
|
37
|
|
|
|
|
|
|
} |
|
38
|
|
|
|
|
|
|
|
|
39
|
2
|
|
|
|
|
13
|
strict->import; |
|
40
|
2
|
|
|
|
|
17
|
warnings->import; |
|
41
|
2
|
|
|
|
|
99
|
feature->import(':5.10'); |
|
42
|
|
|
|
|
|
|
|
|
43
|
2
|
|
|
|
|
10
|
$app = Kelp->new(config_module => 'Config::Less', @_); |
|
44
|
2
|
|
|
|
|
7
|
$app->routes->base('main'); |
|
45
|
|
|
|
|
|
|
} |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub route { |
|
48
|
17
|
|
|
17
|
1
|
88
|
my ( $path, $to ) = @_; |
|
49
|
17
|
|
|
|
|
59
|
$app->add_route( $path, $to ); |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub get { |
|
53
|
2
|
|
|
2
|
1
|
16
|
my ( $path, $to ) = @_; |
|
54
|
2
|
50
|
|
|
|
13
|
route ref($path) ? $path : [ GET => $path ], $to; |
|
55
|
|
|
|
|
|
|
} |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub post { |
|
58
|
1
|
|
|
1
|
1
|
4
|
my ( $path, $to ) = @_; |
|
59
|
1
|
50
|
|
|
|
5
|
route ref($path) ? $path : [ POST => $path ], $to; |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub put { |
|
63
|
1
|
|
|
1
|
1
|
4
|
my ( $path, $to ) = @_; |
|
64
|
1
|
50
|
|
|
|
6
|
route ref($path) ? $path : [ PUT => $path ], $to; |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub del { |
|
68
|
1
|
|
|
1
|
1
|
3
|
my ( $path, $to ) = @_; |
|
69
|
1
|
50
|
|
|
|
9
|
route ref($path) ? $path : [ DELETE => $path ], $to; |
|
70
|
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub run { |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# If we're running a test, then return the entire app, |
|
75
|
|
|
|
|
|
|
# otherwise return the PSGI subroutine |
|
76
|
1
|
50
|
|
1
|
1
|
51
|
return $ENV{KELP_TESTING} ? $app : $app->run; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
3
|
|
|
3
|
1
|
24
|
sub app { $app } |
|
80
|
2
|
|
|
2
|
1
|
15
|
sub attr { Kelp::Base::attr( ref($app), @_ ) } |
|
81
|
2
|
|
|
2
|
1
|
16
|
sub param { $app->param(@_) } |
|
82
|
0
|
|
|
0
|
0
|
0
|
sub session { $app->session(@_) } |
|
83
|
2
|
|
|
2
|
1
|
14
|
sub stash { $app->stash(@_) } |
|
84
|
1
|
|
|
1
|
1
|
8
|
sub named { $app->named(@_) } |
|
85
|
1
|
|
|
1
|
1
|
11
|
sub req { $app->req } |
|
86
|
1
|
|
|
1
|
1
|
7
|
sub res { $app->res } |
|
87
|
1
|
|
|
1
|
1
|
11
|
sub template { $app->res->template(@_) } |
|
88
|
0
|
|
|
0
|
1
|
0
|
sub view { $app->res->template(@_) } |
|
89
|
0
|
0
|
|
0
|
0
|
0
|
sub debug { $app->debug(@_) if $app->can('debug') } |
|
90
|
0
|
0
|
|
0
|
0
|
0
|
sub error { $app->error(@_) if $app->can('error') } |
|
91
|
2
|
|
|
2
|
1
|
118
|
sub module { $app->load_module(@_) } |
|
92
|
1
|
|
|
1
|
1
|
9
|
sub config { $app->config(@_) } |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
1; |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
__END__ |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=pod |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=head1 NAME |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
Kelp::Less - Quick prototyping with Kelp |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
use Kelp::Less; |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
get '/person/:name' => sub { |
|
109
|
|
|
|
|
|
|
"Hello " . named 'name'; |
|
110
|
|
|
|
|
|
|
}; |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
run; |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
This class exists to provide a way for quick and sloppy prototyping of a web |
|
117
|
|
|
|
|
|
|
application. It is a wrapper for L<Kelp>, which imports several keywords, making |
|
118
|
|
|
|
|
|
|
it easier and less verbose to create a quick web app. |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
It's called C<Less>, because there is less typing involved, and |
|
121
|
|
|
|
|
|
|
because it is suited for smaller, less complicated web projects. We encourage |
|
122
|
|
|
|
|
|
|
you to use it anywhere you see fit, however for mid-size and big applications we |
|
123
|
|
|
|
|
|
|
recommend that you use the fully structured L<Kelp>. This way you can take |
|
124
|
|
|
|
|
|
|
advantage of its powerful router, initialization and testing capabilities. |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=head1 QUICK START |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
Each web app begins with C<use Kelp::Less;>. This automatically imports C<strict>, |
|
129
|
|
|
|
|
|
|
C<warnings>, C<v5.10> as well as several useful functions. You can pass any |
|
130
|
|
|
|
|
|
|
parameters to the constructor at the C<use> statement: |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
use Kelp::Less mode => 'development'; |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
The above is equivalent to: |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
use Kelp; |
|
137
|
|
|
|
|
|
|
my $app = Kelp->new( mode => 'development' ); |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
After that, you could add any initializations and attributes. For example, connect |
|
140
|
|
|
|
|
|
|
to a database or setup cache. C<Kelp::Less> exports L<attr|Kelp::Base/attr>, |
|
141
|
|
|
|
|
|
|
so you can use it to register attributes to your app. |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Connect to DBI and CHI right away |
|
144
|
|
|
|
|
|
|
attr dbh => sub { |
|
145
|
|
|
|
|
|
|
DBI->connect( @{ app->config('database') } ); |
|
146
|
|
|
|
|
|
|
}; |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
attr cache => sub { |
|
149
|
|
|
|
|
|
|
CHI->new( @{ app->config('cache') } ); |
|
150
|
|
|
|
|
|
|
}; |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# Another lazy attribute. |
|
153
|
|
|
|
|
|
|
attr version => sub { |
|
154
|
|
|
|
|
|
|
app->dbh->selectrow_array("SELECT version FROM vars"); |
|
155
|
|
|
|
|
|
|
}; |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# Later: |
|
158
|
|
|
|
|
|
|
app->dbh->do(...); |
|
159
|
|
|
|
|
|
|
app->cache->get(...); |
|
160
|
|
|
|
|
|
|
if ( app->version ) { ... } |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Now is a good time to add routes. Routes are added via the L</route> keyword and |
|
163
|
|
|
|
|
|
|
they are automatically registered in your app. A route needs two parameters - |
|
164
|
|
|
|
|
|
|
C<path> and C<destination>. These are exactly equivalent to L<Kelp::Routes/add>, |
|
165
|
|
|
|
|
|
|
and you are encouraged to read its POD to get familiar with how to define routes. |
|
166
|
|
|
|
|
|
|
Here are a few examples for the impatient: |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# Add a 'catch-all-methods' route and send it to an anonymous sub |
|
169
|
|
|
|
|
|
|
route '/hello/:name' => sub { |
|
170
|
|
|
|
|
|
|
return "Hello " . named('name'); |
|
171
|
|
|
|
|
|
|
}; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# Add a POST route |
|
174
|
|
|
|
|
|
|
route [ POST => '/edit/:id' ] => sub { |
|
175
|
|
|
|
|
|
|
# Do something with named('id') |
|
176
|
|
|
|
|
|
|
}; |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# Route that runs an existing sub in your code |
|
179
|
|
|
|
|
|
|
route '/login' => 'login'; |
|
180
|
|
|
|
|
|
|
sub login { |
|
181
|
|
|
|
|
|
|
... |
|
182
|
|
|
|
|
|
|
} |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
Each route subroutine receives C<$self> and all named placeholders. |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
route '/:id/:page' => sub { |
|
187
|
|
|
|
|
|
|
my ( $self, $id, $page ) = @_; |
|
188
|
|
|
|
|
|
|
}; |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
Here, C<$self> is the app object and it can be used the same way as in a full |
|
191
|
|
|
|
|
|
|
L<Kelp> route. For the feeling of magic and eeriness, C<Kelp::Lite> aliases |
|
192
|
|
|
|
|
|
|
C<app> to C<$self>, so the former can be used as a full substitute to the |
|
193
|
|
|
|
|
|
|
latter. See the exported keywords section for more information. |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
After you have added all of your routes, it is time to run the app. This is done |
|
196
|
|
|
|
|
|
|
via a single command: |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
run; |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
It returns PSGI ready subroutine, so you can immediately deploy your new app via |
|
201
|
|
|
|
|
|
|
Plack: |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
> plackup myapp.psgi |
|
204
|
|
|
|
|
|
|
HTTP::Server::PSGI: Accepting connections at http://0:5000/ |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=head1 KEYWORDS |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
The following list of keywords are exported to allow for less typing in |
|
209
|
|
|
|
|
|
|
C<Kelp::Less>: |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=head2 app |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
This a full alias for C<$self>. It is the application object, and an |
|
214
|
|
|
|
|
|
|
instance of the C<Kelp> class. You can use it for anything you would use |
|
215
|
|
|
|
|
|
|
C<$self> inside a route. |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
route '/die' => sub { |
|
218
|
|
|
|
|
|
|
app->res->code(500); |
|
219
|
|
|
|
|
|
|
}; |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head2 attr |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
Assigns lazy or active attributes (using L<Kelp::Base>) to C<app>. Use it to |
|
224
|
|
|
|
|
|
|
initialize your application. |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
attr mongo => MongoDB::MongoClient->new( ... ); |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=head2 route |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
Adds a route to C<app>. It is an alias to C<$self-E<gt>routes-E<gt>add>, and requires |
|
231
|
|
|
|
|
|
|
the exact same parameters. See L<Kelp::Routes> for reference. |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
route '/get-it' => sub { "got it" }; |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=head2 get, post, put, del |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
These are shortcuts to C<route> restricted to the corresponding HTTP method. |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
get '/data' => sub { "Only works with GET" }; |
|
240
|
|
|
|
|
|
|
post '/data' => sub { "Only works with POST" }; |
|
241
|
|
|
|
|
|
|
put '/data' => sub { "Only works with PUT" }; |
|
242
|
|
|
|
|
|
|
del '/data' => sub { "Only works with DELETE" }; |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=head2 param |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
An alias for C<$self-E<gt>param> that gets the GET or POST parameters. |
|
247
|
|
|
|
|
|
|
When used with no arguments, it will return an array with the names of all http |
|
248
|
|
|
|
|
|
|
parameters. Otherwise, it will return the value of the requested http parameter. |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
get '/names' => sub { |
|
251
|
|
|
|
|
|
|
my @names = param; |
|
252
|
|
|
|
|
|
|
# Now @names contains the names of the params |
|
253
|
|
|
|
|
|
|
}; |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
get '/value' => sub { |
|
256
|
|
|
|
|
|
|
my $id = param 'id'; |
|
257
|
|
|
|
|
|
|
# Now $is contains the value of 'id' |
|
258
|
|
|
|
|
|
|
}; |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=head2 stash |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
An alias for C<$self-E<gt>stash>. The stash is a concept originally conceived by the |
|
263
|
|
|
|
|
|
|
developers of L<Catalyst>. It's a hash that you can use to pass data from one |
|
264
|
|
|
|
|
|
|
route to another. |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# Create a bridge route that checks if the user is authenticated, and saves |
|
267
|
|
|
|
|
|
|
# the username in the stash. |
|
268
|
|
|
|
|
|
|
get '/user' => { bridge => 1, to => sub { |
|
269
|
|
|
|
|
|
|
return stash->{username} = app->authenticate(); |
|
270
|
|
|
|
|
|
|
}}; |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# This route is run after the above bridge, so we know that we have an |
|
273
|
|
|
|
|
|
|
# authenticated user and their username in the stash. |
|
274
|
|
|
|
|
|
|
get '/user/welcome' => sub { |
|
275
|
|
|
|
|
|
|
return "Hello " . stash 'username'; |
|
276
|
|
|
|
|
|
|
}; |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
With no arguments C<stash> returns the entire stash hash. A single argument is |
|
279
|
|
|
|
|
|
|
interpreted as the key to the stash hash and its value is returned accordingly. |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=head2 named |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
An alias for C<$self-E<gt>named>. The C<named> hash contains the names and values of |
|
284
|
|
|
|
|
|
|
the named placeholders from the current route's path. Much like the C<stash>, |
|
285
|
|
|
|
|
|
|
with no arguments it returns the entire C<named> hash, and with a single |
|
286
|
|
|
|
|
|
|
argument it returns the value for the corresponding key in the hash. |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
get '/:name/:id' => sub { |
|
289
|
|
|
|
|
|
|
my $name = named 'name'; |
|
290
|
|
|
|
|
|
|
my $id = name 'id'; |
|
291
|
|
|
|
|
|
|
}; |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
In the above example a GET request to C</james/1000> will initialize C<$name> |
|
294
|
|
|
|
|
|
|
with C<"james"> and C<$id> with C<1000>. |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=head2 req |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
An alias for C<$self-E<gt>req>, this provides quick access to the |
|
299
|
|
|
|
|
|
|
L<Kelp::Request> object for the current route. |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# Inside a route |
|
302
|
|
|
|
|
|
|
if ( req->is_ajax ) { |
|
303
|
|
|
|
|
|
|
... |
|
304
|
|
|
|
|
|
|
} |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=head2 res |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
An alias for C<$self-E<gt>res>, this is a shortcut for the L<Kelp::Response> |
|
309
|
|
|
|
|
|
|
object for the current route. |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# Inside a route |
|
312
|
|
|
|
|
|
|
res->code(403); |
|
313
|
|
|
|
|
|
|
res->json->render({ message => "Forbidden" }); |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=head2 template |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
A shortcut to C<$self-E<gt>res-E<gt>template>. Renders a template using the |
|
318
|
|
|
|
|
|
|
currently loaded template module. Note that a Kelp::Less application does not |
|
319
|
|
|
|
|
|
|
by default load a template module, so you will have to load it yourself. |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
use Kelp::Less; |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
module 'Template', path => 'views'; |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
get '/hello/:name' => sub { |
|
326
|
|
|
|
|
|
|
template 'hello.tt', { name => named 'name' }; |
|
327
|
|
|
|
|
|
|
}; |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=head2 view |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
A shortcut for L</template>. |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
get '/hello/:name' => sub { |
|
334
|
|
|
|
|
|
|
view 'hello.tt', { name => named 'name' }; |
|
335
|
|
|
|
|
|
|
}; |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
=head2 run |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
Creates and returns a PSGI ready subroutine, and makes the app ready for C<Plack>. |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=head2 module |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
Loads a Kelp module. The module options may be specified after the module name. |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
module 'JSON::XS', pretty => 1; |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=head2 config |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
Provides procedural interface to the configuration. |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
get '/hello' => sub { |
|
352
|
|
|
|
|
|
|
my $baz = config('bar.foo.baz'); |
|
353
|
|
|
|
|
|
|
}; |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=head1 TESTING |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
When writing a C<Kelp::Less> app, we don't have a separate class to initialize and |
|
358
|
|
|
|
|
|
|
feed into a L<Kelp::Test> object, because all of our code is contained in the |
|
359
|
|
|
|
|
|
|
C<app.psgi> file. In this case, the C<Kelp::Test> object can be initialized |
|
360
|
|
|
|
|
|
|
with the name of the C<PSGI> file in the C<psgi> argument. |
|
361
|
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
# t/main.t |
|
363
|
|
|
|
|
|
|
use Kelp::Test; |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
my $t = Kelp::Test->new( psgi => 'app.psgi' ); |
|
366
|
|
|
|
|
|
|
# Do some tests ... |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
Since you don't have control over the creation of the C<Kelp> object, if you |
|
369
|
|
|
|
|
|
|
need to specify a different mode for testing, you can use the C<PLACK_ENV> |
|
370
|
|
|
|
|
|
|
environmental variable: |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
> PLACK_ENV=test prove -l |
|
373
|
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
This will enable the C<conf/test.pl> configuration, which you should |
|
375
|
|
|
|
|
|
|
tailor to your testing needs. |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
This module's interface was inspired by L<Dancer>, which in its turn was |
|
380
|
|
|
|
|
|
|
inspired by Sinatra, so Viva La Open Source! |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=cut |