X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMooseX%2FClassAttribute.pm;h=57e141b55c7657f3e673c850c324d4529ae29e0f;hb=b2e0e01ec7ccd4771694b1fbd1452d551bc2829f;hp=bfa5febbd6b8d12729aec7540d0b9ff76d7592f7;hpb=7dc1418a6b300b240bc9274b612a91f7fe0efbad;p=gitmo%2FMooseX-ClassAttribute.git diff --git a/lib/MooseX/ClassAttribute.pm b/lib/MooseX/ClassAttribute.pm index bfa5feb..57e141b 100644 --- a/lib/MooseX/ClassAttribute.pm +++ b/lib/MooseX/ClassAttribute.pm @@ -3,116 +3,45 @@ package MooseX::ClassAttribute; use strict; use warnings; -our $VERSION = '0.01'; +our $VERSION = '0.06'; our $AUTHORITY = 'cpan:DROLSKY'; -our @EXPORT = 'class_has'; ## no critic ProhibitAutomaticExportation -use Exporter qw( import ); +use Moose (); +use Moose::Exporter; +use MooseX::ClassAttribute::Role::Meta::Class; +use MooseX::ClassAttribute::Role::Meta::Attribute; -use B qw( svref_2object ); -use Sub::Name; +Moose::Exporter->setup_import_methods + ( with_caller => [ 'class_has' ] ); -sub class_has ## no critic RequireArgUnpacking +sub init_meta { - my $caller = caller(); + shift; + my %p = @_; - my $caller_meta = $caller->meta(); + Moose->init_meta(%p); - my @parents = $caller_meta->superclasses(); - - my $container_pkg = _make_container_class( $caller, @parents ); - - my $has = $container_pkg->can('has'); - $has->(@_); - - my $container_meta = $container_pkg->meta(); - for my $meth ( grep { $_ ne 'instance' } $container_meta->get_method_list() ) - { - next if $caller_meta->has_method($meth); - - my $sub = sub { shift; - my $instance = $container_pkg->instance(); - return $instance->$meth(@_); }; - - $caller_meta->add_method( $meth => $sub ); - } - - return; + return + Moose::Util::MetaRole::apply_metaclass_roles + ( for_class => $p{for_class}, + metaclass_roles => [ 'MooseX::ClassAttribute::Role::Meta::Class' ], + ); } +sub class_has { - # This should probably be an attribute of the metaclass, but that - # would require extending Moose::Meta::Class, which would conflict - # with anything else that wanted to do so as well (we need - # metaclass roles or something). - my %Name; - - sub _make_container_class ## no critic RequireArgUnpacking - { - my $caller = shift; - - return $Name{$caller} if $Name{$caller}; - - my @parents = map { container_class($_) || () } @_; + my $caller = shift; + my $name = shift; + my %options = @_; - my $container_pkg = 'MooseX::ClassAttribute::Container::' . $caller; + my $attrs = ref $name eq 'ARRAY' ? $name : [$name]; - my $code = "package $container_pkg;\n"; - $code .= "use Moose;\n\n"; - - if (@parents) - { - $code .= "extends qw( @parents );\n"; - } - - $code .= <<'EOF'; - -my $Self; -sub instance -{ - return $Self ||= shift->new(@_); + Class::MOP::Class + ->initialize($caller) + ->add_class_attribute( $_, %options ) + for @{ $attrs }; } -EOF - - - eval $code; ## no critic ProhibitStringyEval - die $@ if $@; - - return $Name{$caller} = $container_pkg; - } - - sub container_class - { - my $pkg = shift || caller(); - - return $Name{$pkg}; - } -} - -# This is basically copied from Moose.pm -sub unimport ## no critic RequireFinalReturn -{ - my $caller = caller(); - - no strict 'refs'; ## no critic ProhibitNoStrict - foreach my $name (@EXPORT) - { - if ( defined &{ $caller . '::' . $name } ) - { - my $keyword = \&{ $caller . '::' . $name }; - - my $pkg_name = - eval { svref_2object($keyword)->GV()->STASH()->NAME() }; - - next if $@; - next if $pkg_name ne __PACKAGE__; - - delete ${ $caller . '::' }{$name}; - } - } -} - 1; @@ -138,7 +67,6 @@ MooseX::ClassAttribute - Declare class attributes Moose-style ); __PACKAGE__->meta()->make_immutable(); - MooseX::ClassAttribute::containing_class()->meta()->make_immutable(); no Moose; no MooseX::ClassAttribute; @@ -151,15 +79,14 @@ MooseX::ClassAttribute - Declare class attributes Moose-style =head1 DESCRIPTION This module allows you to declare class attributes in exactly the same -way as you declare object attributes, except using C -instead of C. It is also possible to make these attributes -immutable (and faster) just as you can with normal Moose attributes. +way as object attributes, using C instead of C. You can use any feature of Moose's attribute declarations, including overriding a parent's attributes, delegation (C), and -attribute metaclasses, and it should just work. +attribute metaclasses, and it should just work. The one exception is +the "required" flag, which is not allowed for class attributes. -The accessors methods for class attribute may be called on the class +The accessor methods for class attribute may be called on the class directly, or on objects of that class. Passing a class attribute to the constructor will not set it. @@ -168,24 +95,49 @@ the constructor will not set it. This class exports one function when you use it, C. This works exactly like Moose's C, but it declares class attributes. -Own little nit is that if you include C in your class, you +One little nit is that if you include C in your class, you won't remove the C function. To do that you must include C as well. =head2 Implementation and Immutability -Underneath the hood, this class creates one new class for each class -which has class attributes and sets up delegating methods in the class -for which you're creating class attributes. You don't need to worry -about this too much, except when it comes to making a class immutable. +This module will add a role to your class's metaclass, See +L for details. This role +provides introspection methods for class attributes. + +Class attributes themselves do the +L role. + +There is also a L +which provides part of the inlining implementation for class +attributes. + +=head2 Cooperation with Metaclasses and Traits + +This module should work with most attribute metaclasses and traits, +but it's possible that conflicts could occur. This module has been +tested to work with C. + +=head1 DONATIONS + +If you'd like to thank me for the work I've done on this module, +please consider making a "donation" to me via PayPal. I spend a lot of +free time creating free software, and would appreciate any support +you'd care to offer. -Since the class attributes are not really stored in your class, you -need to make the containing class immutable as well as your own ... +Please note that B in order +for me to continue working on this particular software. I will +continue to do so, inasmuch as I have in the past, for as long as it +interests me. - __PACKAGE__->meta()->make_immutable(); - MooseX::ClassAttribute::containing_class()->meta()->make_immutable(); +Similarly, a donation made in this way will probably not make me work +on this software much more, unless I get so many donations that I can +consider working on free software full time, which seems unlikely at +best. -I +To donate, log into PayPal and send money to autarch@urth.org or use +the button on this page: +L =head1 AUTHOR @@ -200,7 +152,7 @@ automatically be notified of progress on your bug as I make changes. =head1 COPYRIGHT & LICENSE -Copyright 2007 Dave Rolsky, All Rights Reserved. +Copyright 2007-2008 Dave Rolsky, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.