X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoo.pm;h=0dfaf8d1040b3ee00166ce6f9c2ec898bdf849c9;hb=c600e70640098ae6ad958dc7a07187464abd37d3;hp=43f826dbfbc5072f640115d9f4f700aaf72d2a2a;hpb=3b4a915aed3f637f76730b52206681aa7e3503cf;p=gitmo%2FMoo.git diff --git a/lib/Moo.pm b/lib/Moo.pm index 43f826d..0dfaf8d 100644 --- a/lib/Moo.pm +++ b/lib/Moo.pm @@ -5,7 +5,7 @@ use Moo::_Utils; use B 'perlstring'; use Sub::Defer (); -our $VERSION = '1.000001'; # 1.0.1 +our $VERSION = '1.003001'; $VERSION = eval $VERSION; require Moo::sification; @@ -22,8 +22,10 @@ sub import { my $target = caller; my $class = shift; strictures->import; - return if $MAKERS{$target}; # already exported into this package - $MAKERS{$target} = {}; + if ($Role::Tiny::INFO{$target} and $Role::Tiny::INFO{$target}{is_role}) { + die "Cannot import Moo into a role"; + } + $MAKERS{$target} ||= {}; _install_tracked $target => extends => sub { $class->_set_superclasses($target, @_); $class->_maybe_reset_handlemoose($target); @@ -35,12 +37,24 @@ sub import { $class->_maybe_reset_handlemoose($target); }; _install_tracked $target => has => sub { - my ($name, %spec) = @_; - $class->_constructor_maker_for($target) - ->register_attribute_specs($name, \%spec); - $class->_accessor_maker_for($target) - ->generate_method($target, $name, \%spec); - $class->_maybe_reset_handlemoose($target); + my $name_proto = shift; + my @name_proto = ref $name_proto eq 'ARRAY' ? @$name_proto : $name_proto; + if (@_ % 2 != 0) { + require Carp; + Carp::croak("Invalid options for " . join(', ', map "'$_'", @name_proto) + . " attribute(s): even number of arguments expected, got " . scalar @_) + } + my %spec = @_; + foreach my $name (@name_proto) { + # Note that when multiple attributes specified, each attribute + # needs a separate \%specs hashref + my $spec_ref = @name_proto > 1 ? +{%spec} : \%spec; + $class->_constructor_maker_for($target) + ->register_attribute_specs($name, $spec_ref); + $class->_accessor_maker_for($target) + ->generate_method($target, $name, $spec_ref); + $class->_maybe_reset_handlemoose($target); + } return; }; foreach my $type (qw(before after around)) { @@ -50,6 +64,8 @@ sub import { return; }; } + return if $MAKERS{$target}{is_class}; # already exported into this package + $MAKERS{$target}{is_class} = 1; { no strict 'refs'; @{"${target}::ISA"} = do { @@ -69,11 +85,11 @@ sub unimport { sub _set_superclasses { my $class = shift; my $target = shift; - for (@_) { - _load_module($_); - if ($INC{"Role/Tiny.pm"} && $Role::Tiny::INFO{$_}) { + foreach my $superclass (@_) { + _load_module($superclass); + if ($INC{"Role/Tiny.pm"} && $Role::Tiny::INFO{$superclass}) { require Carp; - Carp::croak("Can't extend role '$_'"); + Carp::croak("Can't extend role '$superclass'"); } } # Can't do *{...} = \@_ or 5.10.0's mro.pm stops seeing @ISA @@ -83,10 +99,13 @@ sub _set_superclasses { Moo->_constructor_maker_for($target) ->register_attribute_specs(%{$old->all_attribute_specs}); } + elsif (!$target->isa('Moo::Object')) { + Moo->_constructor_maker_for($target); + } no warnings 'once'; # piss off. -- mst $Moo::HandleMoose::MOUSE{$target} = [ grep defined, map Mouse::Util::find_meta($_), @_ - ] if $INC{"Mouse.pm"}; + ] if Mouse::Util->can('find_meta'); } sub _maybe_reset_handlemoose { @@ -102,7 +121,7 @@ sub _accessor_maker_for { $MAKERS{$target}{accessor} ||= do { my $maker_class = do { if (my $m = do { - if (my $defer_target = + if (my $defer_target = (Sub::Defer::defer_info($target->can('new'))||[])->[0] ) { my ($pkg) = ($defer_target =~ /^(.*)::[^:]+$/); @@ -147,7 +166,7 @@ sub _constructor_maker_for { } else { $moo_constructor = 1; # no other constructor, make a Moo one } - }; + } ($con ? ref($con) : 'Method::Generate::Constructor') ->new( package => $target, @@ -155,14 +174,14 @@ sub _constructor_maker_for { construction_string => ( $moo_constructor ? ($con ? $con->construction_string : undef) - : ('$class->'.$target.'::SUPER::new(@_)') + : ('$class->'.$target.'::SUPER::new($class->can(q[FOREIGNBUILDARGS]) ? $class->FOREIGNBUILDARGS(@_) : @_)') ), subconstructor_handler => ( ' if ($Moo::MAKERS{$class}) {'."\n" .' '.$class.'->_constructor_maker_for($class,'.perlstring($target).');'."\n" .' return $class->new(@_)'.";\n" .' } elsif ($INC{"Moose.pm"} and my $meta = Class::MOP::get_metaclass_by_name($class)) {'."\n" - .' return $meta->new_object(@_);'."\n" + .' return $meta->new_object($class->BUILDARGS(@_));'."\n" .' }'."\n" ), ) @@ -172,13 +191,15 @@ sub _constructor_maker_for { } 1; +__END__ + =pod =encoding utf-8 =head1 NAME -Moo - Minimalist Object Orientation (with Moose compatiblity) +Moo - Minimalist Object Orientation (with Moose compatibility) =head1 SYNOPSIS @@ -202,7 +223,7 @@ Moo - Minimalist Object Orientation (with Moose compatiblity) isa => sub { die "Only SWEET-TREATZ supported!" unless $_[0] eq 'SWEET-TREATZ' }, -); + ); has pounds => ( is => 'rw', @@ -234,10 +255,10 @@ thirds of L. Unlike L this module does not aim at full compatibility with L's surface syntax, preferring instead of provide full interoperability -via the metaclass inflation capabilites described in L. +via the metaclass inflation capabilities described in L. For a full list of the minor differences between L and L's surface -syntax, see L. +syntax, see L. =head1 WHY MOO EXISTS @@ -271,6 +292,10 @@ metaclasses for your L and L packages, so you should be able to use them in L code without anybody ever noticing you aren't using L everywhere. +L will also create L for +classes and roles, so that C<< isa => 'MyClass' >> and C<< isa => 'MyRole' >> +work the same as for L classes and roles. + Extending a L class or consuming a L will also work. So will extending a L class or consuming a L - but note @@ -298,6 +323,15 @@ to your code before Moose is loaded, but bear in mind that this switch is currently global and turns the mechanism off entirely so don't put this in library code. +=head1 MOO AND CLASS::XSACCESSOR + +If a new enough version of L is available, it +will be used to generate simple accessors, readers, and writers for +a speed boost. Simple accessors are those without lazy defaults, +type checks/coercions, or triggers. Readers and writers generated +by L will behave slightly differently: they will +reject attempts to call them with the incorrect number of parameters. + =head1 MOO VERSUS ANY::MOOSE L will load L normally, and L in a program using @@ -348,6 +382,13 @@ passed to the constructor. This method should always return a hash reference of named options. +=head2 FOREIGNBUILDARGS + +If you are inheriting from a non-Moo class, the arguments passed to the parent +class constructor can be manipulated by defining a C method. +It will receive the same arguments as C, and should return a list +of arguments to pass to the parent class constructor. + =head2 BUILD Define a C method on your class and the constructor will automatically @@ -405,6 +446,21 @@ class. An error will be raised if these roles have conflicting methods. Declares an attribute for the class. + package Foo; + use Moo; + has 'attr' => ( + is => 'ro' + ); + + package Bar; + use Moo; + extends 'Foo'; + has '+attr' => ( + default => sub { "blah" }, + ); + +Using the C<+> notation, it's possible to override an attribute. + The options for C are as follows: =over 2 @@ -420,7 +476,9 @@ C generates a reader like C, but also sets C to 1 and C to C<_build_${attribute_name}> to allow on-demand generated attributes. This feature was my attempt to fix my incompetence when originally designing C, and is also implemented by -L. +L. There is, however, nothing to stop you +using C and C yourself with C or C - it's just that +this isn't generally a good idea so we don't provide a shortcut for it. C generates a reader like C, but also sets C to C<_set_${attribute_name}> for attributes that are designed to be written @@ -440,6 +498,9 @@ one should do die "$_[0] is not a number!" unless looks_like_number $_[0] }, +Note that the return value is ignored, only whether the sub lives or +dies matters. + L Since L does B run the C check before C if a coercion @@ -470,7 +531,7 @@ Takes a coderef which is meant to coerce the attribute. The basic idea is to do something like the following: coerce => sub { - $_[0] + 1 unless $_[0] % 2 + $_[0] % 2 ? $_[0] : $_[0] + 1 }, Note that L will always fire your coercion: this is to permit @@ -499,11 +560,11 @@ Takes a hashref un => 'one', } -=item * trigger +=item * C Takes a coderef which will get called any time the attribute is set. This -includes the constructor. Coderef will be invoked against the object with the -new value as an argument. +includes the constructor, but not default or built values. Coderef will be +invoked against the object with the new value as an argument. If you set this to just C<1>, it generates a trigger which calls the C<_trigger_${attr_name}> method on C<$self>. This feature comes from @@ -521,6 +582,10 @@ to populate an attribute if no value is supplied to the constructor - or if the attribute is lazy, when the attribute is first retrieved if no value has yet been provided. +If a simple scalar is provided, it will be inlined as a string. Any non-code +reference (hash, array) will result in an error - for that case instead use +a code reference that returns the desired value. + Note that if your default is fired during new() there is no guarantee that other attributes have been populated yet so you should not rely on their existence. @@ -533,7 +598,7 @@ Takes a method name which will return true if an attribute has a value. If you set this to just C<1>, the predicate is automatically named C if your attribute's name does not start with an -underscore, or <_has_${attr_name_without_the_underscore}> if it does. +underscore, or C<_has_${attr_name_without_the_underscore}> if it does. This feature comes from L. =item * C @@ -547,8 +612,14 @@ Moo will call $self->$builder; -If you set this to just C<1>, the predicate is automatically named -C<_build_${attr_name}>. This feature comes from L. +The following features come from L: + +If you set this to just C<1>, the builder is automatically named +C<_build_${attr_name}>. + +If you set this to a coderef or code-convertible object, that variable will be +installed under C<$class::_build_${attr_name}> and the builder set to the same +name. =item * C @@ -594,6 +665,13 @@ common use of this is to make an underscored attribute have a non-underscored initialization name. C means that passing the value in on instantiation is ignored. +=item * C + +Takes either a coderef or array of coderefs which is meant to transform the +given attributes specifications if necessary when upgrading to a Moose role or +class. You shouldn't need this by default, but is provided as a means of +possible extensibility. + =back =head2 before @@ -671,7 +749,7 @@ API will encourage the use of other type systems as well, since it's probably the weakest part of Moose design-wise. C is not supported in core since the author considers it to be a -bad idea but may be supported by an extension in future. Meanwhile C or +bad idea and Moose best practices recommend avoiding it. Meanwhile C or C are more likely to be able to fulfill your needs. There is no meta object. If you need this level of complexity you wanted @@ -702,13 +780,15 @@ The C method is not provided by default. The author suggests loading L into C (via C for example) and using C<$obj-E$::Dwarn()> instead. -L only supports coderefs, because doing otherwise is usually a -mistake anyway. +L only supports coderefs and plain scalars, because passing a hash +or array reference as a default is almost always incorrect since the value is +then shared between all objects using that default. C is not supported; you are instead encouraged to use the C<< is => 'lazy' >> option supported by L and L. -C is not supported since the author considers it a bad idea. +C is not supported since the author considers it a bad idea and +it has been considered best practice to avoid it for some time. C will show up in a L metaclass created from your class but is otherwise ignored. Then again, L ignores it as well, so this @@ -754,14 +834,27 @@ Finally, Moose requires you to call at the end of your class to get an inlined (i.e. not horribly slow) constructor. Moo does it automatically the first time ->new is called -on your class. +on your class. (C is a no-op in Moo to ease migration.) + +An extension L exists to ease translating Moose packages +to Moo by providing a more Moose-like interface. =head1 SUPPORT Users' IRC: #moose on irc.perl.org +=for html (click for instant chatroom login) + Development and contribution IRC: #web-simple on irc.perl.org +=for html (click for instant chatroom login) + +Bugtracker: L + +Git repository: L + +Git web access: L + =head1 AUTHOR mst - Matt S. Trout (cpan:MSTROUT) @@ -790,6 +883,12 @@ Mithaldu - Christian Walde (cpan:MITHALDU) ilmari - Dagfinn Ilmari Mannsåker (cpan:ILMARI) +tobyink - Toby Inkster (cpan:TOBYINK) + +haarg - Graham Knop (cpan:HAARG) + +mattp - Matt Phillips (cpan:MATTP) + =head1 COPYRIGHT Copyright (c) 2010-2011 the Moo L and L @@ -798,6 +897,6 @@ as listed above. =head1 LICENSE This library is free software and may be distributed under the same terms -as perl itself. +as perl itself. See L. =cut