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   48870 use Moo;
  3         16948  
  3         15  
10 3     3   2966 use Scalar::Util qw(blessed);
  3         6  
  3         153  
11 3     3   1064 use Sub::Quote qw(quote_sub);
  3         5989  
  3         161  
12 3     3   1125 use Types::Standard qw(ArrayRef HashRef InstanceOf Int Maybe Str);
  3         114777  
  3         32  
13 3     3   3219 use namespace::clean;
  3         7196  
  3         20  
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   531 my %pages;
90 21         34 while ( my ( $type, $list ) = each %{ $_[0] } ) {
  45         1176  
91 24         48 foreach my $page (@$list) {
92 41 50 33     943 if ( !blessed($page) && ref($page) eq 'HASH' ) {
93 41         49 push @{ $pages{$type} },
  41         883  
94             Dancer::Plugin::PageHistory::Page->new(%$page);
95             }
96             }
97             }
98 21         394 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   622 my ( $self, $methods ) = @_;
122 11         25 foreach my $method ( @$methods ) {
123 22 100       437 unless ( $self->can( $method )) {
124 4         26 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 3406 my ( $self, %args ) = @_;
143              
144 18   66     107 my $type = delete $args{type} || $self->default_type;
145              
146 18 100       74 die "args to add must include a defined path" unless defined $args{path};
147              
148 15         311 my $page = Dancer::Plugin::PageHistory::Page->new( %args );
149              
150 15 50 66     2898 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         646 unshift( @{ $self->pages->{$type} }, $page );
  15         250  
158              
159             # trim to max_items if necessary
160 4         75 pop @{ $self->pages->{$type} }
  15         209  
161 15 100       79 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 352 my ( $self, $index, $type ) = @_;
179              
180 37 50       97 die "index arg must be supplied to page_index" unless defined $index;
181 37 100       126 $type = $self->default_type unless $type;
182              
183 37 100 100     808 if ( $self->has_pages && defined $self->pages->{$type}->[$index] ) {
184 24         611 return $self->pages->{$type}->[$index];
185             }
186 13         94 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 13678 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 8298 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 1844 my $self = shift;
225 2 50       5 wantarray ? keys %{$self->pages} : [ keys %{$self->pages} ];
  2         27  
  0            
226             }
227              
228             1;