clean undef-tolerant and undefined args in BUILDARGS
[gitmo/MooseX-UndefTolerant.git] / lib / MooseX / UndefTolerant.pm
CommitLineData
5447ee45 1package MooseX::UndefTolerant;
5447ee45 2
02e25b00 3use strict;
4use warnings;
5
5447ee45 6use Moose qw();
7use Moose::Exporter;
5447ee45 8
9use MooseX::UndefTolerant::Attribute;
d6ce838b 10use MooseX::UndefTolerant::Class;
2d1c57bd 11use MooseX::UndefTolerant::Constructor;
5447ee45 12
5447ee45 13
fff0a09d 14my %metaroles = (
15d56027 15 base_class_roles => [ 'MooseX::UndefTolerant::Object' ],
fff0a09d 16 class_metaroles => {
17 attribute => [ 'MooseX::UndefTolerant::Attribute' ],
18 }
19);
d6ce838b 20if ( $Moose::VERSION < 1.9900 ) {
fff0a09d 21 $metaroles{class_metaroles}{constructor} = [
22 'MooseX::UndefTolerant::Constructor',
23 ];
d6ce838b 24}
25else {
fff0a09d 26 $metaroles{class_metaroles}{class} = [
27 'MooseX::UndefTolerant::Class',
28 ];
29 $metaroles{role_metaroles} = {
30 applied_attribute => [
31 'MooseX::UndefTolerant::Attribute',
32 ],
33 role => [
34 'MooseX::UndefTolerant::Role',
35 ],
36 application_to_class => [
37 'MooseX::UndefTolerant::ApplicationToClass',
38 ],
39 application_to_role => [
40 'MooseX::UndefTolerant::ApplicationToRole',
41 ],
42 };
d6ce838b 43}
44
45
fff0a09d 46Moose::Exporter->setup_import_methods(%metaroles);
5447ee45 47
481;
49
b2c5b43c 50# ABSTRACT: Make your attribute(s) tolerant to undef initialization
5447ee45 51
b2c5b43c 52__END__
5447ee45 53
54=head1 SYNOPSIS
55
19258058 56 package My::Class;
5447ee45 57
19258058 58 use Moose;
59 use MooseX::UndefTolerant;
60
61 has 'name' => (
62 is => 'ro',
63 isa => 'Str',
64 predicate => 'has_name'
65 );
66
67 # Meanwhile, under the city...
68
69 # Doesn't explode
70 my $class = My::Class->new(name => undef);
71 $class->has_name # False!
72
73Or, if you only want one attribute to have this behaviour:
74
75 package My:Class;
76 use Moose;
77
78 use MooseX::UndefTolerant::Attribute;
79
80 has 'bar' => (
81 traits => [ qw(MooseX::UndefTolerant::Attribute)],
82 is => 'ro',
83 isa => 'Num',
84 predicate => 'has_bar'
85 );
86
87=head1 DESCRIPTION
88
89Loading this module in your L<Moose> class makes initialization of your
90attributes tolerant of undef. If you specify the value of undef to any of
94f9d198 91the attributes they will not be initialized, effectively behaving as if you
15d56027 92had not provided a value at all. Such values are also cleaned from BUILDARGS.
19258058 93
1686337d 94You can also apply the 'UndefTolerant' trait to individual attributes. See
793ea91a 95L<MooseX::UndefTolerant::Attribute> for details.
96
97There will be no change in behaviour to any attribute with a type constraint
98that accepts undef values (for example C<Maybe> types), as it is presumed that
99since the type is already "undef tolerant", there is no need to avoid
100initializing the attribute value with C<undef>.
101
2b46c488 102As of Moose 1.9900, this module can also be used in a role, in which case all
103of that role's attributes will be undef-tolerant.
104
19258058 105=head1 MOTIVATION
106
107I often found myself in this quandry:
108
109 package My:Class;
110 use Moose;
111
112 has 'foo' => (
113 is => 'ro',
114 isa => 'Str',
115 );
116
117 # ... then
118
119 my $foo = ... # get the param from something
120
121 my $class = My:Class->new(foo => $foo, bar => 123);
122
123What if foo is undefined? I didn't want to change my attribute to be
124Maybe[Str] and I still want my predicate (C<has_foo>) to work. The only
125real solution was:
126
127 if(defined($foo)) {
1cbb963b 128 $class = My:Class->new(foo => $foo, bar => 123);
19258058 129 } else {
1cbb963b 130 $class = My:Class->new(bar => 123);
19258058 131 }
132
c5dd383b 133Or some type of codemulch using ternary conditionals. This module allows you
134to make your attributes more tolerant of undef so that you can keep the first
19258058 135example: have your cake and eat it too!
136
137=head1 PER ATTRIBUTE
5447ee45 138
1cbb963b 139See L<MooseX::UndefTolerant::Attribute>.
140
94f9d198 141=head1 CAVEATS
142
143This extension does not currently work in immutable classes when applying the
15d56027 144trait to a specific attributes in the class, as opposed to the class itself.
145This is because the inlined constructor initialization code currently lives in
0796f935 146L<Moose::Meta::Class>, not L<Moose::Meta::Attribute>. The good news is that
147this is expected to be changing shortly.
94f9d198 148
15d56027 149Also, BUILDARGS cannot be cleaned up if the entire class is not made undef
150tolerant, as attribute traits cannot modify class constructor behaviour.
151
5447ee45 152=head1 ACKNOWLEDGEMENTS
153
19258058 154Many thanks to the crew in #moose who talked me through this module:
155
5447ee45 156Hans Dieter Pearcey (confound)
157
158Jesse Luehrs (doy)
159
160Tomas Doran (t0m)
161
162Dylan Hardison (dylan)
163
164Jay Shirley (jshirley)
165
166Mike Eldridge (diz)
167
5447ee45 168=cut