File Coverage

blib/lib/Dancer2/Plugin/PageHistory/PageSet.pm
Criterion Covered Total %
statement 50 51 98.0
branch 13 16 81.2
condition 11 15 73.3
subroutine 13 13 100.0
pod 5 5 100.0
total 92 100 92.0


line stmt bran cond sub pod time code
1             package Dancer2::Plugin::PageHistory::PageSet;
2              
3             =head1 NAME
4              
5             Dancer2::Plugin::PageHistory::PageSet - collection of pages with accessors
6              
7             =cut
8              
9 5     5   164737 use Carp qw(croak);
  5         7  
  5         215  
10 5     5   17 use Scalar::Util qw(blessed);
  5         5  
  5         175  
11 5     5   386 use Sub::Quote qw(quote_sub);
  5         7968  
  5         173  
12 5     5   400 use Dancer2::Core::Types qw(ArrayRef HashRef InstanceOf Int Maybe Str);
  5         5861  
  5         323  
13 5     5   435 use Moo;
  5         1967  
  5         20  
14 5     5   3347 use namespace::clean;
  5         28758  
  5         18  
15              
16             =head1 ATTRIBUTES
17              
18             =head2 default_type
19              
20             For all methods that expect an argument C then this C
21             will be the one used when C is not specified. Defaults to C.
22              
23             =cut
24              
25             has default_type => (
26             is => 'ro',
27             isa => Str,
28             default => 'default',
29             );
30              
31             =head2 fallback_page
32              
33             In the event that L or L have no page to
34             return then L is returned instead.
35              
36             By default this is set to undef.
37              
38             You can set this page to something else by passing any of the following as
39             the value of this attribute:
40              
41             =over
42              
43             =item * a hash reference to be passed to Dancer2::Plugin::PageHistory::Page->new
44              
45             =item * a Dancer2::Plugin::PageHistory::Page object
46              
47             =back
48              
49             =cut
50              
51             has fallback_page => (
52             is => 'ro',
53             isa => Maybe [ InstanceOf ['Dancer2::Plugin::PageHistory::Page'] ],
54             default => undef,
55             coerce => sub {
56             $_[0] ? Dancer2::Plugin::PageHistory::Page->new( %{ $_[0] } ) : undef;
57             },
58             );
59              
60             =head2 max_items
61              
62             The maximum number of each history C stored in L.
63              
64             =cut
65              
66             has max_items => (
67             is => 'ro',
68             isa => Int,
69             default => 10,
70             );
71              
72             =head2 pages
73              
74             A hash reference of arrays of hash references.
75              
76             Primary key is the history C such as C or C. For each
77             C an array reference of pages is stored with new pages added at
78             the start of the array reference.
79              
80             =cut
81              
82             has pages => (
83             is => 'rw',
84             isa => HashRef [
85             ArrayRef [ InstanceOf ['Dancer2::Plugin::PageHistory::Page'] ] ],
86             coerce => \&_coerce_pages,
87             predicate => 1,
88             );
89              
90             sub _coerce_pages {
91 29     29   672 my %pages;
92 29         30 while ( my ( $type, $list ) = each %{ $_[0] } ) {
  61         294  
93 32         46 foreach my $page (@$list) {
94 57 50 33     353 if ( !blessed($page) && ref($page) eq 'HASH' ) {
95 57         40 push @{ $pages{$type} },
  57         883  
96             Dancer2::Plugin::PageHistory::Page->new(%$page);
97             }
98             }
99             }
100 29         356 return \%pages;
101             }
102              
103             =head2 methods
104              
105             An array reference of extra method names that should be added to the class.
106             For example if one of these method names is 'product' then the following
107             shortcut method will be added:
108              
109             sub product {
110             return shift->pages->{"product"};
111             }
112              
113             =cut
114              
115             has methods => (
116             is => 'ro',
117             isa => ArrayRef,
118             default => sub { [] },
119             trigger => 1,
120             );
121              
122             sub _trigger_methods {
123 19     19   1764 my ( $self, $methods ) = @_;
124 19         31 foreach my $method (@$methods) {
125 39 100       622 unless ( $self->can($method) ) {
126 9         48 quote_sub "Dancer2::Plugin::PageHistory::PageSet::$method",
127             q{ return shift->pages->{$type} || []; },
128             { '$type' => \$method };
129             }
130             }
131             }
132              
133             =head1 METHODS
134              
135             =head2 add( %args )
136              
137             C<$args{type}> defaults to L.
138              
139             In addition to C other arguments should be those passed to C in
140             L.
141              
142             =cut
143              
144             sub add {
145 22     22 1 4469 my ( $self, %args ) = @_;
146              
147 22   66     94 my $type = delete $args{type} || $self->default_type;
148              
149 22         353 my $page = Dancer2::Plugin::PageHistory::Page->new(%args);
150              
151 19 100 66     1217 if ( !$self->pages->{$type}
      100        
152             || !$self->pages->{$type}->[0]
153             || $self->pages->{$type}->[0]->uri ne $page->uri )
154             {
155              
156             # not same uri as newest items on this list so add it
157              
158 17         1345 unshift( @{ $self->pages->{$type} }, $page );
  17         211  
159              
160             # trim to max_items if necessary
161 4         64 pop @{ $self->pages->{$type} }
162 17 100       77 if @{ $self->pages->{$type} } > $self->max_items;
  17         209  
163             }
164             }
165              
166             =head2 has_pages
167              
168             Predicate on L.
169              
170             =head2 page_index($index, $type)
171              
172             Returns the page from L of type C<$type> at position C<$index>.
173             If C<$type> is not supplied then L will be used.
174             If page is not found then L is returned instead.
175              
176             =cut
177              
178             sub page_index {
179 37     37 1 427 my ( $self, $index, $type ) = @_;
180              
181 37 50       76 croak "index arg must be supplied to page_index" unless defined $index;
182 37 100       97 $type = $self->default_type unless $type;
183              
184 37 100 100     601 if ( $self->has_pages && defined $self->pages->{$type}->[$index] ) {
185 26         466 return $self->pages->{$type}->[$index];
186             }
187 11         61 return $self->fallback_page;
188             }
189              
190             =head2 latest_page($type)
191              
192             A convenience method equivalent to:
193              
194             page_index(0, $type)
195              
196             =cut
197              
198             sub latest_page {
199 20     20 1 14801 return shift->page_index( 0, shift );
200             }
201              
202             =head2 previous_page
203              
204             A convenience method equivalent to:
205              
206             page_index(1, $type)
207              
208             =cut
209              
210             sub previous_page {
211 16     16 1 3978 return shift->page_index( 1, shift );
212             }
213              
214             =head2 types
215              
216             Return all of the page types currently stored in history.
217              
218             In array context returns an array of type names (keys of L)
219             and in scalar context returns the same as an array reference.
220              
221             =cut
222              
223             sub types {
224 2     2 1 1614 my $self = shift;
225 2 50       5 wantarray ? keys %{ $self->pages } : [ keys %{ $self->pages } ];
  2         23  
  0            
226             }
227              
228             1;