1 package MooseX::ClassAttribute;
7 our $AUTHORITY = 'cpan:DROLSKY';
9 our @EXPORT = 'class_has'; ## no critic ProhibitAutomaticExportation
12 use B qw( svref_2object );
13 use Moose::Meta::Class;
17 sub class_has ## no critic RequireArgUnpacking
19 my $caller = caller();
21 my $caller_meta = $caller->meta();
23 my @parents = $caller_meta->superclasses();
25 my $container_pkg = _make_container_class( $caller, @parents );
27 $container_pkg->meta()->_process_attribute(@_);
29 my $container_meta = $container_pkg->meta();
30 for my $meth ( grep { $_ ne 'instance' } $container_meta->get_method_list() )
32 next if $caller_meta->has_method($meth);
34 my $sub = sub { shift;
35 my $instance = $container_pkg->instance();
36 return $instance->$meth(@_); };
38 $caller_meta->add_method( $meth => $sub );
45 # This should probably be an attribute of the metaclass, but that
46 # would require extending Moose::Meta::Class, which would conflict
47 # with anything else that wanted to do so as well (we need
48 # metaclass roles or something).
51 sub _make_container_class ## no critic RequireArgUnpacking
55 return $Name{$caller} if $Name{$caller};
57 my @parents = map { container_class($_) || () } @_;
59 push @parents, 'Moose::Object'
60 unless grep { $_->isa('Moose::Object') } @parents;
62 my $container_pkg = 'MooseX::ClassAttribute::Container::' . $caller;
64 my $instance_meth = sub {
65 no strict 'refs'; ## no critic ProhibitNoStrict
66 return ${ $container_pkg . '::Self' } ||= shift->new(@_);
70 Moose::Meta::Class->create
72 superclasses => \@parents,
73 methods => { instance => $instance_meth },
76 return $Name{$caller} = $container_pkg;
81 my $pkg = shift || caller();
87 # This is basically copied from Moose.pm
88 sub unimport ## no critic RequireFinalReturn
90 my $caller = Moose::_get_caller(@_);
92 no strict 'refs'; ## no critic ProhibitNoStrict
93 foreach my $name (@EXPORT)
95 if ( defined &{ $caller . '::' . $name } )
97 my $keyword = \&{ $caller . '::' . $name };
100 eval { svref_2object($keyword)->GV()->STASH()->NAME() };
103 next if $pkg_name ne __PACKAGE__;
105 delete ${ $caller . '::' }{$name};
119 MooseX::ClassAttribute - Declare class attributes Moose-style
126 use MooseX::ClassAttribute;
131 default => sub { {} },
134 __PACKAGE__->meta()->make_immutable();
135 MooseX::ClassAttribute::containing_class()->meta()->make_immutable();
138 no MooseX::ClassAttribute;
142 My::Class->Cache()->{thing} = ...;
147 This module allows you to declare class attributes in exactly the same
148 way as you declare object attributes, except using C<class_has()>
149 instead of C<has()>. It is also possible to make these attributes
150 immutable (and faster) just as you can with normal Moose attributes.
152 You can use any feature of Moose's attribute declarations, including
153 overriding a parent's attributes, delegation (C<handles>), and
154 attribute metaclasses, and it should just work.
156 The accessors methods for class attribute may be called on the class
157 directly, or on objects of that class. Passing a class attribute to
158 the constructor will not set it.
162 This class exports one function when you use it, C<class_has()>. This
163 works exactly like Moose's C<has()>, but it declares class attributes.
165 Own little nit is that if you include C<no Moose> in your class, you
166 won't remove the C<class_has()> function. To do that you must include
167 C<no MooseX::ClassAttribute> as well.
169 =head2 Implementation and Immutability
171 Underneath the hood, this class creates one new class for each class
172 which has class attributes and sets up delegating methods in the class
173 for which you're creating class attributes. You don't need to worry
174 about this too much, except when it comes to making a class immutable.
176 Since the class attributes are not really stored in your class, you
177 need to make the containing class immutable as well as your own ...
179 __PACKAGE__->meta()->make_immutable();
180 MooseX::ClassAttribute::containing_class()->meta()->make_immutable();
182 I<This may change in the future!>
186 Dave Rolsky, C<< <autarch@urth.org> >>
190 Please report any bugs or feature requests to
191 C<bug-moosex-classattribute@rt.cpan.org>, or through the web interface
192 at L<http://rt.cpan.org>. I will be notified, and then you'll
193 automatically be notified of progress on your bug as I make changes.
195 =head1 COPYRIGHT & LICENSE
197 Copyright 2007 Dave Rolsky, All Rights Reserved.
199 This program is free software; you can redistribute it and/or modify
200 it under the same terms as Perl itself.