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
144 shift->compute_all_applicable_class_attributes(@_);
147 sub compute_all_applicable_class_attributes
152 map { my $meta = Class::MOP::Class->initialize($_);
153 $meta->can('get_class_attribute_map')
154 ? %{ $meta->get_class_attribute_map() }
157 reverse $self->linearized_isa;
159 return values %attrs;
162 sub find_class_attribute_by_name
167 foreach my $class ( $self->linearized_isa() )
169 my $meta = Class::MOP::Class->initialize($class);
171 return $meta->get_class_attribute($name)
172 if $meta->can('has_class_attribute') && $meta->has_class_attribute($name);
178 sub _class_attribute_values_hashref
183 return \%{ $self->_class_attribute_var_name() };
186 sub _class_attribute_var_name
190 return $self->name() . q'::__ClassAttributeValues';
193 sub inline_class_slot_access
198 return '$' . $self->_class_attribute_var_name . '{"' . quotemeta($name) . '"}';
201 sub inline_get_class_slot_value
206 return $self->inline_class_slot_access($name);
209 sub inline_set_class_slot_value
213 my $val_name = shift;
215 return $self->inline_class_slot_access($name) . ' = ' . $val_name;
218 sub inline_is_class_slot_initialized
223 return 'exists ' . $self->inline_class_slot_access($name);
226 sub inline_deinitialize_class_slot
231 return 'delete ' . $self->inline_class_slot_access($name);
234 sub inline_weaken_class_slot_value
239 return 'Scalar::Util::weaken( ' . $self->inline_class_slot_access($name) . ')';
252 MooseX::ClassAttribute::Role::Meta::Class - A metaclass role for classes with class attributes
256 for my $attr ( HasClassAttributes->meta()->get_all_class_attributes() )
263 This role adds awareness of class attributes to a metaclass object. It
264 provides a set of introspection methods that largely parallel the
265 existing attribute methods, except they operate on class attributes.
269 Every method provided by this role has an analogous method in
270 C<Class::MOP::Class> or C<Moose::Meta::Class> for regular attributes.
272 =head2 $meta->has_class_attribute($name)
274 =head2 $meta->get_class_attribute($name)
276 =head2 $meta->get_class_attribute_list()
278 =head2 $meta->get_class_attribute_map()
280 These methods operate on the current metaclass only.
282 =head2 $meta->add_class_attribute(...)
284 This accepts the same options as the L<Moose::Meta::Attribute>
285 C<add_attribute()> method. However, if an attribute is specified as
286 "required" an error will be thrown.
288 =head2 $meta->remove_class_attribute($name)
290 If the named class attribute exists, it is removed from the class,
291 along with its accessor methods.
293 =head2 $meta->get_all_class_attributes()
295 =head2 $meta->compute_all_applicable_class_attributes()
297 These methods return a list of attribute objects for the class and all
300 =head2 $meta->find_class_attribute_by_name($name)
302 This method looks at the class and all its parent classes for the
303 named class attribute.
305 =head2 $meta->get_class_attribute_value($name)
307 =head2 $meta->set_class_attribute_value($name, $value)
309 =head2 $meta->set_class_attribute_value($name)
311 =head2 $meta->clear_class_attribute_value($name)
313 These methods operate on the storage for class attribute values, which
314 is attached to the metaclass object.
316 There's really no good reason for you to call these methods unless
317 you're doing some deep hacking. They are named as public methods
318 solely because they are used by other meta roles and classes in this
321 =head2 inline_class_slot_access($name)
323 =head2 inline_get_class_slot_value($name)
325 =head2 inline_set_class_slot_value($name, $val_name)
327 =head2 inline_is_class_slot_initialized($name)
329 =head2 inline_deinitialize_class_slot($name)
331 =head2 inline_weaken_class_slot_value($name)
333 These methods return code snippets for inlining.
335 There's really no good reason for you to call these methods unless
336 you're doing some deep hacking. They are named as public methods
337 solely because they are used by other meta roles and classes in this
342 Dave Rolsky, C<< <autarch@urth.org> >>
346 See L<MooseX::ClassAttribute> for details.
348 =head1 COPYRIGHT & LICENSE
350 Copyright 2007-2008 Dave Rolsky, All Rights Reserved.
352 This program is free software; you can redistribute it and/or modify
353 it under the same terms as Perl itself.