File Coverage

blib/lib/MooseX/FunkyAttributes/Role/Attribute.pm
Criterion Covered Total %
statement 26 26 100.0
branch 2 2 100.0
condition n/a
subroutine 9 9 100.0
pod 1 1 100.0
total 38 38 100.0


line stmt bran cond sub pod time code
1             package MooseX::FunkyAttributes::Role::Attribute;
2              
3 6     6   5349 use 5.008;
  6         20  
  6         265  
4 6     6   37 use strict;
  6         15  
  6         176  
5 6     6   33 use warnings;
  6         10  
  6         393  
6              
7             BEGIN {
8 6     6   16 $MooseX::FunkyAttributes::Role::Attribute::AUTHORITY = 'cpan:TOBYINK';
9 6         266 $MooseX::FunkyAttributes::Role::Attribute::VERSION = '0.003';
10             }
11              
12 6     6   16229 use Moose::Role;
  6         752126  
  6         40  
13              
14 6     6   44096 use aliased 'MooseX::FunkyAttributes::Meta::Accessor';
  6         17  
  6         77  
15 6     6   682 use namespace::autoclean;
  6         14  
  6         28  
16              
17             has custom_get => (
18             is => 'ro',
19             isa => 'CodeRef',
20             required => 1,
21             );
22              
23             has custom_set => (
24             is => 'ro',
25             isa => 'CodeRef',
26             required => 1,
27             );
28              
29             has custom_has => (
30             is => 'ro',
31             isa => 'CodeRef',
32             required => 1,
33             );
34              
35             has custom_clear => (
36             is => 'ro',
37             isa => 'CodeRef',
38             predicate => 'has_custom_clear',
39             );
40              
41             has custom_weaken => (
42             is => 'ro',
43             isa => 'CodeRef',
44             predicate => 'has_custom_weaken',
45             );
46              
47             has custom_init => (
48             is => 'ro',
49             isa => 'CodeRef',
50             predicate => 'has_custom_init',
51             );
52              
53             my @i = qw( set get weaken has clear );
54             for my $i (@i)
55             {
56             my $non_inline = "custom_$i";
57             my $custom = "custom_inline_$i";
58             my $has_custom = "has_$custom";
59             has $custom => (
60             is => 'ro',
61             isa => 'CodeRef',
62             predicate => $has_custom,
63             );
64            
65             my $guts_method =
66             ( $i =~ /^(weaken|clear)$/ )
67             ? "_inline_${i}_value"
68             : "_inline_instance_${i}";
69            
70             around $guts_method => sub
71             {
72             my $next = shift;
73             my $self = shift;
74             my ($instance_var, $param_var) = @_;
75            
76             return $self->$custom->($self, @_) if $self->$has_custom;
77            
78             return sprintf(
79             'do { my $attr = Moose::Util::find_meta(ref(%s))->get_attribute(%s); local $_ = %s; $attr->%s->($attr'.join('',map(',%s',@_)).') }',
80             $instance_var,
81             B::perlstring($self->name),
82             $instance_var,
83             $non_inline,
84             @_,
85             );
86             };
87             }
88              
89             around _inline_weaken_value => sub
90             {
91             my ($orig, $self, @args) = @_;
92             return unless $self->is_weak_ref;
93             $self->$orig(@args);
94             };
95              
96             has has_all_inliners => (
97             is => 'ro',
98             isa => 'Bool',
99             lazy_build => 1,
100             );
101              
102             sub _build_has_all_inliners
103             {
104 11     11   25 my $self = shift;
105 11         35 for (@i) {
106 23         53 my $predicate = "has_custom_inline_$_";
107 23 100       1304 return unless $self->$predicate;
108             }
109 3         142 return 1;
110             }
111              
112             sub accessor_should_be_inlined
113             {
114 17     17 1 8264 shift->has_all_inliners;
115             }
116              
117             after _process_options => sub
118             {
119             my ($class, $name, $options) = @_;
120            
121             if (defined $options->{clearer}
122             and not defined $options->{custom_clear})
123             {
124             confess "can't set clearer without custom_clear";
125             }
126              
127             if ($options->{weak_ref}
128             and not defined $options->{custom_weaken})
129             {
130             confess "can't set weak_ref without custom_weaken";
131             }
132             };
133              
134             override accessor_metaclass => sub { Accessor };
135              
136             override get_raw_value => sub
137             {
138             my ($attr) = @_;
139             local $_ = $_[1];
140             return $attr->custom_get->(@_);
141             };
142              
143             override set_raw_value => sub
144             {
145             my ($attr) = @_;
146             local $_ = $_[1];
147             return $attr->custom_set->(@_);
148             };
149              
150             override has_value => sub
151             {
152             my ($attr) = @_;
153             local $_ = $_[1];
154             return $attr->custom_has->(@_);
155             };
156              
157             override clear_value => sub
158             {
159             my ($attr) = @_;
160             local $_ = $_[1];
161             return $attr->custom_clear->(@_);
162             };
163              
164             override _weaken_value => sub
165             {
166             my ($attr) = @_;
167             local $_ = $_[1];
168             return $attr->custom_weaken->(@_);
169             };
170              
171             override set_initial_value => sub
172             {
173             my ($attr) = @_;
174             local $_ = $_[1];
175             if ($attr->has_custom_init) {
176             return $attr->custom_init->(@_);
177             }
178             return $attr->custom_set->(@_);
179             };
180              
181             1;
182              
183             __END__
184              
185             =head1 NAME
186              
187             MooseX::FunkyAttributes::Role::Attribute - custom get/set/clear/has coderefs
188              
189             =head1 SYNOPSIS
190              
191             package Circle;
192            
193             use Moose;
194             use MooseX::FunkyAttributes;
195            
196             has radius => (
197             is => 'rw',
198             isa => 'Num',
199             predicate => 'has_radius',
200             );
201            
202             has diameter => (
203             traits => [ FunkyAttribute ],
204             is => 'rw',
205             isa => 'Num',
206             custom_get => sub { 2 * $_->radius },
207             custom_set => sub { $_->radius( $_[-1] / 2 ) },
208             custom_has => sub { $_->has_radius },
209             );
210              
211             =head1 DESCRIPTION
212              
213             This is the base trait which the other MooseX::FunkyAttribute traits inherit
214             from. It allows you to provide coderefs to handle the business of storing and
215             retrieving attribute values.
216              
217             So instead of storing your attribute values in the object's blessed hashref,
218             you could calculate them on the fly, or store them in a file or database, or
219             an external hashref, or whatever.
220              
221             =head2 Options
222              
223             If your attribute uses this trait, then you I<must> provide at least the
224             following three coderefs:
225              
226             =over
227              
228             =item C<< custom_set => CODE ($meta, $instance, $value) >>
229              
230             The code which implements setting an attribute value. Note that this code
231             does I<not> need to implement type constraint checks, etc. C<< $meta >> is a
232             L<Moose::Meta::Attribute> object describing the attribute; C<< $instance >>
233             is the object itself.
234              
235             C<< $_ >> is available as an alias for the instance.
236              
237             =item C<< custom_get => CODE ($meta, $instance) >>
238              
239             The code which implements getting an attribute value.
240              
241             It should return the value.
242              
243             =item C<< custom_has => CODE ($meta, $instance) >>
244              
245             The code which implements the predicate functionality for an attribute. That
246             is, it should return true if the attribute has been set, and false if the
247             attribute is unset. (Note that Moose does allow attribute values to be set to
248             undefined, so settedness is not the same as definedness.)
249              
250             =back
251              
252             The following three additional coderefs are optional:
253              
254             =over
255              
256             =item C<< custom_clear => CODE ($meta, $instance) >>
257              
258             The code which clears an attribute value, making it unset.
259              
260             If you do not provide this, then your attribute cannot be cleared once set.
261              
262             =item C<< custom_init => CODE ($meta, $instance, $value) >>
263              
264             Like C<custom_set> but used during object construction.
265              
266             If you do not provide this, then the C<custom_set> coderef will be used in its
267             place.
268              
269             =item C<< custom_weaken => CODE ($meta, $instance) >>
270              
271             The code which weakens an attribute value that is a reference.
272              
273             If you do not provide this, then your attribute cannot be a weak ref.
274              
275             =back
276              
277             Moose attempts to create inlined attribute accessors whenever possible. The
278             following coderefs can be defined which must return strings of Perl code
279             suitable for inlining the accessors. They are each optional, but unless all
280             of them are defined, your attribute will not be inlined.
281              
282             =over
283              
284             =item C<< custom_inline_set => CODE ($meta, $instance_string, $value_string) >>
285              
286             C<< $instance_string >> is a string representing the name of the instance
287             variable, such as C<< "\$self" >>. C<< $value_string >> is a string which
288             evaluates to the value.
289              
290             An example for the C<diameter> example in the SYNOPSIS
291              
292             custom_inline_set => sub {
293             my ($meta, $i, $v) = @_;
294             return sprintf('%s->{radius} = (%s)/2', $i, $v);
295             },
296              
297             =item C<< custom_inline_get => CODE ($meta, $instance_string) >>
298              
299             An example for the C<diameter> example in the SYNOPSIS
300              
301             custom_inline_get => sub {
302             my ($meta, $i) = @_;
303             return sprintf('%s->{radius} * 2', $i);
304             },
305              
306             =item C<< custom_inline_has => CODE ($meta, $instance_string) >>
307              
308             An example for the C<diameter> example in the SYNOPSIS
309              
310             custom_inline_has => sub {
311             my ($meta, $i) = @_;
312             return sprintf('exists %s->{radius}', $i);
313             },
314              
315             =item C<< custom_inline_clear => CODE ($meta, $instance_string) >>
316              
317             An example for the C<diameter> example in the SYNOPSIS
318              
319             custom_inline_has => sub {
320             my ($meta, $i) = @_;
321             return sprintf('delete %s->{radius}', $i);
322             },
323              
324             =item C<< custom_inline_weaken => CODE ($meta, $instance_string) >>
325              
326             An example for the C<diameter> example in the SYNOPSIS
327              
328             custom_inline_has => sub {
329             my ($meta, $i) = @_;
330             return sprintf('Scalar::Util::weaken(%s->{radius})', $i);
331             },
332              
333             (Not that weakening a Num makes any sense...)
334              
335             =back
336              
337             Your attribute metaobject has the following methods (in addition to the
338             standard L<Moose::Meta::Attribute> stuff):
339              
340             =over
341              
342             =item C<custom_get>
343              
344             =item C<custom_set>
345              
346             =item C<custom_has>
347              
348             =item C<custom_clear>, C<has_custom_clear>
349              
350             =item C<custom_weaken>, C<has_custom_weaken>
351              
352             =item C<custom_init>, C<has_custom_init>
353              
354             =item C<custom_inline_get>, C<has_custom_inline_get>
355              
356             =item C<custom_inline_set>, C<has_custom_inline_set>
357              
358             =item C<custom_inline_has>, C<has_custom_inline_has>
359              
360             =item C<custom_inline_clear>, C<has_custom_inline_clear>
361              
362             =item C<custom_inline_weaken>, C<has_custom_inline_weaken>
363              
364             =item C<accessor_should_be_inlined>
365              
366             =item C<has_all_inliners>
367              
368             =back
369              
370             =head1 BUGS
371              
372             Please report any bugs to
373             L<http://rt.cpan.org/Dist/Display.html?Queue=MooseX-FunkyAttributes>.
374              
375             =head1 SEE ALSO
376              
377             L<MooseX::FunkyAttributes>.
378              
379             =head1 AUTHOR
380              
381             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
382              
383             =head1 COPYRIGHT AND LICENCE
384              
385             This software is copyright (c) 2012-2014 by Toby Inkster.
386              
387             This is free software; you can redistribute it and/or modify it under
388             the same terms as the Perl 5 programming language system itself.
389              
390             =head1 DISCLAIMER OF WARRANTIES
391              
392             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
393             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
394             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
395