1 package MooseX::ClassAttribute::Role::Meta::Class;
6 use MooseX::AttributeHelpers;
7 use MooseX::ClassAttribute::Role::Meta::Attribute;
8 use Scalar::Util qw( blessed );
13 has class_attribute_map =>
14 ( metaclass => 'Collection::Hash',
16 isa => 'HashRef[Moose::Meta::Attribute]',
17 provides => { set => '_add_class_attribute',
18 exists => 'has_class_attribute',
19 get => 'get_class_attribute',
20 delete => '_remove_class_attribute',
21 keys => 'get_class_attribute_list',
23 default => sub { {} },
24 reader => 'get_class_attribute_map',
27 has _class_attribute_values =>
28 ( metaclass => 'Collection::Hash',
31 provides => { get => 'get_class_attribute_value',
32 set => 'set_class_attribute_value',
33 exists => 'has_class_attribute_value',
34 delete => 'clear_class_attribute_value',
37 default => sub { $_[0]->_class_attribute_values_hashref() },
41 sub add_class_attribute
46 blessed $_[0] && $_[0]->isa('Class::MOP::Attribute')
48 : $self->_process_class_attribute(@_);
50 my $name = $attr->name();
52 $self->remove_class_attribute($name)
53 if $self->has_class_attribute($name);
55 $attr->attach_to_class($self);
57 $self->_add_class_attribute( $name => $attr );
59 my $e = do { local $@; eval { $attr->install_accessors() }; $@ };
63 $self->remove_attribute($name);
70 # It'd be nice if I didn't have to replicate this for class
71 # attributes, since it's basically just a copy of
72 # Moose::Meta::Class->_process_attribute
73 sub _process_class_attribute
79 @args = %{$args[0]} if scalar @args == 1 && ref($args[0]) eq 'HASH';
81 if ($name =~ /^\+(.*)/)
83 return $self->_process_inherited_class_attribute( $1, @args );
87 return $self->_process_new_class_attribute( $name, @args );
91 sub _process_new_class_attribute
99 push @{ $p{traits} },'MooseX::ClassAttribute::Role::Meta::Attribute'
103 $p{traits} = [ 'MooseX::ClassAttribute::Role::Meta::Attribute' ];
106 return Moose::Meta::Attribute->interpolate_class_and_new( $name, %p );
109 sub _process_inherited_class_attribute
115 my $inherited_attr = $self->find_class_attribute_by_name($name);
117 (defined $inherited_attr)
118 || confess "Could not find an attribute by the name of '$name' to inherit from";
120 return $inherited_attr->clone_and_inherit_options(%p);
123 sub remove_class_attribute
128 (defined $name && $name)
129 || confess 'You must provide an attribute name';
131 my $removed_attr = $self->get_class_attribute($name);
132 return unless $removed_attr;
134 $self->_remove_class_attribute($name);
136 $removed_attr->remove_accessors();
137 $removed_attr->detach_from_class();
139 return $removed_attr;
142 sub get_all_class_attributes
147 map { my $meta = Class::MOP::class_of($_);
148 $meta && $meta->can('get_class_attribute_map')
149 ? %{ $meta->get_class_attribute_map() }
152 reverse $self->linearized_isa;
154 return values %attrs;
157 sub compute_all_applicable_class_attributes
159 warn 'The compute_all_applicable_class_attributes method has been deprecated.'
160 . " Use get_all_class_attributes instead.\n";
162 shift->compute_all_applicable_class_attributes(@_);
165 sub find_class_attribute_by_name
170 foreach my $class ( $self->linearized_isa() )
172 my $meta = Class::MOP::class_of($class)
175 return $meta->get_class_attribute($name)
176 if $meta->can('has_class_attribute') && $meta->has_class_attribute($name);
182 sub _class_attribute_values_hashref
187 return \%{ $self->_class_attribute_var_name() };
190 sub _class_attribute_var_name
194 return $self->name() . q'::__ClassAttributeValues';
197 sub inline_class_slot_access
202 return '$' . $self->_class_attribute_var_name . '{"' . quotemeta($name) . '"}';
205 sub inline_get_class_slot_value
210 return $self->inline_class_slot_access($name);
213 sub inline_set_class_slot_value
217 my $val_name = shift;
219 return $self->inline_class_slot_access($name) . ' = ' . $val_name;
222 sub inline_is_class_slot_initialized
227 return 'exists ' . $self->inline_class_slot_access($name);
230 sub inline_deinitialize_class_slot
235 return 'delete ' . $self->inline_class_slot_access($name);
238 sub inline_weaken_class_slot_value
243 return 'Scalar::Util::weaken( ' . $self->inline_class_slot_access($name) . ')';
256 MooseX::ClassAttribute::Role::Meta::Class - A metaclass role for classes with class attributes
260 for my $attr ( HasClassAttributes->meta()->get_all_class_attributes() )
267 This role adds awareness of class attributes to a metaclass object. It
268 provides a set of introspection methods that largely parallel the
269 existing attribute methods, except they operate on class attributes.
273 Every method provided by this role has an analogous method in
274 C<Class::MOP::Class> or C<Moose::Meta::Class> for regular attributes.
276 =head2 $meta->has_class_attribute($name)
278 =head2 $meta->get_class_attribute($name)
280 =head2 $meta->get_class_attribute_list()
282 =head2 $meta->get_class_attribute_map()
284 These methods operate on the current metaclass only.
286 =head2 $meta->add_class_attribute(...)
288 This accepts the same options as the L<Moose::Meta::Attribute>
289 C<add_attribute()> method. However, if an attribute is specified as
290 "required" an error will be thrown.
292 =head2 $meta->remove_class_attribute($name)
294 If the named class attribute exists, it is removed from the class,
295 along with its accessor methods.
297 =head2 $meta->get_all_class_attributes()
299 This method returns a list of attribute objects for the class and all
302 =head2 $meta->find_class_attribute_by_name($name)
304 This method looks at the class and all its parent classes for the
305 named class attribute.
307 =head2 $meta->get_class_attribute_value($name)
309 =head2 $meta->set_class_attribute_value($name, $value)
311 =head2 $meta->set_class_attribute_value($name)
313 =head2 $meta->clear_class_attribute_value($name)
315 These methods operate on the storage for class attribute values, which
316 is attached to the metaclass object.
318 There's really no good reason for you to call these methods unless
319 you're doing some deep hacking. They are named as public methods
320 solely because they are used by other meta roles and classes in this
323 =head2 inline_class_slot_access($name)
325 =head2 inline_get_class_slot_value($name)
327 =head2 inline_set_class_slot_value($name, $val_name)
329 =head2 inline_is_class_slot_initialized($name)
331 =head2 inline_deinitialize_class_slot($name)
333 =head2 inline_weaken_class_slot_value($name)
335 These methods return code snippets for inlining.
337 There's really no good reason for you to call these methods unless
338 you're doing some deep hacking. They are named as public methods
339 solely because they are used by other meta roles and classes in this
344 Dave Rolsky, C<< <autarch@urth.org> >>
348 See L<MooseX::ClassAttribute> for details.
350 =head1 COPYRIGHT & LICENSE
352 Copyright 2007-2008 Dave Rolsky, All Rights Reserved.
354 This program is free software; you can redistribute it and/or modify
355 it under the same terms as Perl itself.