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   8679260 use strict;
  14         21  
  14         362  
4 14     14   48 use warnings;
  14         17  
  14         282  
5              
6 14     14   45 use Carp;
  14         18  
  14         790  
7 14     14   484 use Dancer2::Core::Types qw/Str CodeRef/;
  14         158854  
  14         95  
8 14     14   17034 use Dancer2::Plugin;
  14         166091  
  14         88  
9              
10             our $VERSION = '0.02';
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 1015 my $plugin = shift;
73 13         19 my $flash_sub;
74             my $dequeue_sub;
75              
76 13         29 $plugin->_is_valid_config();
77              
78 13 100       65 if ( $plugin->queue eq 'single' ) {
    100          
    100          
    50          
79             $flash_sub = sub {
80 20     20   31 my $plugin = shift();
81 20   50     132 my $value = $plugin->_get_parameters(@_) || '';
82 20         349 my $session = $plugin->app->session;
83 20         30890 $session->write( $plugin->session_hash_key, $value );
84 20         885 return $value;
85 8         28 };
86             } elsif ( $plugin->queue eq 'multiple' ) {
87             $flash_sub = sub {
88 8     8   9 my $plugin = shift();
89 8   50     20 my $value = $plugin->_get_parameters(@_) || '';
90 8         119 my $session = $plugin->app->session;
91 8   100     3053 my $flash = $session->read( $plugin->session_hash_key ) || [];
92 8         160 push @$flash, $value;
93 8         28 $session->write( $plugin->session_hash_key, $flash );
94 8         316 return $value;
95 2         8 };
96             } elsif ( $plugin->queue eq 'key_single' ) {
97             $flash_sub = sub {
98 8     8   8 my $plugin = shift();
99 8         9 my $key = shift;
100 8   50     16 my $value = $plugin->_get_parameters(@_) || '';
101 8         120 my $session = $plugin->app->session;
102 8   100     2177 my $flash = $session->read( $plugin->session_hash_key ) || {};
103 8         163 $flash->{$key} = $value;
104 8         27 $session->write( $plugin->session_hash_key, $flash );
105 8         316 return $value;
106 2         8 };
107             } elsif ( $plugin->queue eq 'key_multiple' ) {
108             $flash_sub = sub {
109 6     6   8 my $plugin = shift();
110 6         7 my $key = shift;
111 6   50     10 my $value = $plugin->_get_parameters(@_) || '';
112 6         85 my $session = $plugin->app->session;
113 6   100     1539 my $flash = $session->read( $plugin->session_hash_key ) || {};
114 6         108 push @{ $flash->{$key} }, $value;
  6         15  
115 6         18 $session->write( $plugin->session_hash_key, $flash );
116 6         223 return $value;
117 1         3 };
118             } else {
119 0         0 croak "invalid queueing style '${\$plugin->queue}'";
  0         0  
120             }
121              
122 13 100       93 if ( $plugin->dequeue eq 'never' ) {
    100          
    100          
    50          
123             $dequeue_sub = sub {
124 9     9   68558 my $tokens = shift();
125 9         137 my $session = $plugin->app->session;
126 9         5808 my $token_name = $plugin->token_name();
127 9         58 $tokens->{$token_name} =
128             $session->read( $plugin->session_hash_key );
129 9         163 return;
130 1         3 };
131             } elsif ( $plugin->dequeue eq 'always' ) {
132             $dequeue_sub = sub {
133 5     5   40268 my $tokens = shift();
134 5         75 my $session = $plugin->app->session;
135 5         6083 my $token_name = $plugin->token_name();
136 5         20 $tokens->{$token_name} =
137             $session->read( $plugin->session_hash_key );
138 5         91 return;
139 1         2 };
140             } elsif ( $plugin->dequeue eq 'when_used' ) {
141              
142             $dequeue_sub = sub {
143 39     39   264472 my $tokens = shift();
144 39         588 my $session = $plugin->app->session;
145 39         35045 my $token_name = $plugin->token_name();
146              
147 39         155 my $cache;
148             $tokens->{$token_name} = sub {
149 58 100       396396 if ( !$cache ) {
150 45         227 $cache = $session->read( $plugin->session_hash_key );
151 45         947 $session->delete( $plugin->session_hash_key );
152             }
153 58         2095 return $cache;
154 39         238 };
155             }
156              
157 10         28 } elsif ( $plugin->dequeue eq 'by_key' ) {
158             $dequeue_sub = sub {
159 4     4   40668 my $tokens = shift();
160 4         65 my $session = $plugin->app->session;
161 4         5667 my $token_name = $plugin->token_name();
162 4   100     32 my $flash = $session->read( $plugin->session_hash_key ) || {};
163             $tokens->{$token_name} = {
164             map {
165 4         106 my $key = $_;
  3         4  
166 3         4 my $cache;
167             $key => sub {
168 3 100       2237 if ( !$cache ) {
169 2         4 $cache = delete $flash->{$key};
170             }
171 3         7 return $cache;
172 3         17 };
173             } keys %$flash,
174             };
175 1         3 };
176             } else {
177 0         0 croak "invalid dequeuing style '${\$plugin->dequeue}'";
  0         0  
178             }
179              
180 13         199 $plugin->_set_flash_sub($flash_sub);
181 13         322 $plugin->_set_dequeue_sub($dequeue_sub);
182              
183 13         386 $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       802568 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   52229 my $tokens = shift();
198 6         89 my $session = $plugin->app->session;
199 6         29 my $token_name = $plugin->token_name();
200 6         21 $tokens->{$token_name} =
201             $session->delete( $plugin->session_hash_key );
202 6         260 return;
203             },
204             )
205 1         29 );
206             }
207             }
208              
209             sub _is_valid_config
210             {
211              
212 13     13   15 my ($plugin) = @_;
213 13         163 my $conf = $plugin->config;
214              
215 13         73 my @keyss = keys %$conf;
216              
217             my %is_allowed_setting =
218 13         23 map { $_ => 1 } qw( token_name session_hash_key queue arguments dequeue );
  65         91  
219              
220 13         37 my @allowed = keys %is_allowed_setting;
221              
222 13 50       26 if ( my @extra = grep { !$is_allowed_setting{$_} } keys %$conf ) {
  24         76  
223 0         0 croak __PACKAGE__ . ": invalid configuration keys (@extra)";
224             }
225              
226             }
227              
228             sub flash
229             {
230 42     42 1 371376 my ($plugin) = @_;
231              
232 42         198 return $plugin->flash_sub()->(@_);
233              
234             }
235              
236             sub flash_flush
237             {
238 2     2 1 12567 my $plugin = shift();
239 2         46 my $session = $plugin->app->session;
240 2         1498 my $flash = $session->read( $plugin->session_hash_key );
241 2 50       59 return unless defined $flash;
242 2 50 33     10 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         11 $session->delete( $plugin->session_hash_key );
249 2         122 return $flash;
250             }
251 0         0 return;
252              
253             }
254              
255             sub _get_parameters
256             {
257 42     42   51 my $plugin = shift();
258 42 100       268 if ( $plugin->arguments eq 'single' ) { return shift }
  1 100       4  
    100          
259 3   100     28 elsif ( $plugin->arguments eq 'join' ) { return join $, || '', @_ }
260 3         12 elsif ( $plugin->arguments eq 'array' ) { return [@_] }
261 35 50       120 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