File Coverage

blib/lib/MooseX/Attribute/Deflator/Meta/Role/Attribute.pm
Criterion Covered Total %
statement 61 75 81.3
branch 19 34 55.8
condition 2 6 33.3
subroutine 11 15 73.3
pod 4 4 100.0
total 97 134 72.3


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::Deflator::Meta::Role::Attribute;
11             {
12             $MooseX::Attribute::Deflator::Meta::Role::Attribute::VERSION = '2.1.11'; # TRIAL
13             }
14              
15             # ABSTRACT: Attribute meta role to support deflation
16 7     7   42804 use Moose::Role;
  7         9  
  7         43  
17 7     7   23987 use Try::Tiny;
  7         13  
  7         369  
18 7     7   30 use Eval::Closure;
  7         8  
  7         223  
19 7     7   27 use MooseX::Attribute::Deflator;
  7         8  
  7         71  
20             my $REGISTRY = MooseX::Attribute::Deflator->get_registry;
21 7     7   3560 no MooseX::Attribute::Deflator;
  7         11  
  7         31  
22              
23             has is_deflator_inlined => ( is => 'rw', isa => 'Bool', default => 0 );
24             has is_inflator_inlined => ( is => 'rw', isa => 'Bool', default => 0 );
25              
26             sub _inline_deflator {
27 35     35   245462 my $self = shift;
28 35         225 my $role = Moose::Meta::Role->create_anon_role;
29 35         28223 foreach my $type (qw(deflator inflator)) {
30 70         155 my $find = "find_$type";
31 70 100       224 my $method = $type eq 'deflator' ? 'deflate' : 'inflate';
32 70         2067 my $tc = $self->type_constraint;
33 70         420 my $slot_access = $self->_inline_instance_get('$_[1]');
34 70         1250 my $has_value = $self->_inline_instance_has('$_[1]');
35 70         1016 my @check_lazy = $self->_inline_check_lazy(
36             '$_[1]', '$type_constraint',
37             '$type_coercion', '$type_message',
38             );
39             my @deflator = $tc
40 70 100       12208 ? do {
41 68         606 ( $tc, undef, my $inline ) = $REGISTRY->$find($tc);
42 68 100       150 next unless $inline;
43 65         69 my $find_sub;
44             $find_sub = sub {
45 100     100   9703 my $type_constraint = shift;
46 100         244 my @tc = $REGISTRY->$find($type_constraint);
47 100 100       191 return join( "\n",
48             'my ($tc, $via) = $registry->find_'
49             . $type
50             . '(Moose::Util::TypeConstraints::find_type_constraint("'
51             . quotemeta($type_constraint) . '"));',
52             'my ($attr, $obj, @rest) = @_;',
53             '$via->($attr, $tc, sub { $attr->deflate($obj, @rest) });'
54             ) unless ( $tc[2] );
55 98         277 return $tc[2]->( $self, $tc[0], $find_sub );
56 65         345 };
57 65         282 $inline->( $self, $tc, $find_sub );
58             }
59             : '$value';
60 67         228 my @code = ('sub {');
61 67 100       136 if ( $type eq 'deflator' ) {
62 33         170 push( @code,
63             'my $value = $_[2];',
64             'unless(defined $value) {',
65             @check_lazy,
66             "return undef unless($has_value);",
67             '$value = ' . $slot_access . ';',
68             '}',
69             );
70             }
71             else {
72 34         64 push( @code, 'my $value = $_[2];' );
73             }
74             $role->add_method(
75             $method => eval_closure(
76             environment => {
77 67         100 %{ $self->_eval_environment },
  67         192  
78             '$registry' => \$REGISTRY
79             },
80             source => join( "\n", @code, @deflator, '}' )
81             )
82             );
83 67 100       129052 $type eq 'deflator'
84             ? $self->is_deflator_inlined(1)
85             : $self->is_inflator_inlined(1);
86             }
87 35         185 Moose::Util::apply_all_roles( $self, $role );
88             }
89              
90             sub deflate {
91 2     2 1 11804 my ( $self, $obj, $value, $constraint, @rest ) = @_;
92 2 50       15 $value = $self->get_value($obj) unless(defined $value);
93 2 50       243 return undef unless ( defined $value );
94 2   33     66 $constraint ||= $self->type_constraint;
95 2 50       21 return $value unless ($constraint);
96 2 50       19 return $value
97             unless ( ( $constraint, my $via )
98             = $REGISTRY->find_deflator($constraint) );
99 2         3 my $return;
100             try {
101             $return = $via->(
102 0         0 $self, $constraint, sub { $self->deflate( $obj, @_ ) },
103             $obj, @rest
104 2     2   135 ) for ($value);
105             }
106             catch {
107 0     0   0 die
108 0         0 qq{Failed to deflate value "$value" (${\($constraint->name)}): $_};
109 2         27 };
110 2         67 return $return;
111             }
112              
113             sub inflate {
114 1     1 1 971 my ( $self, $obj, $value, $constraint, @rest ) = @_;
115 1 50       4 return undef unless ( defined $value );
116 1   33     47 $constraint ||= $self->type_constraint;
117 1 50       9 return $value unless ($constraint);
118 1 50       8 return $value
119             unless ( ( $constraint, my $via )
120             = $REGISTRY->find_inflator($constraint) );
121 1         2 my $return;
122             try {
123             $return = $via->(
124 0         0 $self, $constraint, sub { $self->inflate( $obj, @_ ) },
125             $obj, @rest
126 1     1   39 ) for ($value);
127             }
128             catch {
129 0     0   0 die
130 0         0 qq{Failed to inflate value "$value" (${\($constraint->name)}): $_};
131 1         9 };
132 1         172 return $return;
133             }
134              
135             sub has_deflator {
136 0     0 1   my $self = shift;
137 0 0         return unless ( $self->has_type_constraint );
138 0           my @tc = $REGISTRY->find_deflator( $self->type_constraint, 'norecurse' );
139 0 0         return @tc ? 1 : 0;
140             }
141              
142             sub has_inflator {
143 0     0 1   my $self = shift;
144 0 0         return unless ( $self->has_type_constraint );
145 0           my @tc = $REGISTRY->find_inflator( $self->type_constraint, 'norecurse' );
146 0 0         return @tc ? 1 : 0;
147             }
148              
149             after install_accessors => \&_inline_deflator if ( $Moose::VERSION >= 1.9 );
150              
151             1;
152              
153              
154              
155             =pod
156              
157             =head1 NAME
158              
159             MooseX::Attribute::Deflator::Meta::Role::Attribute - Attribute meta role to support deflation
160              
161             =head1 VERSION
162              
163             version 2.1.11
164              
165             =head1 SYNOPSIS
166              
167             package Test;
168              
169             use Moose;
170             use DateTime;
171              
172             use MooseX::Attribute::Deflator;
173              
174             deflate 'DateTime', via { $_->epoch };
175             inflate 'DateTime', via { DateTime->from_epoch( epoch => $_ ) };
176              
177             no MooseX::Attribute::Deflator;
178              
179             has now => ( is => 'rw',
180             isa => 'DateTime',
181             required => 1,
182             default => sub { DateTime->now },
183             traits => ['Deflator'] );
184              
185             package main;
186            
187             my $obj = Test->new;
188             my $attr = $obj->meta->get_attribute('now');
189            
190             my $deflated = $attr->deflate($obj);
191             # $deflated is now a number
192            
193             my inflated = $attr->inflate($obj, $deflated);
194             # $inflated is now a DateTime object
195              
196             =head1 METHODS
197              
198             These two methods work basically the same. They look up the type constraint
199             which is associated with the attribute and try to find an appropriate
200             deflator/inflator. If there is no deflator/inflator for the exact type
201             constraint, the method will bubble up the type constraint hierarchy
202             until it finds one.
203              
204             =over 4
205              
206             =item B<< $attr->deflate($instance) >>
207              
208             Returns the deflated value of the attribute. It does not change the value
209             of the attribute.
210              
211             =item B<< $attr->inflate($instance, $string) >>
212              
213             Inflates a string C<$string>. This method does not set the value of
214             the attribute to the inflated value.
215              
216             =item B<< $attr->has_inflator >>
217             =item B<< $attr->has_deflator >>
218              
219             =back
220              
221             =head1 AUTHOR
222              
223             Moritz Onken
224              
225             =head1 COPYRIGHT AND LICENSE
226              
227             This software is Copyright (c) 2012 by Moritz Onken.
228              
229             This is free software, licensed under:
230              
231             The (three-clause) BSD License
232              
233             =cut
234              
235              
236             __END__
237