Simplify attach & detach code
[gitmo/MooseX-ClassAttribute.git] / lib / MooseX / ClassAttribute / Trait / Attribute.pm
CommitLineData
63fcc508 1package MooseX::ClassAttribute::Trait::Attribute;
bb70fe3a 2
3use strict;
4use warnings;
5
88b7f2c8 6use namespace::autoclean;
a1ec1ff1 7use Moose::Role;
bb70fe3a 8
a1ec1ff1 9# This is the worst role evar! Really, this should be a subclass,
10# because it overrides a lot of behavior. However, as a subclass it
8e988dc6 11# won't cooperate with _other_ subclasses.
bb70fe3a 12
9e2d0ef1 13around _process_options => sub {
a1ec1ff1 14 my $orig = shift;
bb70fe3a 15 my $class = shift;
16 my $name = shift;
17 my $options = shift;
18
19 confess 'A class attribute cannot be required'
20 if $options->{required};
21
a1ec1ff1 22 return $class->$orig( $name, $options );
23};
bb70fe3a 24
549cbfd2 25after attach_to_class => sub {
bb70fe3a 26 my $self = shift;
27 my $meta = shift;
28
bb70fe3a 29 $self->_initialize($meta)
30 unless $self->is_lazy();
a1ec1ff1 31};
bb70fe3a 32
549cbfd2 33before detach_from_class => sub {
bb70fe3a 34 my $self = shift;
35 my $meta = shift;
36
37 $self->clear_value($meta);
a1ec1ff1 38};
bb70fe3a 39
88b7f2c8 40sub _initialize {
6048a053 41 my $self = shift;
42 my $metaclass = shift;
bb70fe3a 43
88b7f2c8 44 if ( $self->has_default() ) {
d0785271 45 $self->set_value( undef, $self->default() );
bb70fe3a 46 }
88b7f2c8 47 elsif ( $self->has_builder() ) {
6048a053 48 $self->set_value( undef, $self->_call_builder( $metaclass->name() ) );
bb70fe3a 49 }
50}
51
9e2d0ef1 52around default => sub {
a1ec1ff1 53 my $orig = shift;
bb70fe3a 54 my $self = shift;
55
a1ec1ff1 56 my $default = $self->$orig();
bb70fe3a 57
88b7f2c8 58 if ( $self->is_default_a_coderef() ) {
bb70fe3a 59 return $default->( $self->associated_class() );
60 }
61
62 return $default;
a1ec1ff1 63};
bb70fe3a 64
9e2d0ef1 65around _call_builder => sub {
a1ec1ff1 66 shift;
bb70fe3a 67 my $self = shift;
68 my $class = shift;
69
70 my $builder = $self->builder();
71
72 return $class->$builder()
73 if $class->can( $self->builder );
74
75 confess( "$class does not support builder method '"
76 . $self->builder
77 . "' for attribute '"
78 . $self->name
79 . "'" );
a1ec1ff1 80};
bb70fe3a 81
9e2d0ef1 82around set_value => sub {
a1ec1ff1 83 shift;
88b7f2c8 84 my $self = shift;
85 shift; # ignoring instance or class name
86 my $value = shift;
bb70fe3a 87
88b7f2c8 88 $self->associated_class()
89 ->set_class_attribute_value( $self->name() => $value );
a1ec1ff1 90};
bb70fe3a 91
9e2d0ef1 92around get_value => sub {
a1ec1ff1 93 shift;
88b7f2c8 94 my $self = shift;
bb70fe3a 95
88b7f2c8 96 return $self->associated_class()
97 ->get_class_attribute_value( $self->name() );
a1ec1ff1 98};
bb70fe3a 99
9e2d0ef1 100around has_value => sub {
a1ec1ff1 101 shift;
88b7f2c8 102 my $self = shift;
bb70fe3a 103
88b7f2c8 104 return $self->associated_class()
105 ->has_class_attribute_value( $self->name() );
a1ec1ff1 106};
bb70fe3a 107
9e2d0ef1 108around clear_value => sub {
a1ec1ff1 109 shift;
88b7f2c8 110 my $self = shift;
bb70fe3a 111
88b7f2c8 112 return $self->associated_class()
113 ->clear_class_attribute_value( $self->name() );
a1ec1ff1 114};
bb70fe3a 115
28c23808 116if ( $Moose::VERSION < 1.99 ) {
117 around inline_get => sub {
118 shift;
119 my $self = shift;
120
121 return $self->associated_class()
122 ->inline_get_class_slot_value( $self->slots() );
123 };
124
125 around inline_set => sub {
126 shift;
127 my $self = shift;
128 shift;
129 my $value = shift;
130
131 my $meta = $self->associated_class();
132
133 my $code
134 = $meta->inline_set_class_slot_value( $self->slots(), $value )
135 . ";";
136 $code
137 .= $meta->inline_weaken_class_slot_value( $self->slots(), $value )
138 . " if ref $value;"
139 if $self->is_weak_ref();
140
141 return $code;
142 };
143
144 around inline_has => sub {
145 shift;
146 my $self = shift;
147
148 return $self->associated_class()
149 ->inline_is_class_slot_initialized( $self->slots() );
150 };
151
152 around inline_clear => sub {
153 shift;
154 my $self = shift;
155
156 return $self->associated_class()
157 ->inline_deinitialize_class_slot( $self->slots() );
158 };
159}
160else {
161 around _inline_instance_get => sub {
162 shift;
163 my $self = shift;
164
165 return $self->associated_class()
166 ->inline_get_class_slot_value( $self->slots() );
167 };
168
169 around _inline_instance_set => sub {
170 shift;
171 my $self = shift;
172 shift;
173 my $value = shift;
174
175 return $self->associated_class()
176 ->inline_set_class_slot_value( $self->slots(), $value );
177 };
178
179 around _inline_instance_has => sub {
180 shift;
181 my $self = shift;
182
183 return $self->associated_class()
184 ->inline_is_class_slot_initialized( $self->slots() );
185 };
186
187 around _inline_instance_clear => sub {
188 shift;
189 my $self = shift;
190
191 return $self->associated_class()
192 ->inline_deinitialize_class_slot( $self->slots() );
193 };
194
195 around _inline_weaken_value => sub {
196 shift;
197 my $self = shift;
198 shift;
199 my $value = shift;
200
201 return unless $self->is_weak_ref();
202
203 return (
204 $self->associated_class->inline_weaken_class_slot_value(
205 $self->slots(), $value
206 ),
207 'if ref ' . $value . ';',
208 );
209 };
210}
935982fc 211
bb70fe3a 2121;
7a4a3b1e 213
0d0bf8c3 214# ABSTRACT: A trait for class attributes
215
7a4a3b1e 216__END__
217
218=pod
219
7a4a3b1e 220=head1 DESCRIPTION
221
222This role modifies the behavior of class attributes in various
223ways. It really should be a subclass of C<Moose::Meta::Attribute>, but
224if it were then it couldn't be combined with other attribute
225metaclasses, like C<MooseX::AttributeHelpers>.
226
227There are no new public methods implemented by this role. All it does
228is change the behavior of a number of existing methods.
229
7a4a3b1e 230=head1 BUGS
231
232See L<MooseX::ClassAttribute> for details.
233
7a4a3b1e 234=cut