File Coverage

blib/lib/Data/Pageset/Exponential.pm
Criterion Covered Total %
statement 133 133 100.0
branch 21 22 95.4
condition n/a
subroutine 28 28 100.0
pod 9 12 75.0
total 191 195 97.9


line stmt bran cond sub pod time code
1             package Data::Pageset::Exponential;
2              
3             # ABSTRACT: Page numbering for very large page numbers
4              
5 3     3   1084639 use v5.20;
  3         11  
6              
7 3     3   1852 use Moo;
  3         26643  
  3         24  
8              
9 3     3   5339 use List::Util 1.33 qw( all min );
  3         71  
  3         240  
10 3     3   1552 use PerlX::Maybe qw( maybe );
  3         9106  
  3         15  
11 3     3   1926 use POSIX qw( ceil floor );
  3         23038  
  3         19  
12 3     3   6877 use MooX::Aliases;
  3         19057  
  3         21  
13 3     3   2535 use MooX::TypeTiny;
  3         1155  
  3         49  
14 3     3   38402 use Types::Common 2.000000 qw( is_Int Int ArrayRef is_HashRef PositiveOrZeroInt PositiveInt );
  3         951142  
  3         29  
15              
16 3     3   13410 use experimental qw( postderef signatures );
  3         4149  
  3         18  
17              
18              
19 3     3   1941 use asa 'Data::Page';
  3         878  
  3         18  
20              
21 3     3   1889 use namespace::autoclean;
  3         55790  
  3         14  
22              
23             # RECOMMEND PREREQ: Type::Tiny::XS
24             # RECOMMEND PREREQ: Ref::Util::XS
25              
26             our $VERSION = 'v0.4.1';
27              
28              
29             has total_entries => (
30             is => 'rw',
31             isa => PositiveOrZeroInt,
32             default => 0,
33             );
34              
35              
36             has entries_per_page => (
37             is => 'rw',
38             isa => PositiveInt,
39             default => 10,
40             );
41              
42              
43             has first_page => (
44             is => 'ro',
45             isa => Int,
46             default => 1,
47             );
48              
49              
50             has current_page => (
51             is => 'rw',
52             isa => Int,
53             lazy => 1,
54             default => \&first_page,
55             coerce => sub($val) { floor( $val // 0 ) },
56             );
57              
58              
59             has exponent_base => (
60             is => 'ro',
61             isa => PositiveInt,
62             default => 10,
63             );
64              
65              
66             has exponent_max => (
67             is => 'ro',
68             isa => PositiveInt,
69             default => 3,
70             );
71              
72              
73             has pages_per_exponent => (
74             is => 'ro',
75             isa => PositiveInt,
76             default => 3,
77             );
78              
79              
80 1         3 has pages_per_set => (
81             is => 'lazy',
82             isa => PositiveInt,
83             alias => 'max_pages_per_set',
84 1     1   1223 builder => sub($self) {
  1         3  
85 3     3   2501 use integer;
  3         42  
  3         30  
86 1         8 my $n = $self->pages_per_exponent * ( $self->exponent_max + 1 );
87 1         26 return ( $n - 1 ) * 2 + 1;
88             },
89             );
90              
91              
92 1         4 has series => (
93             is => 'lazy',
94             isa => ArrayRef [Int],
95 1     1   15 builder => sub($self) {
  1         2  
96 3     3   350 use integer;
  3         5  
  3         12  
97              
98 1         2 my @series;
99              
100 1         7 my $n = $self->exponent_base;
101 1         5 my $m = $self->exponent_max;
102              
103 1         2 my $j = 0;
104 1         7 while ( $j <= $m ) {
105              
106 4         8 my $i = $n**$j;
107 4         7 my $a = $i;
108 4         12 my $p = $self->pages_per_exponent;
109              
110 4         11 while ( $p-- ) {
111 12         24 push @series, $a - 1;
112 12         28 $a += $i;
113             }
114              
115 4         9 $j++;
116              
117             }
118              
119 1         7 my @prevs = map { -$_ } reverse @series[ 1 .. $#series ];
  11         23  
120              
121 1         35 return [ @prevs, @series ];
122             },
123             );
124              
125             around current_page => sub( $next, $self, @args ) {
126              
127             # N.B. unlike Data::Page, setting a value outside the first_page
128             # or last_page will not return that value.
129              
130             my $page = $self->$next(@args);
131              
132             return $self->first_page if $page < $self->first_page;
133              
134             return $self->last_page if $page > $self->last_page;
135              
136             return $page;
137             };
138              
139              
140 71     71 1 71959 sub entries_on_this_page($self) {
  71         151  
  71         128  
141 71 100       2456 if ( $self->total_entries ) {
142 68         670 return $self->last - $self->first + 1;
143             }
144             else {
145 3         37 return 0;
146             }
147             }
148              
149              
150 1558     1558 1 113265 sub last_page($self) {
  1558         2495  
  1558         2285  
151 1558 100       31891 return $self->total_entries
152             ? ceil( $self->total_entries / $self->entries_per_page )
153             : $self->first_page;
154             }
155              
156              
157 386     386 1 60667 sub first($self) {
  386         643  
  386         532  
158 386 100       8638 if ( $self->total_entries ) {
159 380         10409 return ( $self->current_page - 1 ) * $self->entries_per_page + 1;
160             }
161             else {
162 6         117 return 0;
163             }
164             }
165              
166              
167 211     211 1 62909 sub last($self) {
  211         446  
  211         338  
168 211 100       6953 if ( $self->current_page == $self->last_page ) {
169 121         2919 return $self->total_entries;
170             }
171             else {
172 90         2877 return $self->current_page * $self->entries_per_page;
173             }
174             }
175              
176              
177 71     71 1 65450 sub previous_page($self) {
  71         166  
  71         126  
178 71         2583 my $page = $self->current_page;
179              
180 71 100       616 return $page > $self->first_page
181             ? $page - 1
182             : undef;
183             }
184              
185              
186 71     71 1 191 sub next_page($self) {
  71         129  
  71         141  
187 71         2570 my $page = $self->current_page;
188              
189 71 100       957 return $page < $self->last_page
190             ? $page + 1
191             : undef;
192             }
193              
194              
195 72     72 0 852 sub splice( $self, $items ) {
  72         151  
  72         126  
  72         112  
196 72         197 my $last = min( $self->last, scalar( $items->@* ) );
197              
198             return $last
199 72 100       995 ? @{$items}[ $self->first - 1 .. $last - 1 ]
  68         891  
200             : ();
201             }
202              
203              
204 71     71 0 63596 sub skipped($self) {
  71         148  
  71         119  
205 71 100       2334 return $self->total_entries
206             ? $self->first - 1
207             : 0;
208             }
209              
210             # Ideally, we'd use a trigger instead, but Moo does not pass the old
211             # value to a trigger.
212              
213             around entries_per_page => sub( $next, $self, @args ) {
214             if (@args) {
215              
216             my ($value) = @args;
217              
218             my $first = $self->first;
219              
220             $self->$next($value);
221              
222             $self->current_page( $self->first_page + $first / $value );
223              
224             return $value;
225             }
226             else {
227              
228             return $self->$next;
229              
230             }
231             };
232              
233              
234 2     2 1 969 sub pages_in_set($self) {
  2         5  
  2         5  
235 3     3   3269 use integer;
  3         6  
  3         13  
236              
237 2         9 my $first = $self->first_page;
238 2         7 my $last = $self->last_page;
239 2         74 my $page = $self->current_page;
240              
241             return [
242 46 100       149 grep { $first <= $_ && $_ <= $last }
243 2         28 map { $page + $_ } @{ $self->series }
  46         99  
  2         48  
244             ];
245             }
246              
247              
248 2     2 1 7 sub previous_set($self) {
  2         5  
  2         4  
249 2         111 my $page = $self->current_page - ( 2 * $self->pages_per_exponent ) - 1;
250 2 100       20 return $page < $self->first_page
251             ? undef
252             : $page;
253             }
254              
255              
256 2     2 1 7 sub next_set($self) {
  2         5  
  2         5  
257 2         85 my $page = $self->current_page + ( 2 * $self->pages_per_exponent ) - 1;
258 2 50       7 return $page > $self->last_page
259             ? undef
260             : $page;
261             }
262              
263              
264 70     70 0 61848 sub change_entries_per_page( $self, $value ) {
  70         144  
  70         177  
  70         127  
265 70         2696 $self->entries_per_page($value);
266              
267 70         1426 return $self->current_page;
268             }
269              
270              
271             sub BUILDARGS( $class, @args ) {
272              
273             if ( @args == 1 && is_HashRef(@args) ) {
274             return $args[0];
275             }
276              
277             if ( @args && ( @args <= 3 ) && all { is_Int($_) } @args ) {
278              
279             return {
280             total_entries => $args[0],
281             maybe
282             entries_per_page => $args[1],
283             maybe current_page => $args[2],
284             };
285              
286             }
287              
288             return {@args};
289             }
290              
291              
292             1;
293              
294             __END__