| 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; | ||||||