File Coverage

blib/lib/Tie/Moose.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1 6     6   184274 use 5.010;
  6         20  
  6         231  
2 6     6   31 use strict;
  6         11  
  6         173  
3 6     6   28 use warnings;
  6         21  
  6         376  
4              
5             package Tie::Moose;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.001';
9              
10 6     6   31 use Carp 'croak';
  6         9  
  6         324  
11 6     6   10624 use Moose;
  0            
  0            
12              
13             with 'MooseX::Traits';
14              
15             has object => (
16             is => 'ro',
17             isa => 'Object',
18             required => 1,
19             );
20              
21             has attributes => (
22             is => 'ro',
23             isa => 'ArrayRef[ArrayRef[Str|Undef]]',
24             lazy => 1,
25             builder => '_build_attributes',
26             );
27              
28             has attributes_hash => (
29             is => 'ro',
30             isa => 'HashRef[ArrayRef[Str|Undef]]',
31             lazy => 1,
32             builder => '_build_attributes_hash',
33             );
34              
35             has "+_trait_namespace" => (
36             default => __PACKAGE__,
37             );
38              
39             sub _build_attributes
40             {
41             return [
42             map [
43             $_->name, # 0
44             $_->reader || $_->accessor, # 1
45             $_->writer || $_->accessor, # 2
46             $_->predicate, # 3
47             $_->clearer, # 4
48             ], Class::MOP::class_of(shift->object)->get_all_attributes
49             ]
50             }
51              
52             sub _build_attributes_hash
53             {
54             return +{ map {; $_->[0], $_ } @{ shift->attributes } };
55             }
56              
57             sub fallback
58             {
59             my $self = shift;
60             my ($operation, $key) = @_;
61             croak "No attribute '$key' in tied object";
62             }
63              
64             sub TIEHASH
65             {
66             my $class = shift;
67             my ($object, %opts) = @_;
68             $class->new(%opts, object => $object);
69             }
70              
71             sub FETCH
72             {
73             my $self = shift;
74             my ($key) = @_;
75            
76             $self->attributes_hash->{$key}
77             or return $self->fallback(FETCH => $key);
78            
79             my $accessor = $self->attributes_hash->{$key}[1]
80             or croak "No reader for attribute '$key' in tied object";
81             return $self->object->$accessor;
82             }
83              
84             sub STORE
85             {
86             my $self = shift;
87             my ($key, $value) = @_;
88            
89             $self->attributes_hash->{$key}
90             or return $self->fallback(STORE => $key, $value);
91            
92             my $accessor = $self->attributes_hash->{$key}[2]
93             or croak "No writer for attribute '$key' in tied object";
94             return $self->object->$accessor($value);
95             }
96              
97             sub EXISTS
98             {
99             my $self = shift;
100             my ($key) = @_;
101            
102             $self->attributes_hash->{$key}
103             or return $self->fallback(EXISTS => $key);
104            
105             my $accessor = $self->attributes_hash->{$key}[3];
106             $accessor and return $self->object->$accessor;
107            
108             return $self->object->meta->find_attribute_by_name($key)->has_value($self->object);
109             }
110              
111             sub DELETE
112             {
113             my $self = shift;
114             my ($key) = @_;
115            
116             $self->attributes_hash->{$key}
117             or return $self->fallback(DELETE => $key);
118            
119             my $accessor = $self->attributes_hash->{$key}[4]
120             or croak "No clearer for attribute '$key' in tied object";
121             return $self->object->$accessor;
122             }
123              
124             sub CLEAR
125             {
126             my $self = shift;
127            
128             for my $attr (@{$self->attributes})
129             {
130             my $name = $attr->[0];
131             $self->EXISTS($name) and $self->DELETE($name);
132             }
133             }
134              
135             sub FIRSTKEY
136             {
137             my $self = shift;
138             for my $attr (@{$self->attributes})
139             {
140             next unless $self->EXISTS($attr->[0]);
141             return $attr->[0];
142             }
143             return;
144             }
145              
146             sub NEXTKEY
147             {
148             my $self = shift;
149             my ($lastkey) = @_;
150             my $should_return;
151             for my $attr (@{$self->attributes})
152             {
153             if ($attr->[0] eq $lastkey)
154             { $should_return++; }
155             elsif (not $self->EXISTS($attr->[0]))
156             { next; }
157             elsif ($should_return)
158             { return $attr->[0]; }
159             }
160             return;
161             }
162              
163             sub SCALAR
164             {
165             shift->object;
166             }
167              
168             __PACKAGE__->meta->make_immutable;
169             no Moose;
170              
171             1;
172              
173             __END__
174              
175             =head1 NAME
176              
177             Tie::Moose - tie a hash to a Moose object (yeah, like Tie::MooseObject)
178              
179             =head1 SYNOPSIS
180              
181             use v5.14;
182            
183             package Person {
184             use Moose;
185             has name => (
186             is => "rw",
187             isa => "Str",
188             );
189             has age => (
190             is => "rw",
191             isa => "Num",
192             reader => "get_age",
193             writer => "set_age",
194             );
195             }
196            
197             my $bob = Person->new(name => "Robert");
198            
199             tie my %bob, "Tie::Moose", $bob;
200            
201             $bob{age} = 32; # calls the "set_age" method
202             $bob{age} = "x"; # would croak
203             $bob{xyz} = "x"; # would croak
204              
205             =head1 DESCRIPTION
206              
207             This module is much like L<Tie::MooseObject>. It ties a hash to an instance
208             of a L<Moose>-based class, allowing you to access attributes as hash keys. It
209             uses the accessors provided by Moose, and thus honours read-only attributes,
210             type constraints and coercions, triggers, etc.
211              
212             There are a few key differences with L<Tie::MooseObject>:
213              
214             =over
215              
216             =item *
217              
218             It handles differently named getters/setters more to my liking. Given the
219             example in the SYNOPSIS, with Tie::MooseObject you need to write:
220              
221             $bob{set_age} = 32;
222             say $bob{get_age};
223              
224             Whereas with Tie::Moose, you just use the C<age> hash key for both fetching
225             from and storing to the hash.
226              
227             =item *
228              
229             Implements C<DELETE> from the L<Tie::Hash> interface. Tie::MooseObject does
230             not allow keys to be deleted from its hashes.
231              
232             (C<DELETE> only works on Moose attributes that have a "clearer" method.)
233              
234             =item *
235              
236             Supplied with various traits to influence the behaviour of the tied hash.
237              
238             tie my %bob, "Tie::Moose"->with_traits("ReadOnly"), $bob;
239              
240             (Note that by design, many of the traits supplied with Tie::Moose are
241             mutually exclusive.)
242              
243             =back
244              
245             =head1 BUGS
246              
247             Please report any bugs to
248             L<http://rt.cpan.org/Dist/Display.html?Queue=Tie-Moose>.
249              
250             =head1 SEE ALSO
251              
252             L<Tie::MooseObject>.
253              
254             Traits for Tie::Moose hashes:
255             L<Tie::Moose::ReadOnly>,
256             L<Tie::Moose::Forgiving>,
257             L<Tie::Moose::FallbackHash>,
258             L<Tie::Moose::FallbackSlot>.
259              
260             =head1 AUTHOR
261              
262             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
263              
264             =head1 COPYRIGHT AND LICENCE
265              
266             This software is copyright (c) 2013 by Toby Inkster.
267              
268             This is free software; you can redistribute it and/or modify it under
269             the same terms as the Perl 5 programming language system itself.
270              
271             =head1 DISCLAIMER OF WARRANTIES
272              
273             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
274             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
275             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
276