File Coverage

blib/lib/Message/Stack.pm
Criterion Covered Total %
statement 2 4 50.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 4 6 66.6


line stmt bran cond sub pod time code
1             package Message::Stack;
2             BEGIN {
3 4     4   97787 $Message::Stack::VERSION = '0.22';
4             }
5 4     4   5622 use Moose;
  0            
  0            
6              
7             # ABSTRACT: Deal with a "stack" of messages
8              
9             use Carp qw(croak);
10             use MooseX::Storage;
11             use MooseX::Types::Moose qw(HashRef);
12             use Message::Stack::Message;
13             use Message::Stack::Types qw(MessageStackMessage);
14              
15             with 'MooseX::Storage::Deferred';
16              
17              
18             has messages => (
19             traits => [ 'Array' ],
20             is => 'rw',
21             isa => 'ArrayRef[Message::Stack::Message]',
22             default => sub { [] },
23             handles => {
24             reset => 'clear',
25             count => 'count',
26             has_messages => 'count',
27             first => [ get => 0 ],
28             first_message => [ get => 0 ],
29             _grep_messages => 'grep',
30             get_message => 'get',
31             last => [ get => -1 ],
32             last_message => [ get => -1 ],
33             }
34             );
35              
36              
37             sub add {
38             my ($self, $message) = @_;
39              
40             return unless defined($message);
41              
42             if(is_MessageStackMessage($message)) {
43             push(@{ $self->messages }, $message);
44             } elsif(is_HashRef($message)) {
45             my $mess = Message::Stack::Message->new($message);
46             push(@{ $self->messages }, $mess);
47             } else {
48             croak('Message must be either a Message::Stack::Message or hashref');
49             }
50             }
51              
52             sub for_id {
53             my $self = shift;
54             $self->for_msgid(@_);
55             }
56              
57              
58             sub for_msgid {
59             my ($self, $msgid) = @_;
60              
61             return $self->search(sub { $_->msgid eq $msgid if $_->has_msgid });
62             }
63              
64              
65             sub for_level {
66             my ($self, $level) = @_;
67              
68             return $self->search(sub { $_->level eq $level if $_->has_level });
69             }
70              
71              
72             sub for_scope {
73             my ($self, $scope) = @_;
74              
75             return $self->search(sub { $_->scope eq $scope if $_->has_scope });
76             }
77              
78              
79             sub for_subject {
80             my ($self, $subject) = @_;
81              
82             return $self->search(sub { $_->subject eq $subject if $_->has_subject });
83             }
84              
85             sub has_id {
86             my $self = shift;
87             $self->has_msgid(@_);
88             }
89              
90              
91             sub has_msgid {
92             my ($self, $msgid) = @_;
93              
94             return 0 unless $self->has_messages;
95              
96             return $self->for_msgid($msgid)->count ? 1 : 0;
97             }
98              
99              
100             sub has_level {
101             my ($self, $level) = @_;
102              
103             return 0 unless $self->has_messages;
104              
105             return $self->for_level($level)->count ? 1 : 0;
106             }
107              
108              
109             sub has_scope {
110             my ($self, $scope) = @_;
111              
112             return 0 unless $self->has_messages;
113              
114             return $self->for_scope($scope)->count ? 1 : 0;
115             }
116              
117              
118             sub has_subject {
119             my ($self, $subject) = @_;
120              
121             return 0 unless $self->has_messages;
122              
123             return $self->for_subject($subject)->count ? 1 : 0;
124             }
125              
126              
127             sub search {
128             my ($self, $coderef) = @_;
129              
130             my @messages = $self->_grep_messages($coderef);
131             return Message::Stack->new(messages => \@messages);
132             }
133              
134              
135             sub reset_scope {
136             my ($self, $scope) = @_;
137              
138             return 0 unless $self->has_messages;
139              
140             my $filtered = [];
141             foreach my $message (@{$self->messages}) {
142             next if($message->scope eq $scope);
143             push @{$filtered}, $message;
144             }
145              
146             $self->messages($filtered);
147             }
148              
149              
150             sub reset_level {
151             my ($self, $level) = @_;
152              
153             return 0 unless $self->has_messages;
154              
155             my $filtered = [];
156             foreach my $message (@{$self->messages}) {
157             next if($message->level eq $level);
158             push @{$filtered}, $message;
159             }
160              
161             $self->messages($filtered);
162             }
163              
164              
165             sub reset_msgid {
166             my ($self, $msgid) = @_;
167              
168             return 0 unless $self->has_messages;
169              
170             my $filtered = [];
171             foreach my $message (@{$self->messages}) {
172             next if($message->msgid eq $msgid);
173             push @{$filtered}, $message;
174             }
175              
176             $self->messages($filtered);
177             }
178              
179              
180             sub reset_subject {
181             my ($self, $subject) = @_;
182              
183             return 0 unless $self->has_messages;
184              
185             my $filtered = [];
186             foreach my $message (@{$self->messages}) {
187             next if($message->subject eq $subject);
188             push @{$filtered}, $message;
189             }
190              
191             $self->messages($filtered);
192             }
193              
194              
195             __PACKAGE__->meta->make_immutable;
196             no Moose;
197             1;
198              
199             __END__
200             =pod
201              
202             =head1 NAME
203              
204             Message::Stack - Deal with a "stack" of messages
205              
206             =head1 VERSION
207              
208             version 0.22
209              
210             =head1 SYNOPSIS
211              
212             my $stack = Message::Stack->new;
213              
214             $stack->add(Message::Stack::Message->new(
215             msgid => 'something_happened',
216             level => 'error',
217             scope => 'login_formm',
218             subject => 'username',
219             text => 'Something happened!'
220             ));
221             # Or... for those that want to type less
222             $stack->add({
223             msgid => 'something_else_happened',
224             level => 'error',
225             scope => 'login_form',
226             subject => 'password',
227             text => 'Something else happened!'
228             });
229              
230             # ...
231             my $errors = $stack->for_level('error');
232             # Or
233             my $login_form_errors = $stack->for_scope('login_form');
234             $login_form_errors->for_subject('username');
235             print "Username has ".$login_form_errors->count." errors.\n";
236              
237             =head1 DESCRIPTION
238              
239             Message::Stack provides a mechanism for storing messages until they can be
240             consumed. A stack is used to retain order of occurrence. Each message may
241             have a id, level, scope, subject and text. Consult the documentation for
242             L<Message::Stack::Message> for an explanation of these attributes.
243              
244             This is not a logging mechanism. The original use was to store various errors
245             or messages that occur during processing for later display in a web
246             application. The messages are added via C<add>.
247              
248             =head1 NOTES
249              
250             =head2 Note About msgid
251              
252             msgid used to be id. It was renamed to be a bit more description. All the
253             methods that existed for id still exist and the id attribute is now aliased
254             to msgid. In other words if you create an object using C<id> then the msgid
255             methods B<and> the C<id> methods will work, and vice versa.
256              
257             =head1 SERIALIZATION
258              
259             This module uses L<MooseX::Storage::Deferred> to facilitate easy serialization.
260             Consult the documentation for L<MooseX::Storage::Deferred> options, but the
261             gist is:
262              
263             my $json = $stack->freeze({ format => 'JSON' });
264             ...
265             my $stack = Message::Stack->thaw($json, { format => 'JSON' });
266              
267             =head1 ATTRIBUTES
268              
269             =head2 messages
270              
271             Returns the full arrayref of messages for this stack.
272              
273             =head1 METHODS
274              
275             =head2 count
276              
277             Returns the number of messages in the stack.
278              
279             =head2 first_message
280              
281             Returns the first message (if there is one, else undef)
282              
283             =head2 get_message ($index)
284              
285             Get the message at the supplied index.
286              
287             =head2 has_messages
288              
289             Returns true if there are messages in the stack, else false
290              
291             =head2 last_message
292              
293             Returns the last message (if there is one, else undef)
294              
295             =head2 reset
296              
297             Clear all messages, resetting this stack.
298              
299             =head2 add ($message)
300              
301             Adds the supplied message to the stack. C<$message> may be either a
302             L<Message::Stack::Message> object or a hashref with similar keys.
303              
304             =head2 for_msgid ($msgid)
305              
306             Returns a new Message::Stack containing only the message objects with the
307             supplied msgid. If there are no messages for that level then the stack
308             returned will have no messages.
309              
310             =head2 for_level ($level)
311              
312             Returns a new Message::Stack containing only the message objects with the
313             supplied level. If there are no messages for that level then the stack
314             returned will have no messages.
315              
316             =head2 for_scope ($scope)
317              
318             Returns a new Message::Stack containing only the message objects with the
319             supplied scope. If there are no messages for that scope then the stack
320             returned will have no messages.
321              
322             =head2 for_subject ($subject)
323              
324             Returns a new Message::Stack containing only the message objects with the
325             supplied subject. If there are no messages for that subject then the stack
326             returned will have no messages.
327              
328             =head2 has_msgid ($msgid)
329              
330             Returns true if there are messages with the supplied msgid.
331              
332             =head2 has_level ($level)
333              
334             Returns true if there are messages with the supplied level.
335              
336             =head2 has_scope ($scope)
337              
338             Returns true if there are messages with the supplied scope.
339              
340             =head2 has_subject ($subject)
341              
342             Returns true if there are messages with the supplied subject.
343              
344             =head2 search (CODEREF)
345              
346             Returns a Message::Stack containing messages that return true when passed
347             to the coderef argument.
348              
349             $stack->search( sub { $_[0]->id eq 'someid' } )
350              
351             =head2 reset_scope($scope)
352              
353             Clears the stack of all messages of scope $scope.
354              
355             =head2 reset_level($level)
356              
357             Clears the stack of all messages of level $level.
358              
359             =head2 reset_msgid($msgid)
360              
361             Clears the stack of all messages of msgid $msgid.
362              
363             =head2 reset_subject($subject)
364              
365             Clears the stack of all messages of subject $subject.
366              
367             =head1 CONTRIBUTORS
368              
369             Jay Shirley
370              
371             Stevan Little
372              
373             Justin Hunter
374              
375             Jon Wright
376              
377             Mike Eldridge
378              
379             Tomohiro Hosaka
380              
381             Andrew Nelson
382              
383             =head1 AUTHOR
384              
385             Cory G Watson <gphat@cpan.org>
386              
387             =head1 COPYRIGHT AND LICENSE
388              
389             This software is copyright (c) 2011 by Cory G Watson.
390              
391             This is free software; you can redistribute it and/or modify it under
392             the same terms as the Perl 5 programming language system itself.
393              
394             =cut
395