File: | lib/Railsish/Controller.pm |
Coverage: | 100.0% |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package 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 | |||||||
12 | my ($request, $response, $controller, $action, $format); | ||||||
13 | |||||||
14 | sub request() { $request } | ||||||
15 | sub response() { $response } | ||||||
16 | sub controller() { $controller } | ||||||
17 | sub action() { $action } | ||||||
18 | sub format() { $format } | ||||||
19 | |||||||
20 | sub 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 | |||||||
40 | sub 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 | |||||||
74 | sub 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 | |||||||
86 | sub 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; | ||||
130 | sub 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' | ||||||
143 | sub index { | ||||||
144 | render; | ||||||
145 | } | ||||||
146 | |||||||
147 | |||||||
148 | 1; |