File Coverage

blib/lib/MooseX/CascadeClearing.pm
Criterion Covered Total %
statement 27 27 100.0
branch n/a
condition n/a
subroutine 9 9 100.0
pod n/a
total 36 36 100.0


line stmt bran cond sub pod time code
1             #
2             # This file is part of MooseX-CascadeClearing
3             #
4             # This software is Copyright (c) 2012 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::CascadeClearing;
11             {
12             $MooseX::CascadeClearing::VERSION = '0.05';
13             }
14              
15             # ABSTRACT: Cascade clearer actions across attributes
16              
17 6     6   7593955 use warnings;
  6         21  
  6         227  
18 6     6   35 use strict;
  6         13  
  6         211  
19              
20 6     6   5437 use namespace::autoclean;
  6         31345  
  6         33  
21 6     6   1333 use Moose ();
  6         483381  
  6         112  
22 6     6   34 use Moose::Exporter;
  6         14  
  6         59  
23 6     6   244 use Moose::Util::MetaRole;
  6         13  
  6         124  
24 6     6   29 use Carp;
  6         22  
  6         842  
25              
26             # debugging
27             #use Smart::Comments '###', '####';
28              
29             Moose::Exporter->setup_import_methods(
30             trait_aliases => [
31             [ 'MooseX::CascadeClearing::Role::Meta::Attribute' => 'CascadeClearing' ],
32             ],
33             class_metaroles => {
34             attribute => [
35             'MooseX::CascadeClearing::Role::Meta::Attribute',
36             ],
37             },
38             role_metaroles => {
39             applied_attribute => [
40             'MooseX::CascadeClearing::Role::Meta::Attribute',
41             ],
42             },
43             );
44              
45             {
46             package MooseX::CascadeClearing::Role::Meta::Attribute;
47             {
48             $MooseX::CascadeClearing::Role::Meta::Attribute::VERSION = '0.05';
49             }
50 6     6   30 use namespace::autoclean;
  6         11  
  6         53  
51 6     6   142168 use Moose::Role;
  6         21988  
  6         42  
52              
53             has clear_master => (is => 'rw', isa => 'Str', predicate => 'has_clear_master');
54             has is_clear_master => (is => 'rw', isa => 'Bool', default => 0);
55              
56             after install_accessors => sub {
57             my ($self, $inline) = @_;
58              
59             ### in install_accessors, installing if: $self->is_clear_master
60             return unless $self->is_clear_master;
61              
62              
63             my $clearer = $self->clearer;
64             my $name = $self->name;
65             my $att = $self; # right??
66              
67             confess "clear_master attribute '$name' MUST have a clearer defined!"
68             unless $self->has_clearer;
69              
70             ### installing master clearer...
71             $self->associated_class->add_after_method_modifier($self->clearer, sub {
72             my $self = shift @_;
73              
74             ### in clear_value...
75             return unless $att->is_clear_master;
76              
77             ### looping over our attributes...
78             my @attributes = $self->meta->get_all_attributes;
79              
80             for my $attr (@attributes) {
81              
82             ### working on: $attr->name
83             # ->does() seems to be giving us weird results
84             if ($attr->can('clear_master')
85             && $attr->has_clear_master
86             && $attr->clear_master eq $name) {
87              
88             ### clearing...
89             if (my $clearer = $attr->clearer) { $self->$clearer }
90             else { $attr->clear_value($self) }
91             }
92             }
93             });
94             };
95             }
96              
97             # can we prevent the clearer from being inlined? Do we need to? Are we?
98              
99             1;
100              
101             __END__
102              
103             =pod
104              
105             =encoding utf-8
106              
107             =for :stopwords Chris Weyl
108              
109             =head1 NAME
110              
111             MooseX::CascadeClearing - Cascade clearer actions across attributes
112              
113             =head1 VERSION
114              
115             This document describes version 0.05 of MooseX::CascadeClearing - released September 15, 2012 as part of MooseX-CascadeClearing.
116              
117             =head1 SYNOPSIS
118              
119             use Moose;
120             use MooseX::CascadeClearing;
121              
122             has master => (
123             is => 'rw',
124             isa => 'Str',
125             lazy_build => 1,
126             is_clear_master => 1,
127             );
128              
129             my @opts => (
130             is => 'ro',
131             isa => 'Str',
132             clear_master => 'master',
133             lazy_build => 1,
134             );
135              
136             has sub1 => @opts;
137             has sub2 => @opts;
138             has sub3 => @opts;
139              
140             sub _build_sub1 { shift->master . "1" }
141             sub _build_sub2 { shift->master . "2" }
142             sub _build_sub3 { shift->master . "3" }
143              
144             sub some_sub {
145             # ...
146              
147             # clear master, sub[123] in one fell swoop
148             $self->clear_master;
149              
150             }
151              
152             =head1 DESCRIPTION
153              
154             MooseX::CascadeClearing does the necessary metaclass fiddling to allow an
155             clearing one attribute to be cascaded through to other attributes as well,
156             calling their clear accessors.
157              
158             The intended purpose of this is to assist in situations where the value of one
159             attribute is derived from the value of another attribute -- say a situation
160             where the secondary value is expensive to derive and is thus lazily built. A
161             change to the primary attribute's value would invalidate the secondary value
162             and as such the secondary should be cleared. While it could be argued that
163             this is trivial to do manually for a few attributes, once we consider
164             subclassing and adding in roles the ability to "auto-clear", as it were, is
165             a valuable trait. (Sorry, couldn't resist.)
166              
167             =for Pod::Coverage init_meta
168              
169             =head1 CAVEAT
170              
171             We don't yet trigger a cascade clear on a master attribute's value being set
172             through a setter/accessor accessor. This will likely be available as an
173             option in the not-too-distant-future.
174              
175             =head1 ATTRIBUTE OPTIONS
176              
177             We install an attribute metaclass trait that provides two additional
178             attribute options, as well as wraps the generated clearer method for a
179             designated "master" attribute. By default, using this module causes this
180             trait to be installed for all attributes in the package.
181              
182             =over 4
183              
184             =item is_clear_master => (0|1)
185              
186             If set to 1, we wrap this attribute's clearer with a sub that looks for other
187             attributes to clear.
188              
189             =item clear_master => < attribute_name >
190              
191             Marks this attribute as one that should be cleared when the named attribute's
192             clearer is called. Note that no checking is done to ensure that the named
193             master is actually an attribute in the class.
194              
195             =back
196              
197             =head1 SOURCE
198              
199             The development version is on github at L<http://github.com/RsrchBoy/moosex-cascadeclearing>
200             and may be cloned from L<git://github.com/RsrchBoy/moosex-cascadeclearing.git>
201              
202             =head1 BUGS
203              
204             Please report any bugs or feature requests on the bugtracker website
205             https://github.com/RsrchBoy/moosex-cascadeclearing/issues
206              
207             When submitting a bug or request, please include a test-file or a
208             patch to an existing test-file that illustrates the bug or desired
209             feature.
210              
211             =head1 AUTHOR
212              
213             Chris Weyl <cweyl@alumni.drew.edu>
214              
215             =head1 COPYRIGHT AND LICENSE
216              
217             This software is Copyright (c) 2012 by Chris Weyl.
218              
219             This is free software, licensed under:
220              
221             The GNU Lesser General Public License, Version 2.1, February 1999
222              
223             =cut