File Coverage

blib/lib/Dancer2/Plugin/FlashNote.pm
Criterion Covered Total %
statement 120 131 91.6
branch 30 40 75.0
condition 15 21 71.4
subroutine 19 19 100.0
pod 2 3 66.6
total 186 214 86.9


line stmt bran cond sub pod time code
1             package Dancer2::Plugin::FlashNote;
2              
3 14     14   8544202 use strict;
  14         19  
  14         356  
4 14     14   45 use warnings;
  14         18  
  14         297  
5              
6 14     14   44 use Carp;
  14         18  
  14         756  
7 14     14   494 use Dancer2::Core::Types qw/Str CodeRef/;
  14         164919  
  14         105  
8 14     14   17097 use Dancer2::Plugin;
  14         163811  
  14         91  
9              
10             our $VERSION = '0.01';
11             $VERSION = eval $VERSION;
12              
13             has token_name => (
14             is => 'ro',
15             isa => Str,
16             default => sub {
17             my ($self) = @_;
18             return $self->config->{token_name} || 'flash';
19             }
20             );
21              
22             has session_hash_key => (
23             is => 'ro',
24             isa => Str,
25             default => sub {
26             my ($self) = @_;
27             return $self->config->{session_hash_key} || '_flash';
28             }
29             );
30              
31             has queue => (
32             is => 'ro',
33             isa => Str,
34             default => sub {
35             my ($self) = @_;
36             return $self->config->{queue} || 'multiple';
37             }
38             );
39              
40             has arguments => (
41             is => 'ro',
42             isa => Str,
43             default => sub {
44             my ($self) = @_;
45             return $self->config->{arguments} || 'auto';
46             }
47             );
48              
49             has dequeue => (
50             is => 'ro',
51             isa => Str,
52             default => sub {
53             my ($self) = @_;
54             return $self->config->{dequeue} || 'when_used';
55             }
56             );
57              
58             has flash_sub => (
59             is => 'rwp',
60             isa => CodeRef,
61             );
62              
63             has dequeue_sub => (
64             is => 'rwp',
65             isa => CodeRef,
66             );
67              
68             plugin_keywords qw/flash flash_flush/;
69              
70             sub BUILD
71             {
72 13     13 0 1119 my $plugin = shift;
73 13         18 my $flash_sub;
74             my $dequeue_sub;
75              
76 13         33 $plugin->_is_valid_config();
77              
78 13 100       75 if ( $plugin->queue eq 'single' ) {
    100          
    100          
    50          
79             $flash_sub = sub {
80 20     20   33 my $plugin = shift();
81 20   50     146 my $value = $plugin->_get_parameters(@_) || '';
82 20         368 my $session = $plugin->app->session;
83 20         31578 $session->write( $plugin->session_hash_key, $value );
84 20         948 return $value;
85 8         32 };
86             } elsif ( $plugin->queue eq 'multiple' ) {
87             $flash_sub = sub {
88 8     8   11 my $plugin = shift();
89 8   50     19 my $value = $plugin->_get_parameters(@_) || '';
90 8         122 my $session = $plugin->app->session;
91 8   100     3036 my $flash = $session->read( $plugin->session_hash_key ) || [];
92 8         158 push @$flash, $value;
93 8         24 $session->write( $plugin->session_hash_key, $flash );
94 8         309 return $value;
95 2         9 };
96             } elsif ( $plugin->queue eq 'key_single' ) {
97             $flash_sub = sub {
98 8     8   10 my $plugin = shift();
99 8         11 my $key = shift;
100 8   50     23 my $value = $plugin->_get_parameters(@_) || '';
101 8         122 my $session = $plugin->app->session;
102 8   100     2394 my $flash = $session->read( $plugin->session_hash_key ) || {};
103 8         168 $flash->{$key} = $value;
104 8         36 $session->write( $plugin->session_hash_key, $flash );
105 8         369 return $value;
106 2         9 };
107             } elsif ( $plugin->queue eq 'key_multiple' ) {
108             $flash_sub = sub {
109 6     6   7 my $plugin = shift();
110 6         6 my $key = shift;
111 6   50     12 my $value = $plugin->_get_parameters(@_) || '';
112 6         84 my $session = $plugin->app->session;
113 6   100     1549 my $flash = $session->read( $plugin->session_hash_key ) || {};
114 6         104 push @{ $flash->{$key} }, $value;
  6         13  
115 6         20 $session->write( $plugin->session_hash_key, $flash );
116 6         288 return $value;
117 1         4 };
118             } else {
119 0         0 croak "invalid queueing style '${\$plugin->queue}'";
  0         0  
120             }
121              
122 13 100       111 if ( $plugin->dequeue eq 'never' ) {
    100          
    100          
    50          
123             $dequeue_sub = sub {
124 9     9   82704 my $tokens = shift();
125 9         193 my $session = $plugin->app->session;
126 9         6027 my $token_name = $plugin->token_name();
127 9         66 $tokens->{$token_name} =
128             $session->read( $plugin->session_hash_key );
129 9         220 return;
130 1         5 };
131             } elsif ( $plugin->dequeue eq 'always' ) {
132             $dequeue_sub = sub {
133 5     5   40338 my $tokens = shift();
134 5         83 my $session = $plugin->app->session;
135 5         5926 my $token_name = $plugin->token_name();
136 5         22 $tokens->{$token_name} =
137             $session->read( $plugin->session_hash_key );
138 5         101 return;
139 1         1 };
140             } elsif ( $plugin->dequeue eq 'when_used' ) {
141              
142             $dequeue_sub = sub {
143 39     39   275512 my $tokens = shift();
144 39         626 my $session = $plugin->app->session;
145 39         34513 my $token_name = $plugin->token_name();
146              
147 39         154 my $cache;
148             $tokens->{$token_name} = sub {
149 58 100       388478 if ( !$cache ) {
150 45         251 $cache = $session->read( $plugin->session_hash_key );
151 45         987 $session->delete( $plugin->session_hash_key );
152             }
153 58         2143 return $cache;
154 39         296 };
155             }
156              
157 10         32 } elsif ( $plugin->dequeue eq 'by_key' ) {
158             $dequeue_sub = sub {
159 4     4   40702 my $tokens = shift();
160 4         65 my $session = $plugin->app->session;
161 4         6067 my $token_name = $plugin->token_name();
162 4   100     36 my $flash = $session->read( $plugin->session_hash_key ) || {};
163             $tokens->{$token_name} = {
164             map {
165 4         87 my $key = $_;
  3         5  
166 3         1 my $cache;
167             $key => sub {
168 3 100       2272 if ( !$cache ) {
169 2         6 $cache = delete $flash->{$key};
170             }
171 3         7 return $cache;
172 3         19 };
173             } keys %$flash,
174             };
175 1         3 };
176             } else {
177 0         0 croak "invalid dequeuing style '${\$plugin->dequeue}'";
  0         0  
178             }
179              
180 13         215 $plugin->_set_flash_sub($flash_sub);
181 13         357 $plugin->_set_dequeue_sub($dequeue_sub);
182              
183 13         416 $plugin->app->add_hook(
184             Dancer2::Core::Hook->new(
185             name => 'before_template_render',
186             code => $plugin->dequeue_sub,
187              
188             )
189             );
190              
191 13 100       800130 if ( $plugin->dequeue() eq 'always' ) {
192              
193             $plugin->app->add_hook(
194             Dancer2::Core::Hook->new(
195             name => 'after',
196             code => sub {
197 6     6   51372 my $tokens = shift();
198 6         93 my $session = $plugin->app->session;
199 6         32 my $token_name = $plugin->token_name();
200 6         25 $tokens->{$token_name} =
201             $session->delete( $plugin->session_hash_key );
202 6         269 return;
203             },
204             )
205 1         29 );
206             }
207             }
208              
209             sub _is_valid_config
210             {
211              
212 13     13   18 my ($plugin) = @_;
213 13         173 my $conf = $plugin->config;
214              
215 13         78 my @keyss = keys %$conf;
216              
217             my %is_allowed_setting =
218 13         27 map { $_ => 1 } qw( token_name session_hash_key queue arguments dequeue );
  65         101  
219              
220 13         38 my @allowed = keys %is_allowed_setting;
221              
222 13 50       32 if ( my @extra = grep { !$is_allowed_setting{$_} } keys %$conf ) {
  24         79  
223 0         0 croak __PACKAGE__ . ": invalid configuration keys (@extra)";
224             }
225              
226             }
227              
228             sub flash
229             {
230 42     42 1 374450 my ($plugin) = @_;
231              
232 42         180 return $plugin->flash_sub()->(@_);
233              
234             }
235              
236             sub flash_flush
237             {
238 2     2 1 16484 my $plugin = shift();
239 2         59 my $session = $plugin->app->session;
240 2         1209 my $flash = $session->read( $plugin->session_hash_key );
241 2 50       50 return unless defined $flash;
242 2 50 33     8 if ( ( ref($flash) eq 'HASH' ) && @_ ) {
243 0         0 my @values = map { delete $flash->{$_} } @_;
  0         0  
244 0 0       0 return unless defined wantarray();
245 0 0       0 return $values[0] unless wantarray();
246 0         0 return @values;
247             } else {
248 2         12 $session->delete( $plugin->session_hash_key );
249 2         107 return $flash;
250             }
251 0         0 return;
252              
253             }
254              
255             sub _get_parameters
256             {
257 42     42   49 my $plugin = shift();
258 42 100       308 if ( $plugin->arguments eq 'single' ) { return shift }
  1 100       5  
    100          
259 3   100     24 elsif ( $plugin->arguments eq 'join' ) { return join $, || '', @_ }
260 3         13 elsif ( $plugin->arguments eq 'array' ) { return [@_] }
261 35 50       133 return @_ > 1 ? [@_] : shift;
262             }
263              
264             1;
265              
266             =pod
267              
268             =head1 NAME
269              
270             Dancer2::Plugin::FlashNote - support notifications in your Dancer2 web application
271              
272              
273             =head1 SYNOPSIS
274              
275             # In the configuration you choose a "flash style", e.g.
276             # notifications stored in an array and automatically
277             # removed from the session when used
278             plugins:
279             FlashNote:
280             queue: multiple
281             dequeue: when_used
282              
283              
284             # In the application you generate flash notifications
285             package MyWebService;
286              
287             use Dancer2;
288             use Dancer2::Plugin::FlashNote;
289              
290             get '/hello/:id/:who' => sub {
291             flash 'A first error message'
292             unless params->{id} =~ /\A\d+\z/mxs;
293             flash 'A second error message'
294             unless params->{who} =~ /\A(?: you | me )\z/mxs;
295             # ...
296             template 'index';
297             };
298              
299              
300             # Then, in the layout you consume them and they are flushed
301             <% IF flash %>
302            
303             <% FOR notice = flash %>
304            
  • <% notice | html %>
  • 305             <% END %>
    306            
    307             <% END %>
    308              
    309             =head1 DESCRIPTION
    310              
    311             This plugin helps you display temporary messages, so called "flash messages".
    312             It provides a C method to define the message. The plugin then takes
    313             care of attaching the content to the session, propagating it to the templating
    314             system, and then removing it from the session. On the other hand, you still
    315             have to take care to find a suitable place to put the messages. Code and docs
    316             based largely on work done by Flavio Poletti in L
    317              
    318             =head2 Styles
    319              
    320             Dancer2::Plugin::FlashNote lets you decide the I