File Coverage

blib/lib/Dancer2/Plugin/PageHistory/PageSet.pm
Criterion Covered Total %
statement 48 49 97.9
branch 15 18 83.3
condition 11 15 73.3
subroutine 12 12 100.0
pod 5 5 100.0
total 91 99 91.9


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 4     4   169785 use Scalar::Util qw(blessed);
  4         6  
  4         163  
10 4     4   414 use Sub::Quote qw(quote_sub);
  4         8213  
  4         147  
11 4     4   392 use Dancer2::Core::Types qw(ArrayRef HashRef InstanceOf Int Maybe Str);
  4         6105  
  4         265  
12 4     4   470 use Moo;
  4         1998  
  4         20  
13 4     4   2749 use namespace::clean;
  4         20497  
  4         14  
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 Dancer2::Plugin::PageHistory::Page->new
43              
44             =item * a Dancer2::Plugin::PageHistory::Page object
45              
46             =back
47              
48             =cut
49              
50             has fallback_page => (
51             is => 'ro',
52             isa => Maybe [ InstanceOf ['Dancer2::Plugin::PageHistory::Page'] ],
53             default => undef,
54             coerce => sub {
55             $_[0] ? Dancer2::Plugin::PageHistory::Page->new( %{ $_[0] } ) : undef;
56             },
57             );
58              
59             =head2 max_items
60              
61             The maximum number of each history C stored in L.
62              
63             =cut
64              
65             has max_items => (
66             is => 'ro',
67             isa => Int,
68             default => 10,
69             );
70              
71             =head2 pages
72              
73             A hash reference of arrays of hash references.
74              
75             Primary key is the history C such as C or C. For each
76             C an array reference of pages is stored with new pages added at
77             the start of the array reference.
78              
79             =cut
80              
81             has pages => (
82             is => 'rw',
83             isa => HashRef [
84             ArrayRef [ InstanceOf ['Dancer2::Plugin::PageHistory::Page'] ] ],
85             coerce => \&_coerce_pages,
86             predicate => 1,
87             );
88              
89             sub _coerce_pages {
90 25     25   586 my %pages;
91 25         29 while ( my ( $type, $list ) = each %{ $_[0] } ) {
  55         1821  
92 30         46 foreach my $page (@$list) {
93 55 50 33     1601 if ( !blessed($page) && ref($page) eq 'HASH' ) {
94 55         61 push @{ $pages{$type} },
  55         918  
95             Dancer2::Plugin::PageHistory::Page->new(%$page);
96             }
97             }
98             }
99 25         316 return \%pages;
100             }
101              
102             =head2 methods
103              
104             An array reference of extra method names that should be added to the class.
105             For example if one of these method names is 'product' then the following
106             shortcut method will be added:
107              
108             sub product {
109             return shift->pages->{"product"};
110             }
111              
112             =cut
113              
114             has methods => (
115             is => 'ro',
116             isa => ArrayRef,
117             default => sub { [] },
118             trigger => 1,
119             );
120              
121             sub _trigger_methods {
122 15     15   1401 my ( $self, $methods ) = @_;
123 15         27 foreach my $method (@$methods) {
124 31 100       535 unless ( $self->can($method) ) {
125 7         30 quote_sub "Dancer2::Plugin::PageHistory::PageSet::$method",
126             q{ return shift->pages->{$type} || []; },
127             { '$type' => \$method };
128             }
129             }
130             }
131              
132             =head1 METHODS
133              
134             =head2 add( %args )
135              
136             C<$args{type}> defaults to L.
137              
138             In addition to C other arguments should be those passed to C in
139             L.
140              
141             =cut
142              
143             sub add {
144 20     20 1 3405 my ( $self, %args ) = @_;
145              
146 20   66     96 my $type = delete $args{type} || $self->default_type;
147              
148 20 100       62 die "args to add must include a defined path" unless defined $args{path};
149              
150 17         272 my $page = Dancer2::Plugin::PageHistory::Page->new(%args);
151              
152 17 100 66     3580 if ( !$self->pages->{$type}
      100        
153             || !$self->pages->{$type}->[0]
154             || $self->pages->{$type}->[0]->uri ne $page->uri )
155             {
156              
157             # not same uri as newest items on this list so add it
158              
159 15         1009 unshift( @{ $self->pages->{$type} }, $page );
  15         188  
160              
161             # trim to max_items if necessary
162 4         66 pop @{ $self->pages->{$type} }
163 15 100       69 if @{ $self->pages->{$type} } > $self->max_items;
  15         179  
164             }
165             }
166              
167             =head2 has_pages
168              
169             Predicate on L.
170              
171             =head2 page_index($index, $type)
172              
173             Returns the page from L of type C<$type> at position C<$index>.
174             If C<$type> is not supplied then L will be used.
175             If page is not found then L is returned instead.
176              
177             =cut
178              
179             sub page_index {
180 35     35 1 473 my ( $self, $index, $type ) = @_;
181              
182 35 50       77 die "index arg must be supplied to page_index" unless defined $index;
183 35 100       92 $type = $self->default_type unless $type;
184              
185 35 100 100     652 if ( $self->has_pages && defined $self->pages->{$type}->[$index] ) {
186 24         447 return $self->pages->{$type}->[$index];
187             }
188 11         57 return $self->fallback_page;
189             }
190              
191             =head2 latest_page($type)
192              
193             A convenience method equivalent to:
194              
195             page_index(0, $type)
196              
197             =cut
198              
199             sub latest_page {
200 18     18 1 17573 return shift->page_index( 0, shift );
201             }
202              
203             =head2 previous_page
204              
205             A convenience method equivalent to:
206              
207             page_index(1, $type)
208              
209             =cut
210              
211             sub previous_page {
212 16     16 1 3841 return shift->page_index( 1, shift );
213             }
214              
215             =head2 types
216              
217             Return all of the page types currently stored in history.
218              
219             In array context returns an array of type names (keys of L)
220             and in scalar context returns the same as an array reference.
221              
222             =cut
223              
224             sub types {
225 2     2 1 1592 my $self = shift;
226 2 50       6 wantarray ? keys %{ $self->pages } : [ keys %{ $self->pages } ];
  2         37  
  0            
227             }
228              
229             1;