List::Index->ranges
[perl/list-index.git] / lib / List / Index.pm
1 package List::Index;
2
3 use 5.010;
4 use strict;
5 use warnings;
6
7 our $VERSION = '1.00';
8
9 sub new {
10         my ($class, $values) = @_;
11         bless [map { tr/{/./; $_ } sort map { s/[^a-z]/{/g; $_ } @$values], $class;
12 }
13
14 sub ranges {
15         my $self = shift;
16         my $options = shift || {};
17         my $pagesize = $options->{pagesize} || 50;
18         my $context  = $options->{context } // 1 + ($pagesize >> 4);
19         my $length   = $options->{length  } || 4;
20         my $pages    = $options->{pages   } || 1 + int $#$self / $pagesize;
21
22         $pagesize = @$self / $pages;
23         my $offset = 0;
24         my @links;
25         while ($offset < @$self) {
26                 my $link = substr $self->[$offset], 0, $length;
27                 if ($context) {
28                         my $trim = 1;
29                         my $before = $offset > $context ? $self->[$offset - $context] : '';
30                         for my $match (split //, $before) {
31                                 scalar $link =~ /\G\Q$match/g or last;
32                                 $trim++;
33                         }
34                         substr($link, $trim) = '' unless $trim > length $link;
35                 }
36
37                 push @links, [$link];
38                 $offset += $pagesize;
39         }
40
41         for my $i (0 .. $#links - 1) {
42                 my ($link, $lastchar) = $links[$i + 1]->[0] =~ /(.*)(.)/;
43                 $link .= $lastchar eq '.' ? 'z' : chr( ord($lastchar) - 1 )
44                         unless $lastchar eq 'a';
45                 $links[$i]->[1] = $link;
46         }
47         $links[-1]->[1] = '';
48
49         return \@links;
50 }
51
52 1;
53
54 __END__
55
56 =head1 NAME
57
58 List::Index - Paginate alphabetic entries by finding minimal prefixes
59
60 =head1 SYNOPSIS
61
62         use List::Index;
63         my $index = List::Index->new(\@values);
64         my @pages = $index->ranges({pagesize => 50});
65         printf '<a href="?start=%s&amp;end=%s">%1$s</a> ', @$_ for @pages;
66
67 =head1 DESCRIPTION
68
69 TODO
70
71 =head1 SEE ALSO
72
73 L<List::Maker|List::Maker> for complex ranges of numeric lists.
74
75 =head1 AUTHOR
76
77 Mischa POSLAWSKY <perl@shiar.org>
78
79 =head1 LICENSE
80
81 Copyright. All rights reserved.
82