Commit | Line | Data |
5447ee45 |
1 | package MooseX::UndefTolerant; |
5447ee45 |
2 | |
3 | use Moose qw(); |
4 | use Moose::Exporter; |
5447ee45 |
5 | |
6 | use MooseX::UndefTolerant::Attribute; |
d6ce838b |
7 | use MooseX::UndefTolerant::Class; |
2d1c57bd |
8 | use MooseX::UndefTolerant::Constructor; |
5447ee45 |
9 | |
5447ee45 |
10 | |
fff0a09d |
11 | my %metaroles = ( |
12 | class_metaroles => { |
13 | attribute => [ 'MooseX::UndefTolerant::Attribute' ], |
14 | } |
15 | ); |
d6ce838b |
16 | if ( $Moose::VERSION < 1.9900 ) { |
fff0a09d |
17 | $metaroles{class_metaroles}{constructor} = [ |
18 | 'MooseX::UndefTolerant::Constructor', |
19 | ]; |
d6ce838b |
20 | } |
21 | else { |
fff0a09d |
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 | }; |
d6ce838b |
39 | } |
40 | |
41 | |
fff0a09d |
42 | Moose::Exporter->setup_import_methods(%metaroles); |
5447ee45 |
43 | |
44 | 1; |
45 | |
b2c5b43c |
46 | # ABSTRACT: Make your attribute(s) tolerant to undef initialization |
5447ee45 |
47 | |
b2c5b43c |
48 | __END__ |
5447ee45 |
49 | |
50 | =head1 SYNOPSIS |
51 | |
19258058 |
52 | package My::Class; |
5447ee45 |
53 | |
19258058 |
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 |
94f9d198 |
87 | the attributes they will not be initialized, effectively behaving as if you |
19258058 |
88 | had not provided a value at all. |
89 | |
1686337d |
90 | You can also apply the 'UndefTolerant' trait to individual attributes. See |
793ea91a |
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 | |
19258058 |
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)) { |
1cbb963b |
121 | $class = My:Class->new(foo => $foo, bar => 123); |
19258058 |
122 | } else { |
1cbb963b |
123 | $class = My:Class->new(bar => 123); |
19258058 |
124 | } |
125 | |
c5dd383b |
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 |
19258058 |
128 | example: have your cake and eat it too! |
129 | |
130 | =head1 PER ATTRIBUTE |
5447ee45 |
131 | |
1cbb963b |
132 | See L<MooseX::UndefTolerant::Attribute>. |
133 | |
94f9d198 |
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 | |
5447ee45 |
142 | =head1 ACKNOWLEDGEMENTS |
143 | |
19258058 |
144 | Many thanks to the crew in #moose who talked me through this module: |
145 | |
5447ee45 |
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 | |
5447ee45 |
158 | =cut |