File Coverage

blib/lib/Minima/Controller.pm
Criterion Covered Total %
statement 35 35 100.0
branch n/a
condition n/a
subroutine 12 12 100.0
pod n/a
total 47 47 100.0


line stmt bran cond sub pod time code
1 4     4   1325 use v5.40;
  4         45  
2 4     4   25 use experimental 'class';
  4         7  
  4         52  
3              
4             class Minima::Controller;
5              
6 4     4   932 use Carp;
  4         7  
  4         258  
7 4     4   1984 use Data::Dumper;
  4         26060  
  4         369  
8 4     4   674 use Encode qw(decode);
  4         21189  
  4         402  
9 4     4   1778 use Hash::MultiValue;
  4         18364  
  4         166  
10 4     4   2358 use JSON;
  4         36556  
  4         26  
11 4     4   3018 use Minima::View::PlainText;
  4         17  
  4         171  
12 4     4   2187 use Plack::Request;
  4         201412  
  4         210  
13 4     4   32 use Plack::Response;
  4         8  
  4         101  
14 4     4   18 use Scalar::Util qw(reftype);
  4         8  
  4         229  
15              
16 4     4   19 use constant k_FLASH => 'minima.flash';
  4         8  
  4         9789  
17              
18             field $env :reader;
19             field $app :param :reader;
20             field $route :param :reader = {};
21              
22             field $request :reader;
23             field $response :reader;
24             field $params :reader;
25              
26             field $req_encoding;
27              
28             ADJUST {
29             $env = $app->env // {};
30              
31             $request = Plack::Request->new($env);
32             $response = Plack::Response->new(200);
33              
34             $params = $self->_get_request_parameters;
35             }
36              
37             method before_action ($m) { }
38             method after_action ($r) { }
39              
40             method trimmed_params ($options = {})
41             {
42             my $exclude = $options->{exclude} // [];
43             my @f_params = $params->flatten;
44             my @params;
45              
46             for my ($k, $v) (@f_params) {
47             if (defined $v) {
48             my $skip = 0;
49             for my $pat (@$exclude) {
50             if (ref $pat && reftype $pat eq 'REGEXP') {
51             if ($k =~ $pat) { $skip = 1; last }
52             } else {
53             if ($k eq $pat) { $skip = 1; last }
54             }
55             }
56             if (!$skip) {
57             if (!ref $v) {
58             $v = trim $v;
59             } elsif (ref $v eq ref []) {
60             $v = [ map { defined $_ ? trim($_) : $_ } @$v ];
61             }
62             }
63             }
64             push @params, $k, $v;
65             }
66             return Hash::MultiValue->new(@params);
67             }
68              
69             method json_body
70             {
71             my $c_type = $request->content_type // '';
72             return undef unless $c_type =~ m|\Aapplication/json\b|i;
73              
74             my $body = $request->content;
75             return undef unless length $body;
76              
77             my $data;
78              
79             try {
80             $data = decode_json($body);
81             } catch ($e) {
82             return undef;
83             }
84              
85             return $data;
86             }
87              
88             method flash ($type = undef, $message = undef)
89             {
90             my $session = $request->session;
91             my $options = $request->session_options;
92              
93             croak <<~M unless $session;
94             flash requires session middleware.
95             Please enable Plack::Middleware::Session.
96             M
97              
98             # pop
99             unless (defined $type) {
100             return undef unless exists $session->{+k_FLASH};
101             delete $options->{no_store} if $options;
102             return delete $session->{+k_FLASH};
103             }
104              
105             # push
106             delete $options->{no_store} if $options;
107             push $session->{+k_FLASH}->{$type}->@*, $message;
108             }
109              
110             method hello
111             {
112             $self->render(Minima::View::PlainText->new, "hello, world\n");
113             }
114              
115             method not_found
116             {
117             $response->code(404);
118             $self->render(Minima::View::PlainText->new, "not found\n");
119             }
120              
121             method redirect ($url, $code = 302)
122             {
123             $response->redirect($url, $code);
124             $response->finalize;
125             }
126              
127             method render ($view, $data = {})
128             {
129             $response->body($view->render($data));
130             $view->prepare_response($response);
131              
132             $response->finalize;
133             }
134              
135             method print_env
136             {
137             return $self->redirect('/') unless $app->development;
138              
139             my $max = 0;
140             for (map { length } keys %$env) {
141             $max = $_ if $_ > $max;
142             }
143              
144             $self->render(
145             Minima::View::PlainText->new,
146             join '', map {
147             sprintf "%*s => %s\n", -$max, $_, $env->{$_}
148             } sort keys %$env
149             );
150             }
151              
152             method dd ($ref)
153             {
154             my $dumper = Data::Dumper->new([ $ref ]);
155             $dumper->Terse(1);
156              
157             $self->render(
158             Minima::View::PlainText->new,
159             $dumper->Dump,
160             );
161             }
162              
163             method _get_request_parameters
164             {
165             $req_encoding = $app->config->{request_encoding} // 'UTF-8';
166              
167             my @parameters = map {
168             $self->_decode($_)
169             } $request->parameters->flatten;
170              
171             $params = Hash::MultiValue->new(@parameters);
172             }
173              
174             method _decode ($data)
175             {
176             if (ref $data eq ref {}) {
177             my %encoded;
178             for my ($k, $v) (%$data) {
179             $encoded{ $self->_decode($k) } = $self->_decode($v);
180             }
181             return \%encoded;
182             }
183              
184             if (ref $data eq ref []) {
185             my @encoded;
186             for my $v (@$data) {
187             push @encoded, $self->_decode($v);
188             }
189             return \@encoded;
190             }
191              
192             if (defined $data) {
193             return decode($req_encoding, $data);
194             }
195              
196             undef;
197             }
198              
199             __END__