File Coverage

blib/lib/Data/PaginatedTable.pm
Criterion Covered Total %
statement 67 69 97.1
branch n/a
condition n/a
subroutine 19 19 100.0
pod n/a
total 86 88 97.7


line stmt bran cond sub pod time code
1 1     1   26411 use 5.18.2;
  1         3  
  1         35  
2 1     1   4 use Modern::Perl;
  1         2  
  1         7  
3 1     1   669 use Moops;
  1         78107  
  1         7  
4              
5 1     1   140592 class Data::PaginatedTable 1.0.0 {
  1     1   22  
  1     1   9  
  1     1   1  
  1     1   57  
  1     1   437  
  1     1   1610  
  1     1   3  
  1     1   1458  
  1     1   1  
  1     1   7  
  1     1   57  
  1     1   2  
  1         44  
  1         4  
  1         1  
  1         82  
  1         32  
  1         4  
  1         1  
  1         10  
  1         3018  
  1         2  
  1         5  
  1         852  
  1         2966  
  1         5  
  1         114  
  1         9  
  1         9  
  1         633  
  1         6731  
  1         11  
  1         893  
  1         2382  
  1         5  
  1         1268  
  1         3230  
  1         11  
  1         104316  
  1         5  
  1         30  
  1         6  
  1         1  
  1         25  
  1         4  
  1         6  
  1         35  
  1         4  
  1         1  
  1         106  
6 1     1   557 use Types::XSD::Lite qw( PositiveInteger );
  1         95684  
  1         12  
7 1     1   1253 use Text::Table;
  1         14549  
  1         37  
8 1     1   212 use XML::Simple;
  0            
  0            
9             use XML::Simple::Sugar;
10             use POSIX qw(ceil);
11             use overload '""' => 'as_string';
12             use overload '@{}' => 'pages';
13             use constant VERTICAL => 'vertical';
14             use constant HORIZONTAL => 'horizontal';
15             use constant HTML => 'html';
16             use constant PREFORMATTED => 'preformatted';
17             use constant RAW => 'raw';
18              
19             has rows => ( is => 'rw', isa => PositiveInteger, default => 4 );
20             has columns => ( is => 'rw', isa => PositiveInteger, default => 3 );
21             has data => ( is => 'rw', isa => ArrayRef, required => true );
22             has fill_direction => (
23             is => 'rw',
24             isa => Enum [ VERTICAL, HORIZONTAL ],
25             default => HORIZONTAL
26             );
27             has string_mode =>
28             ( is => 'rw', isa => Enum [ HTML, PREFORMATTED, RAW ], default => RAW );
29             has current => ( is => 'rw', isa => PositiveInteger, default => 1 );
30              
31             method page ( $page? ) {
32             $self->current($page) if defined $page;
33              
34             my $data = $self->data;
35             my $min = $self->rows * $self->columns * ( $self->current - 1 );
36             my $max = $self->rows * $self->columns * $self->current - 1;
37              
38             my $i = 0;
39             my $k = 0;
40             my $next_ik = $self->fill_direction eq VERTICAL
41             ? sub {
42             $i++;
43             if ( $i == $self->rows ) { $i = 0; $k++; }
44             }
45             : sub {
46             $k++;
47             if ( $k == $self->columns ) { $k = 0; $i++; }
48             };
49              
50             my @table;
51             foreach my $row ( @{$data}[ $min .. $max ] ) {
52             $table[$i][$k] = $row;
53             $next_ik->();
54             }
55              
56             \@table;
57             }
58              
59             method pages {
60             [ map { $self->page($_) } 1 .. $self->page_count ];
61             }
62              
63             method as_string {
64             my $string_mode = 'as_' . $self->string_mode;
65             $self->$string_mode;
66             }
67              
68             method as_raw {
69             my $string;
70             foreach my $row ( @{ $self->page } ) {
71             $string .= "$row->[$_]" for 0 .. @$row - 1;
72             }
73             $string;
74             }
75              
76             method as_preformatted {
77             my $text_table = Text::Table->new;
78             $text_table->load( @{ $self->page } );
79             "$text_table";
80             }
81              
82             method as_html {
83             my $xs = XML::Simple::Sugar->new(
84             { xml_xs => XML::Simple->new( XMLDecl => '' ) } );
85             my $table = $xs->table;
86              
87             my $i = 0;
88             foreach my $row ( @{ $self->page } ) {
89             $table->tr( [$i] )->td( [ $_, "$row->[$_]" ] ) for 0 .. @$row - 1;
90             $i++;
91             }
92              
93             $xs->xml_write;
94             }
95              
96             method page_count {
97             ceil( @{ $self->data } / $self->columns / $self->rows );
98             }
99              
100             method next {
101             return if $self->current >= $self->page_count;
102             $self->current( $self->current + 1 );
103             $self;
104             }
105              
106             method previous {
107             return if $self->current <= 1;
108             $self->current( $self->current - 1 );
109             $self;
110             }
111              
112             method last {
113             $self->current( $self->page_count );
114             $self;
115             }
116              
117             method first {
118             $self->current(1);
119             $self;
120             }
121             }
122              
123             1;
124              
125             # ABSTRACT: Paginate lists as two-dimensional arrays and stringify
126             # PODNAME: Data::PaginatedTable
127              
128             __END__
129              
130             =pod
131              
132             =encoding UTF-8
133              
134             =head1 NAME
135              
136             Data::PaginatedTable - Paginate lists as two-dimensional arrays and stringify
137              
138             =head1 VERSION
139              
140             version 1.0.0
141              
142             =head1 SYNOPSIS
143              
144             use Modern::Perl;
145             use Data::PaginatedTable;
146             use Data::Printer;
147            
148             my @series = 'aaa' .. 'zzz';
149            
150             my $pt = Data::PaginatedTable->new(
151             {
152             data => \@series,
153             string_mode => 'preformatted',
154             fill_direction => 'vertical',
155             }
156             );
157            
158             do { say $pt } while ( $pt->next );
159            
160             # aaa aae aai
161             # aab aaf aaj
162             # aac aag aak
163             # aad aah aal
164             #
165             # ...
166             #
167             # zzg zzk zzo
168             # zzh zzl zzp
169             # zzi zzm zzq
170             # zzj zzn zzr
171             #
172             # zzs zzw
173             # zzt zzx
174             # zzu zzy
175             # zzv zzz
176              
177              
178             say Data::Printer::p( $pt->page( 32 ) );
179              
180             # \ [
181             # [0] [
182             # [0] "aoi",
183             # [1] "aom",
184             # [2] "aoq"
185             # ],
186             # [1] [
187             # [0] "aoj",
188             # [1] "aon",
189             # [2] "aor"
190             # ],
191             # [2] [
192             # [0] "aok",
193             # [1] "aoo",
194             # [2] "aos"
195             # ],
196             # [3] [
197             # [0] "aol",
198             # [1] "aop",
199             # [2] "aot"
200             # ]
201             # ]
202              
203             =head1 DESCRIPTION
204              
205             This is yet another class to generate tables and paginate data. Each page represents a two-dimensional array of given dimensions, and can be filled horizontally or vertically. In string context, an instance of C<Data::PaginatedTable> will invoke one of the C<string_mode> methods to render the C<current> page.
206              
207             =head1 ATTRIBUTES
208              
209             =head2 data, data ( ArrayRef REQUIRED )
210              
211             Gets or sets the data to be transformed by the instance of C<Data::PaginatedTable>.
212              
213             =head2 rows, rows ( PositiveInteger default => 4 )
214              
215             Gets or sets the number of rows per C<page>.
216              
217             =head2 columns, columns ( PositiveInteger default => 3 )
218              
219             Gets or sets the number of columns per C<row>.
220              
221             =head2 fill_direction, fill_direction ( Enum[ 'vertical', 'horizontal' ] default => 'horizontal' )
222              
223             Gets or sets the order in which C<data> elements will be used to fill the two-dimensional array of each C<page>.
224              
225             use Modern::Perl;
226             use Data::PaginatedTable;
227            
228             my @series = 1 .. 9;
229            
230             my $pt = Data::PaginatedTable->new(
231             {
232             data => \@series,
233             rows => 3,
234             columns => 3,
235             fill_direction => 'vertical', # default horizontal
236             string_mode => 'preformatted'
237             }
238             );
239             say $pt;
240            
241             # 1 4 7
242             # 2 5 8
243             # 3 6 9
244            
245             $pt->fill_direction( 'horizontal' );
246             say $pt;
247              
248             # 1 2 3
249             # 4 5 6
250             # 7 8 9
251              
252             =head2 string_mode, string_mode ( Enum[ 'html', 'preformatted', 'raw' ] default => 'raw' );
253              
254             Gets or sets the method to use when a Data::PaginatedTable object is used in string context. See L</STRING MODES>.
255              
256             =head2 current, current ( PositiveInteger default => 1 );
257              
258             Gets or sets the current C<page>.
259              
260             =head1 METHODS
261              
262             =head2 page_count
263              
264             Returns the total number of pages based on the number of C<rows> and C<columns>.
265              
266             =head2 page, page( PositiveInteger )
267              
268             Returns the two-dimensional array with the given number of C<rows> and C<columns> representing the C<current> page, or optionally returns a specific page when passed an integer argument.
269              
270             =head2 pages
271              
272             Returns an array reference containing each C<page> of C<data>.
273              
274             =head2 first
275              
276             Sets the C<current> page to the first C<page> and returns the instance.
277              
278             =head2 next
279              
280             Sets the C<current> page to the next C<page> and returns the instance or undef if there are no next pages.
281              
282             =head2 previous
283              
284             Sets the C<current> page to the previous C<page> and returns the instance or undef if there are no previous pages.
285              
286             =head2 last
287              
288             Sets the C<current> page to the last C<page> and returns the instance.
289              
290             =head1 STRING MODES
291              
292             =head2 as_string
293              
294             This is a wrapper around the as_* C<string_mode> methods. This method is called implicitly when the instance is in string context.
295              
296             =head2 as_html
297              
298             The html C<string_mode> stringifies the C<current> C<page> as a plain html table. All C<page> elements are placed in string context (see L<overload>).
299              
300             use Modern::Perl;
301             use Data::PaginatedTable;
302            
303             my @series = 1 .. 12;
304            
305             my $pt = Data::PaginatedTable->new(
306             {
307             data => \@series,
308             string_mode => 'html'
309             }
310             );
311            
312             say $pt;
313            
314             # <table>
315             # <tr>
316             # <td>1</td>
317             # <td>2</td>
318             # <td>3</td>
319             # </tr>
320             # <tr>
321             # <td>4</td>
322             # <td>5</td>
323             # <td>6</td>
324             # </tr>
325             # <tr>
326             # <td>7</td>
327             # <td>8</td>
328             # <td>9</td>
329             # </tr>
330             # <tr>
331             # <td>10</td>
332             # <td>11</td>
333             # <td>12</td>
334             # </tr>
335             # </table>
336              
337             =head2 as_preformatted
338              
339             The preformatted C<string_mode> uses L<Text::Table> to format the C<current> C<page>. All C<page> elements are placed in string context (see L<overload>).
340              
341             use Modern::Perl;
342             use Data::PaginatedTable;
343            
344             my @series = 1 .. 12;
345            
346             my $pt = Data::PaginatedTable->new(
347             {
348             data => \@series,
349             string_mode => 'preformatted'
350             }
351             );
352            
353             say $pt;
354            
355             # 1 2 3
356             # 4 5 6
357             # 7 8 9
358             # 10 11 12
359              
360             =head2 as_raw
361              
362             The C<as_raw> method iterates over the C<page> elements and invokes each in string context (see L<overload>), without seperating C<rows> with newlines. This method is likely not how you want to render your data unless your C<data> elements are string L<overload>ed objects with their own rendering logic.
363              
364             =head1 VERSIONING
365              
366             This module adopts semantic versioning (L<http://www.semver.org>).
367              
368             =head1 REPOSITORY
369              
370             L<https://github.com/Camspi/Data-PaginatedTable>
371              
372             =head2 SEE ALSO
373              
374             =over 4
375              
376             *
377             L<Text::Table>
378              
379             *
380             L<Data::Table>
381              
382             *
383             L<Data::Tabular>
384              
385             *
386             L<Data::Tabulate>
387              
388             *
389             L<Data::Tabulator>
390              
391             *
392             L<Data::Paginated>
393              
394             =back
395              
396             =head1 AUTHOR
397              
398             Chris Tijerina
399              
400             =head1 COPYRIGHT AND LICENSE
401              
402             This software is copyright (c) 2015 by Chris Tijerina.
403              
404             This is free software; you can redistribute it and/or modify it under
405             the same terms as the Perl 5 programming language system itself.
406              
407             =cut