File Coverage

blib/lib/MooseX/ClassAttribute/Trait/Class.pm
Criterion Covered Total %
statement 88 94 93.6
branch 12 16 75.0
condition 5 9 55.5
subroutine 22 23 95.6
pod 2 3 66.6
total 129 145 88.9


line stmt bran cond sub pod time code
1             package MooseX::ClassAttribute::Trait::Class;
2              
3 8     8   27 use strict;
  8         9  
  8         193  
4 8     8   26 use warnings;
  8         7  
  8         330  
5              
6             our $VERSION = '0.29';
7              
8 8     8   2641 use MooseX::ClassAttribute::Trait::Attribute;
  8         20  
  8         349  
9 8     8   54 use Scalar::Util qw( blessed );
  8         8  
  8         493  
10              
11 8     8   121 use namespace::autoclean;
  8         12  
  8         45  
12 8     8   443 use Moose::Role;
  8         9  
  8         31  
13              
14             with 'MooseX::ClassAttribute::Trait::Mixin::HasClassAttributes';
15              
16             has _class_attribute_values => (
17             traits => ['Hash'],
18             is => 'ro',
19             isa => 'HashRef',
20             handles => {
21             'get_class_attribute_value' => 'get',
22             'set_class_attribute_value' => 'set',
23             'has_class_attribute_value' => 'exists',
24             'clear_class_attribute_value' => 'delete',
25             },
26             lazy => 1,
27             default => sub { $_[0]->_class_attribute_values_hashref() },
28             init_arg => undef,
29             );
30              
31             around add_class_attribute => sub {
32             my $orig = shift;
33             my $self = shift;
34             my $attr = (
35             blessed $_[0] && $_[0]->isa('Class::MOP::Attribute')
36             ? $_[0]
37             : $self->_process_class_attribute(@_)
38             );
39              
40             $self->$orig($attr);
41              
42             return $attr;
43             };
44              
45             sub _post_add_class_attribute {
46 95     95   89 my $self = shift;
47 95         81 my $attr = shift;
48              
49 95         169 my $name = $attr->name();
50              
51 95         79 my $e = do {
52 95         87 local $@;
53 95         114 eval { $attr->install_accessors() };
  95         262  
54 95         87883 $@;
55             };
56              
57 95 50       473 if ($e) {
58 0         0 $self->remove_attribute($name);
59 0         0 die $e;
60             }
61             }
62              
63             sub _attach_class_attribute {
64 95     95   127 my ( $self, $attribute ) = @_;
65 95         250 $attribute->attach_to_class($self);
66             }
67              
68             # It'd be nice if I didn't have to replicate this for class
69             # attributes, since it's basically just a copy of
70             # Moose::Meta::Class->_process_attribute
71             sub _process_class_attribute {
72 56     56   54 my $self = shift;
73 56         60 my $name = shift;
74 56         108 my @args = @_;
75              
76 56 50 33     160 @args = %{ $args[0] } if scalar @args == 1 && ref( $args[0] ) eq 'HASH';
  0         0  
77              
78 56 100       134 if ( $name =~ /^\+(.*)/ ) {
79 4         18 return $self->_process_inherited_class_attribute( $1, @args );
80             }
81             else {
82 52         117 return $self->_process_new_class_attribute( $name, @args );
83             }
84             }
85              
86             sub _process_new_class_attribute {
87 52     52   63 my $self = shift;
88 52         55 my $name = shift;
89 52         101 my %p = @_;
90              
91 52 100       93 if ( $p{traits} ) {
92 6         9 push @{ $p{traits} }, 'MooseX::ClassAttribute::Trait::Attribute';
  6         17  
93             }
94             else {
95 46         81 $p{traits} = ['MooseX::ClassAttribute::Trait::Attribute'];
96             }
97              
98 52         237 return Moose::Meta::Attribute->interpolate_class_and_new( $name, %p );
99             }
100              
101             sub _process_inherited_class_attribute {
102 4     4   7 my $self = shift;
103 4         11 my $name = shift;
104 4         9 my %p = @_;
105              
106 4         14 my $inherited_attr = $self->find_class_attribute_by_name($name);
107              
108 4 50       12 ( defined $inherited_attr )
109             || confess
110             "Could not find an attribute by the name of '$name' to inherit from";
111              
112 4         35 return $inherited_attr->clone_and_inherit_options(%p);
113             }
114              
115             around remove_class_attribute => sub {
116             my $orig = shift;
117             my $self = shift;
118              
119             my $removed_attr = $self->$orig(@_)
120             or return;
121              
122             $removed_attr->remove_accessors();
123             $removed_attr->detach_from_class();
124              
125             return $removed_attr;
126             };
127              
128             sub get_all_class_attributes {
129 2     2 1 489 my $self = shift;
130              
131             my %attrs = map {
132 2         6 my $meta = Class::MOP::class_of($_);
  5         20  
133             $meta && $meta->can('_class_attribute_map')
134 5 100 66     51 ? %{ $meta->_class_attribute_map() }
  3         107  
135             : ()
136             }
137             reverse $self->linearized_isa;
138              
139 2         9 return values %attrs;
140             }
141              
142             sub compute_all_applicable_class_attributes {
143 0     0 0 0 warn
144             'The compute_all_applicable_class_attributes method has been deprecated.'
145             . " Use get_all_class_attributes instead.\n";
146              
147 0         0 shift->compute_all_applicable_class_attributes(@_);
148             }
149              
150             sub find_class_attribute_by_name {
151 4     4 1 6 my $self = shift;
152 4         5 my $name = shift;
153              
154 4         16 foreach my $class ( $self->linearized_isa() ) {
155 8 50       39 my $meta = Class::MOP::class_of($class)
156             or next;
157              
158 8 100 66     370 return $meta->get_class_attribute($name)
159             if $meta->can('has_class_attribute')
160             && $meta->has_class_attribute($name);
161             }
162              
163 0         0 return;
164             }
165              
166             sub _class_attribute_values_hashref {
167 18     18   29 my $self = shift;
168              
169 8     8   35214 no strict 'refs';
  8         13  
  8         2062  
170 18         23 return \%{ $self->_class_attribute_var_name() };
  18         44  
171             }
172              
173             sub _class_attribute_var_name {
174 273     273   212 my $self = shift;
175              
176 273         2246 return $self->name() . q'::__ClassAttributeValues';
177             }
178              
179             sub _inline_class_slot_access {
180 255     255   216 my $self = shift;
181 255         182 my $name = shift;
182              
183             return
184 255         326 '$'
185             . $self->_class_attribute_var_name . '{"'
186             . quotemeta($name) . '"}';
187             }
188              
189             sub _inline_get_class_slot_value {
190 132     132   448 my $self = shift;
191 132         125 my $name = shift;
192              
193 132         198 return $self->_inline_class_slot_access($name);
194             }
195              
196             sub _inline_set_class_slot_value {
197 72     72   275 my $self = shift;
198 72         69 my $name = shift;
199 72         63 my $val_name = shift;
200              
201 72         186 return $self->_inline_class_slot_access($name) . ' = ' . $val_name;
202             }
203              
204             sub _inline_is_class_slot_initialized {
205 37     37   135 my $self = shift;
206 37         38 my $name = shift;
207              
208 37         65 return 'exists ' . $self->_inline_class_slot_access($name);
209             }
210              
211             sub _inline_deinitialize_class_slot {
212 7     7   34 my $self = shift;
213 7         11 my $name = shift;
214              
215 7         16 return 'delete ' . $self->_inline_class_slot_access($name);
216             }
217              
218             sub _inline_weaken_class_slot_value {
219 7     7   33 my $self = shift;
220 7         11 my $name = shift;
221              
222             return
223 7         15 'Scalar::Util::weaken( '
224             . $self->_inline_class_slot_access($name) . ')';
225             }
226              
227             1;
228              
229             # ABSTRACT: A trait for classes with class attributes
230              
231             __END__
232              
233             =pod
234              
235             =encoding UTF-8
236              
237             =head1 NAME
238              
239             MooseX::ClassAttribute::Trait::Class - A trait for classes with class attributes
240              
241             =head1 VERSION
242              
243             version 0.29
244              
245             =head1 SYNOPSIS
246              
247             for my $attr ( HasClassAttributes->meta()->get_all_class_attributes() )
248             {
249             print $attr->name();
250             }
251              
252             =head1 DESCRIPTION
253              
254             This role adds awareness of class attributes to a metaclass object. It
255             provides a set of introspection methods that largely parallel the
256             existing attribute methods, except they operate on class attributes.
257              
258             =head1 METHODS
259              
260             Every method provided by this role has an analogous method in
261             C<Class::MOP::Class> or C<Moose::Meta::Class> for regular attributes.
262              
263             =head2 $meta->has_class_attribute($name)
264              
265             =head2 $meta->get_class_attribute($name)
266              
267             =head2 $meta->get_class_attribute_list()
268              
269             These methods operate on the current metaclass only.
270              
271             =head2 $meta->add_class_attribute(...)
272              
273             This accepts the same options as the L<Moose::Meta::Attribute>
274             C<add_attribute()> method. However, if an attribute is specified as
275             "required" an error will be thrown.
276              
277             =head2 $meta->remove_class_attribute($name)
278              
279             If the named class attribute exists, it is removed from the class,
280             along with its accessor methods.
281              
282             =head2 $meta->get_all_class_attributes()
283              
284             This method returns a list of attribute objects for the class and all
285             its parent classes.
286              
287             =head2 $meta->find_class_attribute_by_name($name)
288              
289             This method looks at the class and all its parent classes for the
290             named class attribute.
291              
292             =head2 $meta->get_class_attribute_value($name)
293              
294             =head2 $meta->set_class_attribute_value($name, $value)
295              
296             =head2 $meta->set_class_attribute_value($name)
297              
298             =head2 $meta->clear_class_attribute_value($name)
299              
300             These methods operate on the storage for class attribute values, which
301             is attached to the metaclass object.
302              
303             There's really no good reason for you to call these methods unless
304             you're doing some deep hacking. They are named as public methods
305             solely because they are used by other meta roles and classes in this
306             distribution.
307              
308             =head1 BUGS
309              
310             See L<MooseX::ClassAttribute> for details.
311              
312             Bugs may be submitted through L<the RT bug tracker|http://rt.cpan.org/Public/Dist/Display.html?Name=MooseX-ClassAttribute>
313             (or L<bug-moosex-classattribute@rt.cpan.org|mailto:bug-moosex-classattribute@rt.cpan.org>).
314              
315             I am also usually active on IRC as 'drolsky' on C<irc://irc.perl.org>.
316              
317             =head1 AUTHOR
318              
319             Dave Rolsky <autarch@urth.org>
320              
321             =head1 COPYRIGHT AND LICENCE
322              
323             This software is Copyright (c) 2016 by Dave Rolsky.
324              
325             This is free software, licensed under:
326              
327             The Artistic License 2.0 (GPL Compatible)
328              
329             =cut