File Coverage

blib/lib/MooseX/TrackDirty/Attributes/Trait/Attribute.pm
Criterion Covered Total %
statement 55 67 82.0
branch 9 14 64.2
condition 3 6 50.0
subroutine 18 23 78.2
pod n/a
total 85 110 77.2


line stmt bran cond sub pod time code
1             #
2             # This file is part of MooseX-TrackDirty-Attributes
3             #
4             # This software is Copyright (c) 2011 by Chris Weyl.
5             #
6             # This is free software, licensed under:
7             #
8             # The GNU Lesser General Public License, Version 2.1, February 1999
9             #
10             package MooseX::TrackDirty::Attributes::Trait::Attribute;
11             {
12             $MooseX::TrackDirty::Attributes::Trait::Attribute::VERSION = '1.900'; # TRIAL
13             }
14              
15             # ABSTRACT: Track dirtied attributes
16              
17 11     11   276079 use Moose::Role;
  11         18906  
  11         51  
18 11     11   40388 use namespace::autoclean;
  11         6125  
  11         89  
19 11     11   5493 use MooseX::Types::Perl ':all';
  11         789069  
  11         102  
20 11     11   31620 use MooseX::AttributeShortcuts 0.008;
  11         2165542  
  11         65  
21              
22 11     11   273977 use Moose::Util::MetaRole;
  11         19  
  11         276  
23 11     11   5339 use MooseX::TrackDirty::Attributes::Util ':all';
  11         23  
  11         62  
24 11     11   10008 use MooseX::TrackDirty::Attributes::Trait::Attribute::Native::Trait ();
  11         22  
  11         11029  
25              
26             # roles to help us track / do-the-right-thing when native traits are also used
27             Moose::Util::MetaRole::apply_metaroles(
28             for => __PACKAGE__->meta,
29             role_metaroles => {
30             role => [ trait_for 'Role' ],
31             application_to_class => [ ToClass ],
32             application_to_role => [ ToRole ],
33             application_to_instance => [ ToInstance ],
34             },
35             );
36              
37              
38             # debugging
39             #use Smart::Comments '###', '####';
40              
41             has is_dirty => (is => 'ro', isa => Identifier, lazy => 1, builder => 1);
42             has original_value => (is => 'ro', isa => Identifier);
43              
44 10     10   313 sub _build_is_dirty { shift->name . '_is_dirty' }
45             #...
46              
47             has value_slot => (is => 'lazy', isa => 'Str');
48             has dirty_slot => (is => 'lazy', isa => 'Str');
49              
50 11     11   343 sub _build_value_slot { shift->name }
51 11     11   361 sub _build_dirty_slot { shift->name . '__DIRTY_TRACKING__' }
52              
53             override slots => sub { (super, shift->dirty_slot) };
54              
55             before set_value => sub {
56             my ($self, $instance) = @_;
57              
58             my $mi = $self->associated_class->get_meta_instance;
59              
60             my $_get = sub { $mi->get_slot_value($instance, @_) };
61             my $_set = sub { $mi->set_slot_value($instance, @_) };
62             my $_exists = sub { $mi->is_slot_initialized($instance, @_) };
63              
64             $_set->($self->dirty_slot, $_get->($self->value_slot))
65             if $_exists->($self->value_slot) && !$_exists->($self->dirty_slot);
66              
67             return;
68             };
69              
70             after clear_value => sub { shift->clear_dirty_slot(@_) };
71              
72             around _inline_clear_value => sub {
73             my ($orig, $self) = (shift, shift);
74             my ($instance) = @_;
75              
76             my $mi = $self->associated_class->get_meta_instance;
77              
78             return $self->$orig(@_)
79             . $mi->inline_deinitialize_slot($instance, $self->dirty_slot)
80             . ';'
81             ;
82             };
83              
84             sub _inline_is_dirty_set {
85 40     40   267 my $self = shift;
86 40         51 my ($instance, $value) = @_;
87              
88             # set tracker if dirty_slot is not init and value_slot value_slot is
89              
90 40         150 my $mi = $self->associated_class->get_meta_instance;
91 40         1239 return $mi->inline_set_slot_value($instance, $self->dirty_slot, $value);
92             }
93              
94             sub _inline_is_dirty_get {
95 0     0   0 my $self = shift;
96 0         0 my ($instance, $value) = @_;
97              
98             # set tracker if dirty_slot is not init and value_slot value_slot is
99              
100 0         0 my $mi = $self->associated_class->get_meta_instance;
101 0         0 return $mi->inline_get_slot_value($instance, $self->dirty_slot, $value);
102             }
103              
104             sub _inline_set_dirty_slot_if_dirty {
105 40     40   92 my ($self, $instance, $value) = @_;
106             # set dirty_slot from value_slot if dirty_slot is not init and value_slot value_slot is
107              
108             ### $instance
109             ### $value
110              
111 40         151 my $mi = $self->associated_class->get_meta_instance;
112 40     80   843 my $_exists = sub { $mi->inline_is_slot_initialized($instance, shift) };
  80         170  
113              
114             # use our predicate method if we have one, as it may have been wrapped/etc
115 40 50       210 my $value_slot_exists
116             = $self->has_predicate
117             ? "${instance}->" . $self->predicate . '()'
118             : $_exists->($self->value_slot)
119             ;
120              
121 40         1506 my $dirty_slot_exists = $_exists->($self->dirty_slot);
122              
123 40         1363 my $set_dirty_slot = $self
124             ->_inline_is_dirty_set(
125             $instance,
126             'do { ' . $mi->inline_get_slot_value($instance, $self->value_slot) . ' } ',
127             )
128             ;
129              
130 40         366 my $code =
131             "do { $set_dirty_slot } " .
132             " if $value_slot_exists && !$dirty_slot_exists;"
133             ;
134              
135 40         133 return $code;
136             }
137              
138             around _inline_instance_set => sub {
139             my ($orig, $self) = (shift, shift);
140             my ($instance, $value) = @_;
141              
142             my $code = $self->_inline_set_dirty_slot_if_dirty(@_);
143             $code = "do { $code; " . $self->$orig(@_) . " }";
144              
145             ### $code
146             return $code;
147             };
148              
149             # TODO remove_accessors
150              
151 0     0   0 sub mark_tracking_dirty { shift->set_dirty_slot(@_) }
152              
153 0     0   0 sub original_value_get { shift->is_dirty_get(@_) }
154              
155             sub is_dirty_set {
156 0     0   0 my ($self, $instance) = @_;
157              
158 0         0 return $self
159             ->associated_class
160             ->get_meta_instance
161             ->set_slot_value($instance, $self->dirty_slot)
162             ;
163             }
164              
165             sub is_dirty_get {
166 6     6   7 my ($self, $instance) = @_;
167              
168 6         26 return $self
169             ->associated_class
170             ->get_meta_instance
171             ->get_slot_value($instance, $self->dirty_slot)
172             ;
173             }
174              
175             sub is_dirty_instance {
176 66     66   85 my ($self, $instance) = @_;
177              
178 66         272 return $self
179             ->associated_class
180             ->get_meta_instance
181             ->is_slot_initialized($instance, $self->dirty_slot)
182             ;
183             }
184              
185             sub clear_dirty_slot {
186 0     0   0 my ($self, $instance) = @_;
187              
188 0         0 return $self
189             ->associated_class
190             ->get_meta_instance
191             ->deinitialize_slot($instance, $self->dirty_slot)
192             ;
193             }
194              
195             override accessor_metaclass => sub {
196             my $self = shift @_;
197              
198             my $classname = Moose::Meta::Class->create_anon_class(
199             superclasses => [ super ],
200             roles => [ 'MooseX::TrackDirty::Attributes::Trait::Method::Accessor' ],
201             cache => 1,
202             )->name;
203              
204             return $classname;
205             };
206              
207             after install_accessors => sub { shift->install_trackdirty_accessors(@_) };
208              
209             sub install_trackdirty_accessors {
210 13     13   26 my ($self, $inline) = @_;
211 13         42 my $class = $self->associated_class;
212              
213             ### in install_accessors...
214 13 50       449 $class->add_method(
215             $self->_process_accessors('is_dirty' => $self->is_dirty, $inline)
216             ) if $self->is_dirty;
217 13 100       1183 $class->add_method(
218             $self->_process_accessors('original_value' => $self->original_value, $inline)
219             ) if $self->original_value;
220              
221 13         145 return;
222             };
223              
224             before remove_accessors => sub { shift->remove_trackdirty_accessors(@_) };
225              
226             sub remove_trackdirty_accessors {
227 2     2   4 my $self = shift @_;
228              
229             # stolen from Class::MOP::Attribute
230             my $_remove_accessor = sub {
231 2     2   4 my ($accessor, $class) = @_;
232 2 50 33     8 if (ref($accessor) && ref($accessor) eq 'HASH') {
233 0         0 ($accessor) = keys %{$accessor};
  0         0  
234             }
235 2         7 my $method = $class->get_method($accessor);
236 2 100 66     56 $class->remove_method($accessor)
237             if (ref($method) && $method->isa('Class::MOP::Method::Accessor'));
238 2         9 };
239              
240 2 50       65 $_remove_accessor->($self->is_dirty, $self->associated_class) if $self->is_dirty;
241 2 50       99 $_remove_accessor->($self->original_value, $self->associated_class) if $self->original_value;
242              
243 2         13 return;
244             };
245              
246              
247             !!42;
248              
249              
250              
251             =pod
252              
253             =encoding utf-8
254              
255             =head1 NAME
256              
257             MooseX::TrackDirty::Attributes::Trait::Attribute - Track dirtied attributes
258              
259             =head1 VERSION
260              
261             This document describes 1.900 of MooseX::TrackDirty::Attributes::Trait::Attribute - released February 15, 2012 as part of MooseX-TrackDirty-Attributes.
262              
263             =head1 DESCRIPTION
264              
265             This is a trait for attribute metaclasses. You really don't need to do
266             anything with it; you want L<MooseX::TrackDirty::Attributes>.
267              
268             =head1 SEE ALSO
269              
270             Please see those modules/websites for more information related to this module.
271              
272             =over 4
273              
274             =item *
275              
276             L<MooseX::TrackDirty::Attributes|MooseX::TrackDirty::Attributes>
277              
278             =item *
279              
280             L<MooseX::TrackDirty::Attributes>
281              
282             =back
283              
284             =head1 SOURCE
285              
286             The development version is on github at L<http://github.com/RsrchBoy/moosex-trackdirty-attributes>
287             and may be cloned from L<git://github.com/RsrchBoy/moosex-trackdirty-attributes.git>
288              
289             =head1 BUGS
290              
291             Please report any bugs or feature requests on the bugtracker website
292             https://github.com/RsrchBoy/moosex-trackdirty-attributes/issues
293              
294             When submitting a bug or request, please include a test-file or a
295             patch to an existing test-file that illustrates the bug or desired
296             feature.
297              
298             =head1 AUTHOR
299              
300             Chris Weyl <cweyl@alumni.drew.edu>
301              
302             =head1 COPYRIGHT AND LICENSE
303              
304             This software is Copyright (c) 2011 by Chris Weyl.
305              
306             This is free software, licensed under:
307              
308             The GNU Lesser General Public License, Version 2.1, February 1999
309              
310             =cut
311              
312              
313             __END__
314