1 package MooseX::ClassAttribute::Trait::Class;
6 use MooseX::ClassAttribute::Trait::Attribute;
7 use Scalar::Util qw( blessed );
9 use namespace::autoclean;
12 with 'MooseX::ClassAttribute::Trait::Mixin::HasClassAttributes';
14 has _class_attribute_values => (
19 'get_class_attribute_value' => 'get',
20 'set_class_attribute_value' => 'set',
21 'has_class_attribute_value' => 'exists',
22 'clear_class_attribute_value' => 'delete',
25 default => sub { $_[0]->_class_attribute_values_hashref() },
29 around add_class_attribute => sub {
33 blessed $_[0] && $_[0]->isa('Class::MOP::Attribute')
35 : $self->_process_class_attribute(@_)
43 sub _post_add_class_attribute {
47 my $name = $attr->name();
51 eval { $attr->install_accessors() };
56 $self->remove_attribute($name);
61 sub _attach_class_attribute {
62 my ( $self, $attribute ) = @_;
63 $attribute->attach_to_class($self);
66 # It'd be nice if I didn't have to replicate this for class
67 # attributes, since it's basically just a copy of
68 # Moose::Meta::Class->_process_attribute
69 sub _process_class_attribute {
74 @args = %{ $args[0] } if scalar @args == 1 && ref( $args[0] ) eq 'HASH';
76 if ( $name =~ /^\+(.*)/ ) {
77 return $self->_process_inherited_class_attribute( $1, @args );
80 return $self->_process_new_class_attribute( $name, @args );
84 sub _process_new_class_attribute {
90 push @{ $p{traits} }, 'MooseX::ClassAttribute::Trait::Attribute';
93 $p{traits} = ['MooseX::ClassAttribute::Trait::Attribute'];
96 return Moose::Meta::Attribute->interpolate_class_and_new( $name, %p );
99 sub _process_inherited_class_attribute {
104 my $inherited_attr = $self->find_class_attribute_by_name($name);
106 ( defined $inherited_attr )
108 "Could not find an attribute by the name of '$name' to inherit from";
110 return $inherited_attr->clone_and_inherit_options(%p);
113 around remove_class_attribute => sub {
117 my $removed_attr = $self->$orig(@_)
120 $removed_attr->remove_accessors();
121 $removed_attr->detach_from_class();
123 return $removed_attr;
126 sub get_all_class_attributes {
130 my $meta = Class::MOP::class_of($_);
131 $meta && $meta->can('_class_attribute_map')
132 ? %{ $meta->_class_attribute_map() }
135 reverse $self->linearized_isa;
137 return values %attrs;
140 sub compute_all_applicable_class_attributes {
142 'The compute_all_applicable_class_attributes method has been deprecated.'
143 . " Use get_all_class_attributes instead.\n";
145 shift->compute_all_applicable_class_attributes(@_);
148 sub find_class_attribute_by_name {
152 foreach my $class ( $self->linearized_isa() ) {
153 my $meta = Class::MOP::class_of($class)
156 return $meta->get_class_attribute($name)
157 if $meta->can('has_class_attribute')
158 && $meta->has_class_attribute($name);
164 sub _class_attribute_values_hashref {
168 return \%{ $self->_class_attribute_var_name() };
171 sub _class_attribute_var_name {
174 return $self->name() . q'::__ClassAttributeValues';
177 sub _inline_class_slot_access {
183 . $self->_class_attribute_var_name . '{"'
184 . quotemeta($name) . '"}';
187 sub _inline_get_class_slot_value {
191 return $self->_inline_class_slot_access($name);
194 sub _inline_set_class_slot_value {
197 my $val_name = shift;
199 return $self->_inline_class_slot_access($name) . ' = ' . $val_name;
202 sub _inline_is_class_slot_initialized {
206 return 'exists ' . $self->_inline_class_slot_access($name);
209 sub _inline_deinitialize_class_slot {
213 return 'delete ' . $self->_inline_class_slot_access($name);
216 sub _inline_weaken_class_slot_value {
221 'Scalar::Util::weaken( '
222 . $self->_inline_class_slot_access($name) . ')';
227 # ABSTRACT: A trait for classes with class attributes
235 for my $attr ( HasClassAttributes->meta()->get_all_class_attributes() )
242 This role adds awareness of class attributes to a metaclass object. It
243 provides a set of introspection methods that largely parallel the
244 existing attribute methods, except they operate on class attributes.
248 Every method provided by this role has an analogous method in
249 C<Class::MOP::Class> or C<Moose::Meta::Class> for regular attributes.
251 =head2 $meta->has_class_attribute($name)
253 =head2 $meta->get_class_attribute($name)
255 =head2 $meta->get_class_attribute_list()
257 These methods operate on the current metaclass only.
259 =head2 $meta->add_class_attribute(...)
261 This accepts the same options as the L<Moose::Meta::Attribute>
262 C<add_attribute()> method. However, if an attribute is specified as
263 "required" an error will be thrown.
265 =head2 $meta->remove_class_attribute($name)
267 If the named class attribute exists, it is removed from the class,
268 along with its accessor methods.
270 =head2 $meta->get_all_class_attributes()
272 This method returns a list of attribute objects for the class and all
275 =head2 $meta->find_class_attribute_by_name($name)
277 This method looks at the class and all its parent classes for the
278 named class attribute.
280 =head2 $meta->get_class_attribute_value($name)
282 =head2 $meta->set_class_attribute_value($name, $value)
284 =head2 $meta->set_class_attribute_value($name)
286 =head2 $meta->clear_class_attribute_value($name)
288 These methods operate on the storage for class attribute values, which
289 is attached to the metaclass object.
291 There's really no good reason for you to call these methods unless
292 you're doing some deep hacking. They are named as public methods
293 solely because they are used by other meta roles and classes in this
298 See L<MooseX::ClassAttribute> for details.