1 package MooseX::ClassAttribute;
7 our $AUTHORITY = 'cpan:DROLSKY';
9 our @EXPORT = 'class_has'; ## no critic ProhibitAutomaticExportation
12 use B qw( svref_2object );
16 sub class_has ## no critic RequireArgUnpacking
18 my $caller = caller();
20 my $caller_meta = $caller->meta();
22 my @parents = $caller_meta->superclasses();
24 my $container_pkg = _make_container_class( $caller, @parents );
26 $container_pkg->meta()->_process_attribute(@_);
28 my $container_meta = $container_pkg->meta();
29 for my $meth ( grep { $_ ne 'instance' } $container_meta->get_method_list() )
31 next if $caller_meta->has_method($meth);
33 my $sub = sub { shift;
34 my $instance = $container_pkg->instance();
35 return $instance->$meth(@_); };
37 $caller_meta->add_method( $meth => $sub );
44 # This should probably be an attribute of the metaclass, but that
45 # would require extending Moose::Meta::Class, which would conflict
46 # with anything else that wanted to do so as well (we need
47 # metaclass roles or something).
50 sub _make_container_class ## no critic RequireArgUnpacking
54 return $Name{$caller} if $Name{$caller};
56 my @parents = map { container_class($_) || () } @_;
58 push @parents, 'Moose::Object'
59 unless grep { $_->isa('Moose::Object') } @parents;
61 my $container_pkg = 'MooseX::ClassAttribute::Container::' . $caller;
63 my $instance_meth = sub {
64 no strict 'refs'; ## no critic ProhibitNoStrict
65 return ${ $container_pkg . '::Self' } ||= shift->new(@_);
69 Moose::Meta::Class->create
71 superclasses => \@parents,
72 methods => { instance => $instance_meth },
75 return $Name{$caller} = $container_pkg;
80 my $pkg = shift || caller();
86 # This is basically copied from Moose.pm
87 sub unimport ## no critic RequireFinalReturn
89 my $caller = caller();
91 no strict 'refs'; ## no critic ProhibitNoStrict
92 foreach my $name (@EXPORT)
94 if ( defined &{ $caller . '::' . $name } )
96 my $keyword = \&{ $caller . '::' . $name };
99 eval { svref_2object($keyword)->GV()->STASH()->NAME() };
102 next if $pkg_name ne __PACKAGE__;
104 delete ${ $caller . '::' }{$name};
118 MooseX::ClassAttribute - Declare class attributes Moose-style
125 use MooseX::ClassAttribute;
130 default => sub { {} },
133 __PACKAGE__->meta()->make_immutable();
134 MooseX::ClassAttribute::containing_class()->meta()->make_immutable();
137 no MooseX::ClassAttribute;
141 My::Class->Cache()->{thing} = ...;
146 This module allows you to declare class attributes in exactly the same
147 way as you declare object attributes, except using C<class_has()>
148 instead of C<has()>. It is also possible to make these attributes
149 immutable (and faster) just as you can with normal Moose attributes.
151 You can use any feature of Moose's attribute declarations, including
152 overriding a parent's attributes, delegation (C<handles>), and
153 attribute metaclasses, and it should just work.
155 The accessors methods for class attribute may be called on the class
156 directly, or on objects of that class. Passing a class attribute to
157 the constructor will not set it.
161 This class exports one function when you use it, C<class_has()>. This
162 works exactly like Moose's C<has()>, but it declares class attributes.
164 Own little nit is that if you include C<no Moose> in your class, you
165 won't remove the C<class_has()> function. To do that you must include
166 C<no MooseX::ClassAttribute> as well.
168 =head2 Implementation and Immutability
170 Underneath the hood, this class creates one new class for each class
171 which has class attributes and sets up delegating methods in the class
172 for which you're creating class attributes. You don't need to worry
173 about this too much, except when it comes to making a class immutable.
175 Since the class attributes are not really stored in your class, you
176 need to make the containing class immutable as well as your own ...
178 __PACKAGE__->meta()->make_immutable();
179 MooseX::ClassAttribute::containing_class()->meta()->make_immutable();
181 I<This may change in the future!>
185 Dave Rolsky, C<< <autarch@urth.org> >>
189 Please report any bugs or feature requests to
190 C<bug-moosex-classattribute@rt.cpan.org>, or through the web interface
191 at L<http://rt.cpan.org>. I will be notified, and then you'll
192 automatically be notified of progress on your bug as I make changes.
194 =head1 COPYRIGHT & LICENSE
196 Copyright 2007 Dave Rolsky, All Rights Reserved.
198 This program is free software; you can redistribute it and/or modify
199 it under the same terms as Perl itself.