File Coverage

blib/lib/List/MRU.pm
Criterion Covered Total %
statement 73 73 100.0
branch 32 38 84.2
condition 25 32 78.1
subroutine 15 15 100.0
pod 0 8 0.0
total 145 166 87.3


line stmt bran cond sub pod time code
1             package List::MRU;
2              
3 4     4   132282 use 5.006;
  4         19  
  4         291  
4 4     4   23 use strict;
  4         10  
  4         141  
5 4     4   20 use warnings;
  4         17  
  4         139  
6 4     4   20 use Carp;
  4         8  
  4         4521  
7              
8             our $VERSION = '0.04';
9              
10             # -------------------------------------------------------------------------
11             # Constructor
12             sub new
13             {
14 11     11 0 3111 my $class = shift;
15 11         60 my %arg = @_;
16 11 100       370 croak "required argument 'max' missing'" unless defined $arg{max};
17 10 100       719 croak "'max' argument not an integer'" unless $arg{max} =~ m/^\d+$/;
18 7 100 100     533 croak "'eq' argument not an subroutine'"
19             if $arg{eq} && ref $arg{eq} ne 'CODE';
20 5         82 bless {
21             max => $arg{max},
22             'eq' => $arg{eq},
23             uuid => $arg{uuid},
24             list => [],
25             ulist => [],
26             current => 0,
27             }, $class;
28             }
29              
30             # -------------------------------------------------------------------------
31             # Private methods
32              
33             sub _truncate
34             {
35 11     11   20 my $self = shift;
36 11         16 pop @{$self->{list}} while scalar @{$self->{list}} > $self->max;
  14         42  
  3         11  
37 11 100       28 if ($self->uuid) {
38 4         5 pop @{$self->{ulist}} while scalar @{$self->{ulist}} > $self->max;
  5         12  
  1         3  
39             }
40             }
41              
42 2     2   6 sub _reset { shift->{current} = 0; }
43              
44             # -------------------------------------------------------------------------
45             # Public methods
46              
47             # Add $item, moving to head of list if already exists
48             # (returns $self for method chaining)
49             sub add
50             {
51 20     20 0 39 my $self = shift;
52 20         38 my ($item, $uuid) = @_;
53 20 100       188 croak "no item given to add" unless defined $item;
54 19 50 66     47 croak "no uuid given to add" if $self->uuid && ! defined $uuid;
55 19 100       58 if ($self->delete(item => $item, uuid => $uuid)) {
56 8         40 unshift @{$self->{list}}, $item;
  8         24  
57 8 100       54 unshift @{$self->{ulist}}, $uuid if $self->uuid;
  4         11  
58             }
59             else {
60 11         25 unshift @{$self->{list}}, $item;
  11         31  
61 11 100       64 unshift @{$self->{ulist}}, $uuid if $self->uuid;
  4         8  
62 11         77 $self->_truncate;
63             }
64 19         76 $self
65             }
66              
67             # Delete (first) matching $item (by self or by uuid), returning it if found.
68             sub delete
69             {
70 23     23 0 474 my $self = shift;
71 23         40 my ($item, $uuid) = @_;
72             # Check for named arguments style call
73 23 100 100     130 if ($item && ($item eq 'item' || $item eq 'uuid')) {
      66        
74 21         116 my %arg = @_;
75 21         270 $arg{$item} = $uuid;
76 21         37 $item = $arg{item};
77 21         46 $uuid = $arg{uuid};
78             }
79 23 100 100     345 croak "no item given to delete" unless defined $item or defined $uuid;
80 22   100 26   254 my $eq = $self->{eq} || sub { $_[0] eq $_[1] };
  26         185  
81 22         34 for my $i (0 .. $#{$self->{list}}) {
  22         98  
82 34 100 66     98 if (($self->uuid && $uuid && $self->{ulist}->[$i] eq $uuid) ||
      100        
      66        
      66        
83             ($item && $eq->($item, $self->{list}->[$i]))) {
84 11         20 my $deleted = splice @{$self->{list}}, $i, 1;
  11         115  
85 11 100       27 my $udeleted = splice @{$self->{ulist}}, $i, 1 if $self->uuid;
  5         12  
86 11 50 33     92 return wantarray && $self->uuid ? ($deleted, $udeleted) : $deleted;
87             }
88             }
89             }
90              
91             # Iterator
92             sub each {
93 7     7 0 456 my $self = shift;
94 7 100       14 if ($self->{current} <= $#{$self->{list}}) {
  7         23  
95 5         10 my $current = $self->{current}++;
96             return wantarray ?
97 5 50       19 ($self->{list}->[$current], $self->uuid ? $self->{ulist}->[$current] : undef) :
    50          
98             $self->{list}->[$current];
99             }
100             else {
101             # Reset current
102 2         7 $self->_reset;
103 2 50       7 return wantarray ? () : undef;
104             }
105             }
106              
107             # Accessors
108 15 50   15 0 51 sub list { wantarray ? @{shift->{list}} : shift->{list} }
  15         124  
109 21     21 0 71 sub max { shift->{max} }
110 25     25 0 50 sub count { scalar @{shift->{list}} }
  25         741  
111 100     100 0 538 sub uuid { shift->{uuid} }
112              
113             1;
114              
115             __END__