File Coverage

File:lib/Railsish/Controller.pm
Coverage:100.0%

linestmtbrancondsubpodtimecode
1package Railsish::Controller;
2# ABSTRACT: base class for webapp controllers.
3
1
1
1
7
4
7
use strict;
4
1
1
1
9
3
7
use warnings;
5
6
1
1
1
75
5
16
use Railsish::CoreHelpers;
7
1
1
1
89
5
4
use Railsish::ViewHelpers ();
8
1
1
1
10
3
4
use Railsish::ControllerHelpers ();
9
1
1
1
79
5
13
use Encode;
10
1
1
1
78
4
15
use YAML qw(Dump);
11
12my ($request, $response, $controller, $action, $format);
13
14sub request() { $request }
15sub response() { $response }
16sub controller() { $controller }
17sub action() { $action }
18sub format() { $format }
19
20sub import {
21    my $class = shift;
22    my $caller = caller;
23
1
1
1
12
3
7
    no strict;
24
25    push @{"$caller\::ISA"}, $class;
26
27    *{"$caller\::request"} = \&request;
28    *{"$caller\::response"} = \&response;
29    *{"$caller\::controller"} = \&controller;
30    *{"$caller\::action"} = \&action;
31    *{"$caller\::format"} = \&format;
32    *{"$caller\::render"} = \&render;
33    *{"$caller\::render_json"} = \&render_json;
34
35    for (@Railsish::ControllerHelpers::EXPORT) {
36        *{"$caller\::$_"} = *{"Railsish::ControllerHelpers::$_"};
37    }
38}
39
40sub dispatch {
41    (my $self, $request, $response) = @_;
42
43    my $path = $request->path;
44
45    if ($path =~ s/\.(....?)$//) {
46        $format = $1
47    } else {
48        $format = "html";
49    }
50
51    my @args = split "/", $path; shift @args; # discard the first undef
52    $controller = shift @args || 'welcome';
53    $action = shift @args || 'index';
54
55    logger->debug(Dump({
56        request => $path,
57        controller => $controller,
58        action => $action,
59        params => $request->parameters
60    }));
61
62    if ($self->can($action)) {
63        $self->$action(@args);
64    }
65
66    return $response;
67}
68
69
1
1
1
82
6
22
use Template;
70
1
1
1
11
4
14
use File::Spec::Functions;
71
1
1
1
79
60
18
use Binding 0.04;
72
1
1
1
81
4
17
use Perl6::Junction qw(any);
73
74sub build_stash {
75    my $caller_vars = Binding->of_caller(2)->our_vars;
76    my $stash = {};
77    for my $varname (keys %$caller_vars) {
78        my $val = $caller_vars->{$varname};
79        $varname =~ s/^[\$%@]//;
80        $val = $$val if ref($val) eq any('SCALAR', 'REF');
81        $stash->{$varname} = $val;
82    }
83    return $stash;
84}
85
86sub render {
87    my (%variables) = @_;
88    my $stash = build_stash;
89
90    for (keys %$stash) {
91        $variables{$_} = $stash->{$_};
92    }
93
94    if (defined($format)) {
95        my $renderer = __PACKAGE__->can("render_${format}");
96        if ($renderer) {
97            $renderer->(%variables);
98            return;
99        }
100        $response->status(500);
101        $response->body("Unknown format: $format");
102    }
103
104    $variables{controller} = \&controller;
105    $variables{action} = \&action;
106
107    for (@Railsish::ViewHelpers::EXPORT) {
108        $variables{$_} = \&{"Railsish::ViewHelpers::$_"};
109    }
110
111    $variables{title} ||= ucfirst($controller) . " :: " .ucfirst($action);
112    $variables{layout} ||= "layouts/application.html.tt2";
113    $variables{template} ||= "${controller}/${action}.html.tt2";
114
115    my $tt = Template->new({
116        INCLUDE_PATH => [ catdir(app_root, "app", "views") ],
117        PROCESS => $variables{layout},
118        ENCODING => 'utf8'
119    });
120
121    my $output = "";
122    $tt->process($variables{template}, \%variables, \$output)
123        || die $tt->error();
124
125    $response->body(Encode::encode_utf8($output));
126}
127
128
129
1
1
1
78
4
14
use JSON -convert_blessed_universally;
130sub render_json {
131    my %variables = @_;
132
133    my $json = JSON->new;
134    $json->allow_blessed(1);
135
136    my $out = $json->encode(\%variables);
137
138    $response->headers->header('Content-Type' => 'text/x-json');
139    $response->body( Encode::encode_utf8($out) );
140}
141
142# Provide a default 'index'
143sub index {
144    render;
145}
146
147
1481;