File Coverage

blib/lib/MooseX/Attribute/LazyInflator/Meta/Role/Attribute.pm
Criterion Covered Total %
statement 20 27 74.0
branch 4 14 28.5
condition 4 12 33.3
subroutine 5 6 83.3
pod 1 1 100.0
total 34 60 56.6


line stmt bran cond sub pod time code
1             #
2             # This file is part of MooseX-Attribute-Deflator
3             #
4             # This software is Copyright (c) 2012 by Moritz Onken.
5             #
6             # This is free software, licensed under:
7             #
8             # The (three-clause) BSD License
9             #
10             package MooseX::Attribute::LazyInflator::Meta::Role::Attribute;
11             {
12             $MooseX::Attribute::LazyInflator::Meta::Role::Attribute::VERSION = '2.1.11'; # TRIAL
13             }
14              
15             # ABSTRACT: Lazy inflate attributes
16 4     4   14 use strict;
  4         5  
  4         95  
17 4     4   14 use warnings;
  4         4  
  4         72  
18 4     4   12 use Moose::Role;
  4         4  
  4         31  
19 4     4   13653 use Eval::Closure;
  4         5  
  4         4188  
20              
21             with 'MooseX::Attribute::Deflator::Meta::Role::Attribute';
22              
23             override verify_against_type_constraint => sub {
24             my ( $self, $value, undef, $instance ) = @_;
25             return $value if ( !$self->is_inflated( $instance, undef, $value ) );
26             return super();
27             };
28              
29             before get_value => sub {
30             my ( $self, $instance ) = @_;
31             return
32             if ( !$self->has_value($instance) || $self->is_inflated($instance) );
33             my $value = $self->inflate( $instance, $self->get_raw_value($instance) );
34             $value = $self->type_constraint->coerce($value)
35             if ( $self->should_coerce && $self->type_constraint->has_coercion );
36             $self->verify_against_type_constraint( $value, instance => $instance );
37             $self->set_raw_value( $instance, $value );
38             };
39              
40             # this is just for reference, this method is replaced with an inlined version
41             sub is_inflated {
42 0     0 1 0 my ( $self, $instance, $value, $from_constructor ) = @_;
43 0 0       0 return $instance->_inflated_attributes->{ $self->name } = $value
44             if ( defined $value );
45 0 0       0 if ( $instance->_inflated_attributes->{ $self->name } ) {
46 0         0 return 1;
47             }
48             else {
49 0 0       0 my $value
50             = defined $from_constructor
51             ? $from_constructor
52             : $self->get_raw_value($instance);
53 0 0 0     0 $value = $self->type_constraint->coerce($value)
54             if ( $self->should_coerce
55             && $self->type_constraint->has_coercion );
56             return
57             $self->has_type_constraint
58             && $self->type_constraint->check($value)
59 0   0     0 && ++$instance->_inflated_attributes->{ $self->name };
60             }
61             }
62              
63             after install_accessors => sub {
64             my $self = shift;
65             my @code
66             = $self->_inline_instance_is_inflated( '$_[1]', '$type_constraint',
67             '$type_coercion', '$value', );
68             $self->meta->add_method(
69             'is_inflated' => eval_closure(
70             environment => $self->_eval_environment,
71             source => join( "\n",
72             'sub {',
73             'return $_[1]->{_inflated_attributes}->{"'
74             . quotemeta( $self->name )
75             . '"} = $_[2] if(defined $_[2]);',
76             'my $value = defined $_[3] ? $_[3] : '
77             . $self->_inline_instance_get('$_[1]') . ';',
78             @code,
79             '}' ),
80             )
81             );
82             } if ( $Moose::VERSION >= 1.9 );
83              
84             if ( Moose->VERSION < 1.9900 ) {
85             require MooseX::Attribute::LazyInflator::Meta::Role::Method::Accessor;
86             override accessor_metaclass => sub {
87             'MooseX::Attribute::LazyInflator::Meta::Role::Method::Accessor';
88             };
89             }
90              
91             sub _inline_instance_is_inflated {
92             my ( $self, $instance, $tc, $tc_obj, $value ) = @_;
93             my @code
94             = ( $instance
95             . '->{_inflated_attributes}->{"'
96             . quotemeta( $self->name )
97             . '"}' );
98             return @code if ( !$self->has_type_constraint ); # TODO return 1 ?
99             $value ||= $self->_inline_instance_get($instance);
100             my $coerce
101             = $self->should_coerce && $self->type_constraint->has_coercion
102             ? $tc_obj . '->coerce(' . $value . ')'
103             : $value;
104             push @code,
105             ( ' || ('
106             . $tc . '->('
107             . $coerce
108             . ') && ++'
109             . $instance
110             . '->{_inflated_attributes}->{"'
111             . quotemeta( $self->name )
112             . '"})' );
113             return @code;
114             }
115              
116             if ( Moose->VERSION >= 2.0100 ) {
117             override _inline_get_value => sub {
118             my ( $self, $instance, $tc, $coercion, $message ) = @_;
119             $tc ||= '$type_constraint';
120             $coercion ||= '$type_coercion';
121             $message ||= '$type_message';
122             my $slot_exists = $self->_inline_instance_has($instance);
123             my @code = (
124             "if($slot_exists && !(",
125             $self->_inline_instance_is_inflated( $instance, $tc, $coercion ),
126             ")) {",
127             'my $inflated = '
128             . "\$attr->inflate($instance, "
129             . $self->_inline_instance_get($instance) . ");",
130             $self->has_type_constraint
131             ? ( $self->_inline_check_coercion(
132             '$inflated', $tc, $coercion, 1
133             ),
134             $self->_inline_check_constraint(
135             '$inflated', $tc, $message, 1
136             )
137             )
138             : (),
139             $self->_inline_init_slot( $instance, '$inflated' ),
140             "}"
141             );
142             push @code, super();
143             return @code;
144             };
145              
146             __PACKAGE__->meta->add_method(
147             _inline_instance_is_inflated => sub {
148 38     38   90 my ( $self, $instance, $tc, $coercion, $value ) = @_;
149             my @code
150 38         278 = ( $instance
151             . '->{_inflated_attributes}->{"'
152             . quotemeta( $self->name )
153             . '"}' );
154 38 50       1394 return @code if ( !$self->has_type_constraint );
155 38   66     267 $value ||= $self->_inline_instance_get($instance);
156 38 100 66     1404 my $coerce
157             = $self->should_coerce && $self->type_constraint->has_coercion
158             ? $coercion . '->(' . $value . ')'
159             : $value;
160 38 50       1361 my $check
161             = $self->type_constraint->can_be_inlined
162             ? $self->type_constraint->_inline_check($coerce)
163             : $tc . '->(' . $coerce . ')';
164 38         33490 push @code,
165             ( ' || ('
166             . $check
167             . ' && ++'
168             . $instance
169             . '->{_inflated_attributes}->{"'
170             . quotemeta( $self->name )
171             . '"})' );
172 38         165 return @code;
173             }
174             );
175              
176             override _inline_tc_code => sub {
177             my $self = shift;
178             my ( $value, $tc, $coercion, $message, $is_lazy ) = @_;
179             return (
180             $self->_inline_check_coercion(
181             $value, $tc, $coercion, $is_lazy,
182             ),
183              
184             # $self->_inline_check_constraint(
185             # $value, $tc, $message, $is_lazy,
186             # ),
187             );
188             };
189              
190             override _eval_environment => sub {
191             my $self = shift;
192             return { %{ super() }, '$attr' => \$self, };
193             };
194             }
195             else {
196             override _inline_get_value => sub {
197             my ( $self, $instance, $tc, $tc_obj ) = @_;
198             $tc ||= '$type_constraint';
199             $tc_obj ||= '$type_constraint_obj';
200             my $slot_exists = $self->_inline_instance_has($instance);
201             my @code = (
202             "if($slot_exists && !(",
203             $self->_inline_instance_is_inflated( $instance, $tc, $tc_obj ),
204             ")) {",
205             'my $inflated = '
206             . "\$attr->inflate($instance, "
207             . $self->_inline_instance_get($instance) . ");",
208             $self->has_type_constraint
209             ? ( $self->_inline_check_coercion( '$inflated', $tc, $tc_obj, 1 ),
210             $self->_inline_check_constraint(
211             '$inflated', $tc, $tc_obj, 1
212             )
213             )
214             : (),
215             $self->_inline_init_slot( $instance, '$inflated' ),
216             "}"
217             );
218             push @code, super();
219             return @code;
220             }
221             if Moose->VERSION >= 1.9900;
222              
223             __PACKAGE__->meta->add_method(
224             _inline_instance_is_inflated => sub {
225             my ( $self, $instance, $tc, $tc_obj ) = @_;
226             my @code
227             = ( $instance
228             . '->{_inflated_attributes}->{"'
229             . quotemeta( $self->name )
230             . '"}' );
231             return @code if ( !$self->has_type_constraint );
232             my $value = $self->_inline_instance_get($instance);
233             my $coerce
234             = $self->should_coerce && $self->type_constraint->has_coercion
235             ? $tc_obj . '->coerce(' . $value . ')'
236             : $value;
237             push @code,
238             ( ' || ('
239             . $tc . '->('
240             . $coerce
241             . ') && ++'
242             . $instance
243             . '->{_inflated_attributes}->{"'
244             . quotemeta( $self->name )
245             . '"})' );
246             return @code;
247             }
248             );
249              
250             override _inline_tc_code => sub {
251             my $self = shift;
252             return (
253             $self->_inline_check_coercion(@_),
254              
255             # $self->_inline_check_constraint(@_),
256             );
257             }
258             if Moose->VERSION >= 1.9900;
259             }
260              
261             1;
262              
263              
264              
265             =pod
266              
267             =head1 NAME
268              
269             MooseX::Attribute::LazyInflator::Meta::Role::Attribute - Lazy inflate attributes
270              
271             =head1 VERSION
272              
273             version 2.1.11
274              
275             =head1 SYNOPSIS
276              
277             package Test;
278              
279             use Moose;
280             use MooseX::Attribute::LazyInflator;
281             # Load default deflators and inflators
282             use MooseX::Attribute::Deflator::Moose;
283              
284             has hash => ( is => 'rw',
285             isa => 'HashRef',
286             traits => ['LazyInflator'] );
287              
288             package main;
289            
290             my $obj = Test->new( hash => '{"foo":"bar"}' );
291             # Attribute 'hash' is being inflated to a HashRef on access
292             $obj->hash;
293              
294             =head1 ROLES
295              
296             This role consumes L<MooseX::Attribute::Deflator::Meta::Role::Attribute>.
297              
298             =head1 METHODS
299              
300             =over 8
301              
302             =item B<is_inflated( $intance )>
303              
304             Returns a true value if the value of the attribute passes the type contraint
305             or has been inflated.
306              
307             =item before B<get_value>
308              
309             The attribute's value is being inflated and set if it has a value and hasn't been inflated yet.
310              
311             =item override B<verify_against_type_constraint>
312              
313             Will return true if the attribute hasn't been inflated yet.
314              
315             =back
316              
317             =head1 FUNCTIONS
318              
319             =over 8
320              
321             =item B<accessor_metaclass>
322              
323             The accessor metaclass is set to L<MooseX::Attribute::LazyInflator::Meta::Role::Method::Accessor>.
324              
325             =back
326              
327             =head1 AUTHOR
328              
329             Moritz Onken
330              
331             =head1 COPYRIGHT AND LICENSE
332              
333             This software is Copyright (c) 2012 by Moritz Onken.
334              
335             This is free software, licensed under:
336              
337             The (three-clause) BSD License
338              
339             =cut
340              
341              
342             __END__
343