File Coverage

blib/lib/Mixin/ExtraFields/Driver/HashGuts.pm
Criterion Covered Total %
statement 45 45 100.0
branch 6 6 100.0
condition 7 11 63.6
subroutine 16 16 100.0
pod 13 13 100.0
total 87 91 95.6


line stmt bran cond sub pod time code
1 3     3   18 use strict;
  3         6  
  3         108  
2 3     3   16 use warnings;
  3         6  
  3         161  
3              
4             package Mixin::ExtraFields::Driver::HashGuts;
5             {
6             $Mixin::ExtraFields::Driver::HashGuts::VERSION = '0.140002';
7             }
8 3     3   2657 use parent qw(Mixin::ExtraFields::Driver);
  3         902  
  3         38  
9             # ABSTRACT: store extras in a hashy object's guts
10              
11              
12             sub hash_key {
13 47     47 1 49 my ($self) = @_;
14 47         175 return $self->{hash_key};
15             }
16              
17              
18             my $i = 0;
19             sub default_hash_key {
20 2     2 1 4 my ($self) = @_;
21 2         28 return "$self" . '@' . $i++;
22             }
23              
24              
25 42     42 1 151 sub storage { $_[0]->{storage} }
26              
27              
28             sub storage_for {
29 42     42 1 49 my ($self, $object, $id) = @_;
30              
31 42   100     68 my $store = $self->storage->{ $id } ||= {};
32              
33 42 100 66     79 unless ($object->{ $self->hash_key }||0 == $store) {
34 5   33     13 $object->{ $self->hash_key } ||= $store;
35             }
36              
37 42         189 return $store
38             }
39              
40             sub from_args {
41 5     5 1 9 my ($class, $arg) = @_;
42              
43 5         20 my $self = bless { storage => {} } => $class;
44              
45 5   66     56 $self->{hash_key} = $arg->{hash_key} || $self->default_hash_key;
46              
47 5         21 return $self;
48             }
49              
50             sub exists_extra {
51 20     20 1 31 my ($self, $object, $id, $name) = @_;
52              
53 20         35 return exists $self->storage_for($object, $id)->{$name};
54             }
55              
56             sub get_extra {
57 8     8 1 13 my ($self, $object, $id, $name) = @_;
58              
59             # avoid autovivifying entries on get.
60 8 100       18 return unless $self->exists_extra($object, $id, $name);
61 4         11 return $self->storage_for($object, $id)->{$name};
62             }
63              
64             sub get_detailed_extra {
65 3     3 1 6 my ($self, $object, $id, $name) = @_;
66              
67             # avoid autovivifying entries on get.
68 3 100       8 return unless $self->exists_extra($object, $id, $name);
69 1         4 return { value => $self->storage_for($object, $id)->{$name} };
70             }
71              
72             sub get_all_detailed_extra {
73 7     7 1 10 my ($self, $object, $id) = @_;
74              
75 7         17 my $stash = $self->storage_for($object, $id);
76 7         25 my @all_detailed = map { $_ => { value => $stash->{$_} } } keys %$stash;
  4         39  
77             }
78              
79             sub get_all_extra {
80 4     4 1 8 my ($self, $object, $id) = @_;
81              
82 4         5 return %{ $self->storage_for($object, $id) };
  4         14  
83             }
84              
85             sub set_extra {
86 4     4 1 9 my ($self, $object, $id, $name, $value) = @_;
87              
88 4         11 $self->storage_for($object, $id)->{$name} = $value;
89             }
90              
91             sub delete_extra {
92 1     1 1 4 my ($self, $object, $id, $name) = @_;
93              
94 1         3 delete $self->storage_for($object, $id)->{$name};
95             }
96              
97             sub delete_all_extra {
98 1     1 1 3 my ($self, $object, $id) = @_;
99 1         3 %{ $self->storage_for($object, $id) } = ();
  1         4  
100             }
101              
102             1;
103              
104             __END__
105              
106             =pod
107              
108             =head1 NAME
109              
110             Mixin::ExtraFields::Driver::HashGuts - store extras in a hashy object's guts
111              
112             =head1 VERSION
113              
114             version 0.140002
115              
116             =head1 SYNOPSIS
117              
118             package Your::HashBased::Class;
119              
120             use Mixin::ExtraFields -fields => { driver => 'HashGuts' };
121              
122             =head1 DESCRIPTION
123              
124             This driver class implements an extremely simple storage mechanism: extras are
125             stored on the object on which the mixed-in methods are called. By default,
126             they are stored under the key returned by the C<L</default_has_key>> method,
127             but this can be changed by providing a C<hash_key> argument to the driver
128             configuration, like so:
129              
130             use Mixin::ExtraFields -fields => {
131             driver => { class => 'HashGuts', hash_key => "\0Something\0Wicked\0" }
132             };
133              
134             =head1 METHODS
135              
136             In addition to the methods required by Mixin::ExtraFields::Driver, the
137             following methods are provided:
138              
139             =head2 hash_key
140              
141             my $key = $driver->hash_key;
142              
143             This method returns the key where the driver will store its extras.
144              
145             =head2 default_hash_key
146              
147             If no C<hash_key> argument is given for the driver, this method is called
148             during driver initialization. It will return a unique string to be used as the
149             hash key.
150              
151             =head2 storage
152              
153             This method returns the hashref of storage used for extras. Individual objects
154             get weak references to their id within this hashref.
155              
156             =head2 storage_for
157              
158             my $stash = $driver->storage_for($object, $id);
159              
160             This method returns the hashref to use to store extras for the given object and
161             id. This hashref is stored on both the hash-based object (in its C<hash_key>
162             entry) and on the driver (in the entry for C<$id> in its C<storage> hash).
163              
164             All objects with the same id should end up with the same hash in their
165             C<hash_key> field. B<None> of these references are weakened, which means two
166             things: first, even if all objects with a given id go out of scope, future
167             objects with that id will retain the original extras; secondly, memory used to
168             store extras is never reclaimed. If this is a problem, use a more
169             sophisticated driver.
170              
171             =head1 AUTHOR
172              
173             Ricardo Signes <rjbs@cpan.org>
174              
175             =head1 COPYRIGHT AND LICENSE
176              
177             This software is copyright (c) 2013 by Ricardo Signes.
178              
179             This is free software; you can redistribute it and/or modify it under
180             the same terms as the Perl 5 programming language system itself.
181              
182             =cut