X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FMooseX-UndefTolerant.git;a=blobdiff_plain;f=lib%2FMooseX%2FUndefTolerant.pm;h=1d5054ef708ab6c0281f85b2fd68a26f47755c12;hp=419a7b435893d8c85a83b2f9017a7483a62f3167;hb=bd7aab04aceda77a0bef5ac5a42ec052e63a1648;hpb=5447ee457d5fd503926799cb8efb8552bdb4764d diff --git a/lib/MooseX/UndefTolerant.pm b/lib/MooseX/UndefTolerant.pm index 419a7b4..1d5054e 100644 --- a/lib/MooseX/UndefTolerant.pm +++ b/lib/MooseX/UndefTolerant.pm @@ -1,47 +1,154 @@ package MooseX::UndefTolerant; + use strict; use warnings; -use Moose qw(); +use Moose 0.89 qw(); use Moose::Exporter; -use Moose::Util::MetaRole; use MooseX::UndefTolerant::Attribute; +use MooseX::UndefTolerant::Class; +use MooseX::UndefTolerant::Constructor; + + +my %metaroles = ( + class_metaroles => { + attribute => [ 'MooseX::UndefTolerant::Attribute' ], + } +); +if ( $Moose::VERSION < 1.9900 ) { + $metaroles{class_metaroles}{constructor} = [ + 'MooseX::UndefTolerant::Constructor', + ]; +} +else { + $metaroles{class_metaroles}{class} = [ + 'MooseX::UndefTolerant::Class', + ]; + $metaroles{role_metaroles} = { + applied_attribute => [ + 'MooseX::UndefTolerant::Attribute', + ], + role => [ + 'MooseX::UndefTolerant::Role', + ], + application_to_class => [ + 'MooseX::UndefTolerant::ApplicationToClass', + ], + application_to_role => [ + 'MooseX::UndefTolerant::ApplicationToRole', + ], + }; +} -our $VERSION = '0.01'; -Moose::Exporter->setup_import_methods(); +Moose::Exporter->setup_import_methods(%metaroles); -sub init_meta { - my (undef, %options) = @_; +1; - Moose->init_meta(%options); +# ABSTRACT: Make your attribute(s) tolerant to undef initialization - return Moose::Util::MetaRole::apply_metaclass_roles( - for_class => $options{for_class}, - attribute_metaclass_roles => [ 'MooseX::UndefTolerant::Attribute' ] - ); -} +__END__ -1; +=head1 SYNOPSIS -__END__ + package My::Class; -=head1 NAME + use Moose; + use MooseX::UndefTolerant; -MooseX::Attribute::UndefTolerant - The great new MooseX::Attribute::UndefTolerant! + has 'name' => ( + is => 'ro', + isa => 'Str', + predicate => 'has_name' + ); -=head1 SYNOPSIS + # Meanwhile, under the city... + + # Doesn't explode + my $class = My::Class->new(name => undef); + $class->has_name # False! + +Or, if you only want one attribute to have this behaviour: + + package My:Class; + use Moose; + + use MooseX::UndefTolerant::Attribute; + + has 'bar' => ( + traits => [ qw(MooseX::UndefTolerant::Attribute)], + is => 'ro', + isa => 'Num', + predicate => 'has_bar' + ); + +=head1 DESCRIPTION + +Loading this module in your L class makes initialization of your +attributes tolerant of undef. If you specify the value of undef to any of +the attributes they will not be initialized, effectively behaving as if you +had not provided a value at all. + +You can also apply the 'UndefTolerant' trait to individual attributes. See +L for details. - use MooseX::Attribute::UndefTolerant; +There will be no change in behaviour to any attribute with a type constraint +that accepts undef values (for example C types), as it is presumed that +since the type is already "undef tolerant", there is no need to avoid +initializing the attribute value with C. +As of Moose 1.9900, this module can also be used in a role, in which case all +of that role's attributes will be undef-tolerant. -=head1 AUTHOR +=head1 MOTIVATION -Cory G Watson, C<< >> +I often found myself in this quandry: + + package My:Class; + use Moose; + + has 'foo' => ( + is => 'ro', + isa => 'Str', + ); + + # ... then + + my $foo = ... # get the param from something + + my $class = My:Class->new(foo => $foo, bar => 123); + +What if foo is undefined? I didn't want to change my attribute to be +Maybe[Str] and I still want my predicate (C) to work. The only +real solution was: + + if(defined($foo)) { + $class = My:Class->new(foo => $foo, bar => 123); + } else { + $class = My:Class->new(bar => 123); + } + +Or some type of codemulch using ternary conditionals. This module allows you +to make your attributes more tolerant of undef so that you can keep the first +example: have your cake and eat it too! + +=head1 PER ATTRIBUTE + +See L. + +=head1 CAVEATS + +This extension does not currently work in immutable classes when applying the +trait to some (but not all) attributes in the class. This is because the +inlined constructor initialization code currently lives in +L, not L. The good news is that +this is expected to be changing shortly. =head1 ACKNOWLEDGEMENTS +Many thanks to the crew in #moose who talked me through this module: + Hans Dieter Pearcey (confound) Jesse Luehrs (doy) @@ -54,15 +161,4 @@ Jay Shirley (jshirley) Mike Eldridge (diz) -=head1 COPYRIGHT & LICENSE - -Copyright 2009 Cory G Watson. - -This program is free software; you can redistribute it and/or modify it -under the terms of either: the GNU General Public License as published -by the Free Software Foundation; or the Artistic License. - -See http://dev.perl.org/licenses/ for more information. - - =cut