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