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