File: Lite.pm

package info (click to toggle)
libmojolicious-perl 0.999926-1%2Bsqueeze2
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 1,672 kB
  • ctags: 949
  • sloc: perl: 17,391; makefile: 4
file content (705 lines) | stat: -rw-r--r-- 17,771 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
# Copyright (C) 2008-2010, Sebastian Riedel.

package Mojolicious::Lite;

use strict;
use warnings;

use base 'Mojolicious';

use File::Spec;
use FindBin;

# Make reloading work
BEGIN { $INC{$0} = $0 }

# It's the future, my parents, my co-workers, my girlfriend,
# I'll never see any of them ever again... YAHOOO!
sub import {
    my $class = shift;

    # Lite apps are strict!
    strict->import;
    warnings->import;

    # Home
    $ENV{MOJO_HOME} ||= File::Spec->catdir(split '/', $FindBin::Bin);

    # Initialize app
    my $app = $class->new;

    # Initialize routes
    my $routes = $app->routes;

    # Route generator
    my $route = sub {
        my ($methods, @args) = @_;

        my ($cb, $constraints, $defaults, $name, $pattern);
        my $conditions = [];

        # Route information
        my $condition;
        while (my $arg = shift @args) {

            # Condition can be everything
            if ($condition) {
                push @$conditions, $condition => $arg;
                $condition = undef;
            }

            # First scalar is the pattern
            elsif (!ref $arg && !$pattern) { $pattern = $arg }

            # Scalar
            elsif (!ref $arg && @args) { $condition = $arg }

            # Last scalar is the route name
            elsif (!ref $arg) { $name = $arg }

            # Callback
            elsif (ref $arg eq 'CODE') { $cb = $arg }

            # Constraints
            elsif (ref $arg eq 'ARRAY') { $constraints = $arg }

            # Defaults
            elsif (ref $arg eq 'HASH') { $defaults = $arg }
        }

        # Defaults
        $constraints ||= [];

        # Defaults
        $defaults ||= {};
        $defaults = {%$defaults, cb => $cb} if $cb;

        # Name
        $name ||= '';

        # Create bridge
        return $routes =
          $app->routes->bridge($pattern, {@$constraints})->over($conditions)
          ->to($defaults)->name($name)
          if !ref $methods && $methods eq 'under';

        # WebSocket
        my $websocket = 1 if !ref $methods && $methods eq 'websocket';
        $methods = [] if $websocket;

        # Create route
        my $route =
          $routes->route($pattern, {@$constraints})->over($conditions)
          ->via($methods)->to($defaults)->name($name);

        # WebSocket
        $route->websocket if $websocket;

        return $route;
    };

    # Prepare exports
    my $caller = caller;
    no strict 'refs';
    no warnings 'redefine';

    # Default template class
    $app->renderer->default_template_class($caller);

    # Export
    *{"${caller}::new"} = *{"${caller}::app"} = sub {$app};
    *{"${caller}::any"} = sub { $route->(ref $_[0] ? shift : [], @_) };
    *{"${caller}::get"} = sub { $route->('get', @_) };
    *{"${caller}::under"} = *{"${caller}::ladder"} =
      sub { $route->('under', @_) };
    *{"${caller}::plugin"}    = sub { $app->plugin(@_) };
    *{"${caller}::post"}      = sub { $route->('post', @_) };
    *{"${caller}::websocket"} = sub { $route->('websocket', @_) };

    # We are most likely the app in a lite environment
    $ENV{MOJO_APP} = $app;

    # Shagadelic!
    *{"${caller}::shagadelic"} = sub { Mojolicious::Lite->start(@_) };
}

1;
__END__

=head1 NAME

Mojolicious::Lite - Micro Web Framework

=head1 SYNOPSIS

    # Using Mojolicious::Lite will enable "strict" and "warnings"
    use Mojolicious::Lite;

    # Route with placeholder
    get '/:foo' => sub {
        my $self = shift;
        my $foo  = $self->param('foo');
        $self->render(text => "Hello from $foo!");
    };

    # Start the Mojolicious command system
    app->start;

=head1 DESCRIPTION

L<Mojolicous::Lite> is a micro web framework built around L<Mojolicious>.

A minimal Hello World application looks like this, L<strict> and L<warnings>
are automatically enabled and a few functions imported when you use
L<Mojolicious::Lite>, turning your script into a full featured web
application.

    #!/usr/bin/env perl

    use Mojolicious::Lite;

    get '/' => sub { shift->render(text => 'Hello World!') };

    app->start;

There is also a helper command to generate a small example application.

    % mojolicious generate lite_app

All the normal L<Mojolicious> command options are available from the command
line.
Note that CGI, FastCGI and PSGI environments can usually be auto detected and
will just work without commands.

    % ./myapp.pl daemon
    Server available at http://127.0.0.1:3000.

    % ./myapp.pl daemon --listen http://*:8080
    Server available at http://127.0.0.1:8080.

    % ./myapp.pl daemon_prefork
    Server available at http://127.0.0.1:3000.

    % ./myapp.pl cgi
    ...CGI output...

    % ./myapp.pl fastcgi
    ...Blocking FastCGI main loop...

    % ./myapp.pl
    ...List of available commands (or automatically detected environment)...

The app->start call that starts the L<Mojolicious> command system can be
customized to override normal C<@ARGV> use.

    app->start('cgi');

Your application will automatically reload itself if you set the C<--reload>
option, so you don't have to restart the server after every change.

    % ./myapp.pl daemon --reload
    Server available at http://127.0.0.1:3000.

Routes are basically just fancy paths that can contain different kinds of
placeholders.

    # /foo
    get '/foo' => sub {
        my $self = shift;
        $self->render(text => 'Hello World!');
    };

All routes can have a name associated with them, this allows automatic
template detection and back referencing with C<url_for>, C<link_to> and
C<form_for>.
Names are always the last argument.

    # /
    get '/' => 'index';

    # /foo
    get '/foo' => 'foo';

    # /bar
    get '/bar' => sub {
        my $self = shift;
        $self->render(text => 'Hi!')
    } => 'bar';

    __DATA__

    @@ index.html.ep
    <%= link_to foo => {%>Foo<%}%>.
    <%= link_to bar => {%>Bar<%}%>.

    @@ foo.html.ep
    <a href="<%= url_for 'index' %>">Home</a>.

Templates can have layouts.

    # GET /with_layout
    get '/with_layout' => sub {
        my $self = shift;
        $self->render('with_layout', layout => 'green');
    };

    __DATA__

    @@ with_layout.html.ep
    We've got content!

    @@ layouts/green.html.ep
    <!doctype html><html>
        <head><title>Green!</title></head>
        <body><%= content %></body>
    </html>

Template blocks can be reused like functions in Perl scripts.

    # GET /with_block
    get '/with_block' => 'block';

    __DATA__

    @@ block.html.ep
    <% my $link = {%>
        <% my ($url, $name) = @_; %>
        Try <%= link_to $url => {%><%= $name %><%}%>!
    <%}%>
    <!doctype html><html>
        <head><title>Sebastians Frameworks!</title></head>
        <body>
            <%= $link->('http://mojolicious.org', 'Mojolicious') %>
            <%= $link->('http://catalystframework.org', 'Catalyst') %>
        </body>
    </html>

Templates can also pass around blocks of captured content and extend each
other.

    # GET /
    get '/' => 'first';

    # GET /second
    get '/second' => 'second';

    __DATA__

    @@ first.html.ep
    <!doctype html><html>
        <head><%= content header => {%><title>Hi!</title><%}%></head>
        <body><%= content body => {%>First page!<%}%></body>
    </html>

    @@ second.html.ep
    % extends 'first';
    <% content header => {%>
        <title>Howdy!</title>
    <%}%>
    <% content body => {%>
        Second page!
    <%}%>

Route placeholders allow capturing parts of a request path until a C</> or
C<.> separator occurs, results will be stored by name in the C<stash> and
C<param>.

    # /foo/* (everything except "/" and ".")
    # /foo/test
    # /foo/test123
    get '/foo/:bar' => sub {
        my $self = shift;
        my $bar  = $self->stash('bar');
        $self->render(text => "Our :bar placeholder matched $bar");
    };

    # /*something/foo (everything except "/" and ".")
    # /test/foo
    # /test123/foo
    get '/(:bar)something/foo' => sub {
        my $self = shift;
        my $bar  = $self->param('bar');
        $self->render(text => "Our :bar placeholder matched $bar");
    };

Relaxed placeholders allow matching of everything until a C</> occurs.

    # /*/hello (everything except "/")
    # /test/hello
    # /test123/hello
    # /test.123/hello
    get '/(.you)/hello' => sub {
        shift->render('groovy');
    };

    __DATA__

    @@ groovy.html.ep
    Your name is <%= $you %>.

Wildcard placeholders allow matching absolutely everything, including
C</> and C<.>.

    # /hello/* (everything)
    # /hello/test
    # /hello/test123
    # /hello/test.123/test/123
    get '/hello/(*you)' => sub {
        shift->render('groovy');
    };

    __DATA__

    @@ groovy.html.ep
    Your name is <%= $you %>.

Routes can be restricted to specific request methods.

    # GET /bye
    get '/bye' => sub { shift->render(text => 'Bye!') };

    # POST /bye
    post '/bye' => sub { shift->render(text => 'Bye!') };

    # GET|POST|DELETE /bye
    any [qw/get post delete/] => '/bye' => sub {
        shift->render(text => 'Bye!');
    };

    # /baz
    any '/baz' => sub {
        my $self   = shift;
        my $method = $self->req->method;
        $self->render(text => "You called /baz with $method");
    };

All placeholders get compiled to a regex internally, with regex constraints
this process can be easily customized.

    # /*
    any '/:bar' => [bar => qr/\d+/] => sub {
        my $self = shift;
        my $bar  = $self->param('bar');
        $self->render(text => "Our :bar placeholder matched $bar");
    };

Routes allow default values to make placeholders optional.

    # /hello/*
    get '/hello/:name' => {name => 'Sebastian'} => sub {
        my $self = shift;
        $self->render('groovy', format => 'txt');
    };

    __DATA__

    @@ groovy.txt.ep
    My name is <%= $name %>.

All those features can be easily used together.

    # /everything/*?name=*
    get '/everything/:stuff' => [stuff => qr/\d+/] => {stuff => 23} => sub {
        shift->render('welcome');
    };

    __DATA__

    @@ welcome.html.ep
    Stuff is <%= $stuff %>.
    Query param name is <%= param 'name' %>.

Here's a fully functional example for a html form handling application using
multiple features at once.

    #!/usr/bin/env perl

    use Mojolicious::Lite;

    get '/' => 'index';

    post '/test' => sub {
        my $self = shift;

        my $groovy = $self->param('groovy') || 'Austin Powers';
        $groovy =~ s/[^\w\s]+//g;

        $self->render(
            template => 'welcome',
            layout   => 'funky',
            groovy   => $groovy
        );
    } => 'test';

    app->start;
    __DATA__

    @@ index.html.ep
    % layout 'funky';
    Who is groovy?
    <%= form_for test => (method => 'post') => {%>
        <%= input 'groovy', type => 'text' %>
        <input type="submit" value="Woosh!" />
    <%}%>

    @@ welcome.html.ep
    <%= $groovy %> is groovy!
    <%= include 'menu' %>

    @@ menu.html.ep
    <%= link_to index => {%>Try again<%}%>

    @@ layouts/funky.html.ep
    <!doctype html><html>
        <head><title>Funky!</title></head>
        <body><%= content %>
        </body>
    </html>

Authentication and code shared between multiple routes can be realized easily
with the C<under> statement.
All following routes are only evaluated if the C<under> callback returned a
true value.

    use Mojolicious::Lite;

    # Authenticate based on name parameter
    under sub {
        my $self = shift;

        # Authenticated
        my $name = $self->param('name') || '';
        return 1 if $name eq 'Bender';

        # Not authenticated
        $self->render('denied');
        return;
    };

    # GET / (with authentication)
    get '/' => 'index';

    app->start;
    __DATA__;

    @@ denied.html.ep
    You are not Bender, permission denied!

    @@ index.html.ep
    Hi Bender!

Conditions such as C<agent> allow even more powerful route constructs.

    # /foo
    get '/foo' => (agent => qr/Firefox/) => sub {
        shift->render(
            text => 'Congratulations, you are using a cool browser!');
    }

    # /foo
    get '/foo' => (agent => qr/Internet Explorer/) => sub {
        shift->render(
            text => 'Dude, you really need to upgrade to Firefox!');
    }

Formats can be automatically detected by looking at file extensions.

    # /detection.html
    # /detection.txt
    get '/detection' => sub {
        my $self = shift;
        $self->render('detected');
    };

    __DATA__

    @@ detected.html.ep
    <!doctype html><html>
        <head><title>Detected!</title></head>
        <body>HTML was detected.</body>
    </html>

    @@ detected.txt.ep
    TXT was detected.

Signed cookie based sessions just work out of the box as soon as you start
using them.
The C<flash> can be used to store values that will only be available for one
request, this is very useful in combination with C<redirect_to>.

    use Mojolicious::Lite;

    get '/login' => sub {
        my $self = shift;
        my $name = $self->param('name') || '';
        my $pass = $self->param('pass') || '';
        return $self->render unless $name eq 'sebastian' && $pass eq '1234';
        $self->session(name => $name);
        $self->flash(message => 'Thanks for logging in!');
        $self->redirect_to('index');
    } => 'login';

    get '/' => sub {
        my $self = shift;
        return $self->redirect_to('login') unless $self->session('name');
        $self->render;
    } => 'index';

    get '/logout' => sub {
        my $self = shift;
        $self->session(expires => 1);
        $self->redirect_to('index');
    } => 'logout';

    app->start;
    __DATA__

    @@ layouts/default.html.ep
    <!doctype html><html>
        <head><title>Mojolicious rocks!</title></head>
        <body><%= content %></body>
    </html>

    @@ login.html.ep
    % layout 'default';
    <%= form_for login => {%>
        <% if (param 'name') { %>
            <b>Wrong name or password, please try again.</b><br />
        <% } %>
        Name:<br />
        <%= input name => (type => 'text') %><br />
        Password:<br />
        <%= input pass => (type => 'text') %><br />
        <input type="submit" value="Login" />
    <%}%>

    @@ index.html.ep
    % layout 'default';
    <% if (my $message = flash 'message' ) { %>
        <b><%= $message %></b><br />
    <% } %>
    Welcome <%= session 'name' %>!<br />
    <%= link_to logout => {%>Logout<%}%>

Note that you should use a custom C<secret> to make signed cookies really secure.

    app->secret('My secret passphrase here!');

A full featured HTTP 1.1 and WebSocket client is built right in.
Especially in combination with L<Mojo::JSON> this can be a very powerful
tool.

    get '/test' => sub {
        my $self = shift;
        $self->render(
            data => $self->client->get('http://mojolicious.org')->res->body);
    };

WebSocket applications have never been this easy before.

    websocket '/echo' => sub {
        my $self = shift;
        $self->receive_message(sub {
            my ($self, $message) = @_;
            $self->send_message("echo: $message");
        });
    };

External templates will be searched by the renderer in a C<templates>
directory.

    # /external
    any '/external' => sub {
        my $self = shift;

        # templates/foo/bar.html.ep
        $self->render('foo/bar');
    };

Static files will be automatically served from the C<public> directory if it
exists.

    % mkdir public
    % mv something.js public/something.js

Testing your application is as easy as creating a C<t> directory and filling
it with normal Perl unit tests like C<t/funky.t>.

    use Test::More tests => 3;
    use Test::Mojo;

    use FindBin;
    $ENV{MOJO_HOME} = "$FindBin::Bin/../";
    require "$ENV{MOJO_HOME}/myapp.pl";

    my $t = Test::Mojo->new;
    $t->get_ok('/')->status_is(200)->content_like(qr/Funky!/);

Run all unit tests with the C<test> command.

    % ./myapp.pl test

To make your tests less noisy you can also change the application log level
directly in your test files.

    app->log->level('error');

To disable debug messages later in a production setup you can change the
L<Mojolicious> mode, default will be C<development>.

    % MOJO_MODE=production ./myapp.pl

Log messages will be automatically written to a C<log/$mode.log> file if a
C<log> directory exists.

    % mkdir log

For more control the L<Mojolicious> instance can be accessed directly.

    app->log->level('error');
    app->routes->route('/foo/:bar')->via('get')->to(cb => sub {
        my $self = shift;
        $self->render(text => 'Hello Mojo!');
    });

In case a lite app needs to grow, lite and real L<Mojolicous> applications
can be easily mixed to make the transition process very smooth.

    package MyApp::Foo;
    use base 'Mojolicious::Controller';

    sub index { shift->render(text => 'It works!') }

    package main;
    use Mojolicious::Lite;

    get '/bar' => sub { shift->render(text => 'This too!') };

    app->routes->namespace('MyApp');
    app->routes->route('/foo/:action')->via('get')->to('foo#index');

    app->start;

There is also a helper command to generate a full L<Mojolicious> example that
will let you explore the astonishing similarities between
L<Mojolicious::Lite> and L<Mojolicious> applications.
Both share about 99% of the same code, so almost everything you learned in
this tutorial applies there too. :)

    % mojolicious generate app

Have fun!

=head1 ATTRIBUTES

L<Mojolicious::Lite> inherits all attributes from L<Mojolicious>.

=head1 METHODS

L<Mojolicious::Lite> inherits all methods from L<Mojolicious>.

=head1 SEE ALSO

L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicious.org>.

=cut