File Coverage

blib/lib/Dancer/Plugin/PageHistory/PageSet.pm
Criterion Covered Total %
statement 48 49 97.9
branch 14 18 77.7
condition 10 15 66.6
subroutine 12 12 100.0
pod 5 5 100.0
total 89 99 89.9


line stmt bran cond sub pod time code
1             package Dancer::Plugin::PageHistory::PageSet;
2              
3             =head1 NAME
4              
5             Dancer::Plugin::PageHistory::PageSet - collection of pages with accessors
6              
7             =cut
8              
9 3     3   87176 use Moo;
  3         22351  
  3         24  
10 3     3   3857 use Scalar::Util qw(blessed);
  3         10  
  3         497  
11 3     3   1413 use Sub::Quote qw(quote_sub);
  3         7124  
  3         247  
12 3     3   1460 use Types::Standard qw(ArrayRef HashRef InstanceOf Int Maybe Str);
  3         174561  
  3         49  
13 3     3   4502 use namespace::clean;
  3         9528  
  3         32  
14              
15             =head1 ATTRIBUTES
16              
17             =head2 default_type
18              
19             For all methods that expect an argument C then this C
20             will be the one used when C is not specified. Defaults to C.
21              
22             =cut
23              
24             has default_type => (
25             is => 'ro',
26             isa => Str,
27             default => 'default',
28             );
29              
30             =head2 fallback_page
31              
32             In the event that L or L have no page to
33             return then L is returned instead.
34              
35             By default this is set to undef.
36              
37             You can set this page to something else by passing any of the following as
38             the value of this attribute:
39              
40             =over
41              
42             =item * a hash reference to be passed to Dancer::Plugin::PageHistory::Page->new
43              
44             =item * a Dancer::Plugin::PageHistory::Page object
45              
46             =back
47              
48             =cut
49              
50             has fallback_page => (
51             is => 'ro',
52             isa => Maybe [ InstanceOf ['Dancer::Plugin::PageHistory::Page'] ],
53             default => undef,
54             coerce =>
55             sub { $_[0] ? Dancer::Plugin::PageHistory::Page->new( %{$_[0]} ) : undef },
56             );
57              
58             =head2 max_items
59              
60             The maximum number of each history C stored in L.
61              
62             =cut
63              
64             has max_items => (
65             is => 'ro',
66             isa => Int,
67             default => 10,
68             );
69              
70             =head2 pages
71              
72             A hash reference of arrays of hash references.
73              
74             Primary key is the history C such as C or C. For each
75             C an array reference of pages is stored with new pages added at
76             the start of the array reference.
77              
78             =cut
79              
80             has pages => (
81             is => 'rw',
82             isa =>
83             HashRef [ ArrayRef [ InstanceOf ['Dancer::Plugin::PageHistory::Page'] ] ],
84             coerce => \&_coerce_pages,
85             predicate => 1,
86             );
87              
88             sub _coerce_pages {
89 21     21   1047 my %pages;
90 21         60 while ( my ( $type, $list ) = each %{ $_[0] } ) {
  45         2393  
91 24         77 foreach my $page (@$list) {
92 41 50 33     1776 if ( !blessed($page) && ref($page) eq 'HASH' ) {
93 41         70 push @{ $pages{$type} },
  41         1849  
94             Dancer::Plugin::PageHistory::Page->new(%$page);
95             }
96             }
97             }
98 21         645 return \%pages;
99             }
100              
101             =head2 methods
102              
103             An array reference of extra method names that should be added to the class.
104             For example if one of these method names is 'product' then the following
105             shortcut method will be added:
106              
107             sub product {
108             return shift->pages->{"product"};
109             }
110              
111             =cut
112              
113             has methods => (
114             is => 'ro',
115             isa => ArrayRef,
116             default => sub { [] },
117             trigger => 1,
118             );
119              
120             sub _trigger_methods {
121 11     11   1136 my ( $self, $methods ) = @_;
122 11         46 foreach my $method ( @$methods ) {
123 22 100       784 unless ( $self->can( $method )) {
124 4         34 quote_sub "Dancer::Plugin::PageHistory::PageSet::$method",
125             q{ return shift->pages->{$type}; }, { '$type' => \$method };
126             }
127             }
128             }
129              
130             =head1 METHODS
131              
132             =head2 add( %args )
133              
134             C<$args{type}> defaults to L.
135              
136             In addition to C other arguments should be those passed to C in
137             L.
138              
139             =cut
140              
141             sub add {
142 18     18 1 5973 my ( $self, %args ) = @_;
143              
144 18   66     163 my $type = delete $args{type} || $self->default_type;
145              
146 18 100       97 die "args to add must include a defined path" unless defined $args{path};
147              
148 15         543 my $page = Dancer::Plugin::PageHistory::Page->new( %args );
149              
150 15 50 66     4640 if ( !$self->pages->{$type}
      66        
151             || !$self->pages->{$type}->[0]
152             || $self->pages->{$type}->[0]->uri ne $page->uri )
153             {
154              
155             # not same uri as newest items on this list so add it
156              
157 15         1124 unshift( @{ $self->pages->{$type} }, $page );
  15         429  
158              
159             # trim to max_items if necessary
160 4         118 pop @{ $self->pages->{$type} }
  15         336  
161 15 100       138 if @{ $self->pages->{$type} } > $self->max_items;
162             }
163             }
164              
165             =head2 has_pages
166              
167             Predicate on L.
168              
169             =head2 page_index($index, $type)
170              
171             Returns the page from L of type C<$type> at position C<$index>.
172             If C<$type> is not supplied then L will be used.
173             If page is not found then L is returned instead.
174              
175             =cut
176              
177             sub page_index {
178 37     37 1 625 my ( $self, $index, $type ) = @_;
179              
180 37 50       186 die "index arg must be supplied to page_index" unless defined $index;
181 37 100       227 $type = $self->default_type unless $type;
182              
183 37 100 100     1169 if ( $self->has_pages && defined $self->pages->{$type}->[$index] ) {
184 24         831 return $self->pages->{$type}->[$index];
185             }
186 13         155 return $self->fallback_page;
187             }
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 18     18 1 32457 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 18     18 1 18937 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 4726 my $self = shift;
225 2 50       10 wantarray ? keys %{$self->pages} : [ keys %{$self->pages} ];
  2         55  
  0            
226             }
227              
228             1;