File Coverage

blib/lib/Data/Paginator.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Data::Paginator;
2             $Data::Paginator::VERSION = '0.08';
3 6     6   68693 use Moose;
  0            
  0            
4              
5             # ABSTRACT: Pagination with Moose
6              
7             use Data::Paginator::Types qw(PositiveInt);
8             use MooseX::Types::Moose qw(Maybe);
9              
10              
11             has current_page => (
12             is => 'ro',
13             isa => 'Num',
14             default => 1
15             );
16              
17             has current_set => (
18             is => 'ro',
19             isa => Maybe[PositiveInt],
20             lazy_build => 1
21             );
22              
23              
24             has entries_per_page => (
25             is => 'ro',
26             isa => PositiveInt,
27             required => 1
28             );
29              
30              
31             has last_page => (
32             is => 'ro',
33             isa => PositiveInt,
34             lazy_build => 1
35             );
36              
37              
38             has next_set => (
39             is => 'ro',
40             isa => Maybe[PositiveInt],
41             lazy_build => 1
42             );
43              
44              
45             has pages_per_set => (
46             is => 'ro',
47             isa => Maybe[PositiveInt],
48             predicate => 'has_pages_per_set'
49             );
50              
51              
52             has previous_set => (
53             is => 'ro',
54             isa => Maybe[PositiveInt],
55             lazy_build => 1
56             );
57              
58              
59             has total_entries => (
60             is => 'ro',
61             isa => PositiveInt,
62             required => 1
63             );
64              
65             # This facilitates incorrect page numbers.
66             around 'current_page' => sub {
67             my ($orig, $self) = @_;
68              
69             my $attr = $self->meta->find_attribute_by_name('current_page');
70             my $val = $attr->get_value($self);
71             if(!defined($val)) {
72             $attr->set_value($self, 1);
73             return 1
74             } elsif($val < 1) {
75             $attr->set_value($self, 1);
76             return 1;
77             } elsif($val > $self->last_page) {
78             $attr->set_value($self, $self->last_page);
79             return $self->last_page;
80             }
81              
82             return $val;
83             };
84              
85             sub _build_current_set {
86             my ($self) = @_;
87              
88             return $self->set_for($self->current_page);
89             }
90              
91             sub _build_last_page {
92             my ($self) = @_;
93              
94             my $pages = $self->total_entries / $self->entries_per_page;
95             my $last_page;
96              
97             if ($pages == int $pages) {
98             $last_page = $pages;
99             } else {
100             $last_page = 1 + int($pages);
101             }
102              
103             $last_page = 1 if $last_page < 1;
104             return $last_page;
105             }
106              
107             sub _build_next_set {
108             my ($self) = @_;
109              
110             return undef unless $self->pages_per_set;
111              
112             my $next = $self->current_set * ($self->pages_per_set * $self->entries_per_page) + 1;
113             return undef if $next > $self->total_entries;
114             return $next;
115             }
116              
117             sub _build_previous_set {
118             my ($self) = @_;
119              
120             return undef unless $self->pages_per_set;
121             my $cset = $self->current_set;
122             return undef if $cset == 1;
123              
124             return ($cset - 2) * $self->pages_per_set * $self->entries_per_page + 1;
125             }
126              
127              
128             sub entries_on_this_page {
129             my ($self) = @_;
130              
131             if ($self->total_entries == 0) {
132             return 0;
133             } else {
134             return $self->last - $self->first + 1;
135             }
136             }
137              
138              
139             sub first {
140             my ($self) = @_;
141              
142             if ($self->total_entries == 0) {
143             return 0;
144             } else {
145             return (($self->current_page - 1) * $self->entries_per_page) + 1;
146             }
147             }
148              
149              
150             sub first_page {
151             my ($self) = @_;
152             return 1;
153             }
154              
155              
156             sub first_set {
157             my ($self) = @_;
158              
159             if($self->has_pages_per_set) {
160             return 1;
161             }
162              
163             return undef;
164             }
165              
166              
167             sub last {
168             my $self = shift;
169              
170             if ($self->current_page == $self->last_page) {
171             return $self->total_entries;
172             } else {
173             return ($self->current_page * $self->entries_per_page);
174             }
175             }
176              
177              
178             sub next_page {
179             my $self = shift;
180              
181             $self->current_page < $self->last_page ? $self->current_page + 1 : undef;
182             }
183              
184              
185             sub page_for {
186             my ($self, $num) = @_;
187              
188             return undef if $num > $self->total_entries || $num < 1;
189              
190             my $page = $num / $self->entries_per_page;
191             if($page > int($page)) {
192             return int($page) + 1;
193             }
194              
195             return $page;
196             }
197              
198              
199             sub previous_page {
200             my ($self) = @_;
201              
202             if ($self->current_page > 1) {
203             return $self->current_page - 1;
204             } else {
205             return undef;
206             }
207             }
208              
209              
210             sub set_for {
211             my ($self, $num) = @_;
212              
213             return undef unless $self->has_pages_per_set;
214              
215             my $set = $num / $self->pages_per_set;
216             if(int($set) != $set) {
217             return int($set) + 1;
218             }
219              
220             return $set;
221             }
222              
223             sub skipped {
224             my $self = shift;
225              
226             my $skipped = $self->first - 1;
227             return 0 if $skipped < 0;
228             return $skipped;
229             }
230              
231              
232             sub splice {
233             my ($self, $array) = @_;
234              
235             my $top = @$array > $self->last ? $self->last : @$array;
236             return () if $top == 0; # empty
237             return @{$array}[ $self->first - 1 .. $top - 1 ];
238             }
239              
240              
241             1;
242              
243             __END__
244              
245             =pod
246              
247             =encoding UTF-8
248              
249             =head1 NAME
250              
251             Data::Paginator - Pagination with Moose
252              
253             =head1 VERSION
254              
255             version 0.08
256              
257             =head1 SYNOPSIS
258              
259             use Data::Paginator;
260              
261             my $pager = Data::Paginator->new(
262             current_page => 1,
263             entries_per_page => 10,
264             total_entries => 100,
265             );
266              
267             print "First page: ".$pager->first_page."\n";
268             print "Last page: ".$pager->last_page."\n";
269             print "First entry on page: ".$pager->first."\n";
270             print "Last entry on page: ".$pager->last."\n";
271              
272             =head1 DESCRIPTION
273              
274             This is yet another pagination module. It only exists because none of the
275             other pager modules are written using Moose. Sometimes there is a Moose
276             feature – MooseX::Storage, in my case – that you need. It's a pain when
277             you can't use it with an existing module. This module aims to be completely
278             compatible with the venerable L<Data::Page>. In fact, it's a pretty blatant
279             copy of Data::Page, lifting code from some of it's methods.
280              
281             =head1 SETS
282              
283             This module provides behavior compatible with L<Data::PageSet>, allowing you
284             to break your pagination into sets. For example, if you have a large number
285             of pages to show and would like to allow the user to 'jump' X pages at a time,
286             you can set the C<pages_per_set> attribute to X and populate the links in your
287             pagination control with the values from C<previous_set> and C<next_set>.
288              
289             =head1 ATTRIBUTES
290              
291             =head2 current_page
292              
293             The current page. Defaults to 1. If you set this value to to a page number
294             lesser than or greater than the range of the pager, then 1 or the last_page
295             will be returned instead. It is safe to pass this numbers like -1000 or 1000
296             when there are only 3 pages.
297              
298             =head2 entries_per_page
299              
300             The number of entries per page, required at instantiation.
301              
302             =head2 last_page
303              
304             Returns the number of the last page. Lazily computed, so do not set.
305              
306             =head2 next_set
307              
308             Returns the number of the next set or undefined if there is no next.
309              
310             =head2 pages_per_set
311              
312             If you have a large number of pages to show and would like to allow the user
313             to 'jump' X pages at a time, you can set the C<pages_per_set> attribute to X
314             and populate the links in your pagination control with the values from
315             C<previous_set> and C<next_set>.
316              
317             =head2 previous_set
318              
319             Returns the set number of the previous set or undefined if there is no
320             previous set.
321              
322             =head2 total_entries
323              
324             The total number of entries this pager is covering. Required at
325             instantiation.
326              
327             =head2 first
328              
329             Returns the number of the first entry on the current page.
330              
331             =head2 first_page
332              
333             Always returns 1.
334              
335             =head1 METHODS
336              
337             =head2 entries_on_this_page
338              
339             Returns the number of entries on this page.
340              
341             =head2 first_set
342              
343             Returns 1 if this Paginator has pages_per_set. Otherwise returns undef.
344              
345             =head2 last
346              
347             Returns the number of the last entry on the current page.
348              
349             =head2 next_page
350              
351             Returns the page number of the next page if one exists, otherwise returns
352             false.
353              
354             =head2 page_for ($count)
355              
356             Returns the page number that the $count item appears on. Returns undef if
357             $count is outside the bounds of this Paginator.
358              
359             =head2 previous_page
360              
361             Returns the page number of the previous page if one exists, otherwise returns
362             undef.
363              
364             =head2 set_for $page
365              
366             Returns the set number of the specified page. Returns undef if the page
367             exceeds the bounds of the Paginator.
368              
369             =head2 splice
370              
371             Takes in an arrayref and returns only the values which are on the current
372             page.
373              
374             =head1 ACKNOWLEDGEMENTS
375              
376             Léon Brocard and his work on L<Data::Page>.
377              
378             =head1 AUTHOR
379              
380             Cory G Watson <gphat@cpan.org>
381              
382             =head1 COPYRIGHT AND LICENSE
383              
384             This software is copyright (c) 2014 by Cory G Watson.
385              
386             This is free software; you can redistribute it and/or modify it under
387             the same terms as the Perl 5 programming language system itself.
388              
389             =cut