fix for class attributes in roles
[gitmo/MooseX-AlwaysCoerce.git] / lib / MooseX / AlwaysCoerce.pm
1 package MooseX::AlwaysCoerce;
2
3 use strict;
4 use warnings;
5
6 use namespace::autoclean;
7 use Moose ();
8 use MooseX::ClassAttribute ();
9 use Moose::Exporter;
10 use Moose::Util::MetaRole;
11 use Carp;
12
13 Moose::Exporter->setup_import_methods;
14
15 =head1 NAME
16
17 MooseX::AlwaysCoerce - Automatically enable coercions for Moose attributes
18
19 =head1 VERSION
20
21 Version 0.07
22
23 =cut
24
25 our $VERSION = '0.07';
26
27 =head1 SYNOPSIS
28
29     package MyClass;
30
31     use Moose;
32     use MooseX::AlwaysCoerce;
33     use MyTypeLib 'SomeType';
34
35     has foo => (is => 'rw', isa => SomeType); # coerce => 1 automatically added
36
37     # same, MooseX::ClassAttribute is automatically applied
38     class_has bar => (is => 'rw', isa => SomeType);
39
40 =head1 DESCRIPTION
41
42 Have you ever spent an hour or more trying to figure out "WTF, why did my
43 coercion not run?" only to find out that you forgot C<< coerce => 1 >> ?
44
45 Just load this module in your L<Moose> class and C<< coerce => 1 >> will be
46 enabled for every attribute and class attribute automatically.
47
48 Use C<< coerce => 0 >> to disable a coercion explicitly.
49
50 =cut
51
52 {
53     package MooseX::AlwaysCoerce::Role::Meta::Attribute;
54     use namespace::autoclean;
55     use Moose::Role;
56
57     around should_coerce => sub {
58         my $orig = shift;
59         my $self = shift;
60
61         my $current_val = $self->$orig(@_);
62
63         return 0 if defined $current_val && $current_val == 0;
64         return 1 if $self->type_constraint->has_coercion;
65         return 0;
66     };
67
68     package MooseX::AlwaysCoerce::Role::Meta::Class;
69     use namespace::autoclean;
70     use Moose::Role;
71     use Moose::Util::TypeConstraints;
72     use MooseX::ClassAttribute;
73
74     around add_class_attribute => sub {
75         my $next = shift;
76         my $self = shift;
77         my ($what, %opts) = @_;
78
79         my $type = Moose::Util::TypeConstraints::find_or_parse_type_constraint($opts{isa});
80         $opts{coerce} = 1 if !exists $opts{coerce} and $type->has_coercion;
81
82         $self->$next($what, %opts);
83     };
84 }
85
86 my (undef, undef, $init_meta) = Moose::Exporter->build_import_methods(
87
88     install => [ qw(import unimport) ],
89
90     class_metaroles => {
91         attribute   => ['MooseX::AlwaysCoerce::Role::Meta::Attribute'],
92         class       => ['MooseX::AlwaysCoerce::Role::Meta::Class'],
93     },
94
95     role_metaroles => {
96         # applied_attribute should be available soon, for now roles are borked
97         # applied_attribute   => ['MooseX::AlwaysCoerce::Role::Meta::Attribute'],
98         role                => ['MooseX::AlwaysCoerce::Role::Meta::Class'],
99     }
100 );
101
102 sub init_meta {
103     my ($class, %options) = @_;
104     my $for_class = $options{for_class};
105
106     MooseX::ClassAttribute->import({ into => $for_class });
107
108     # call generated method to do the rest of the work.
109     goto $init_meta;
110 }
111
112 =head1 AUTHOR
113
114 Rafael Kitover, C<< <rkitover at cpan.org> >>
115
116 =head1 CONTRIBUTORS
117
118 Schwern: Michael G. Schwern <mschwern@cpan.org>
119 Ether: Karen Etheridge <ether@cpan.org>
120
121 =head1 BUGS
122
123 Please report any bugs or feature requests to C<bug-moosex-alwayscoerce at rt.cpan.org>, or through
124 the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=MooseX-AlwaysCoerce>.  I will be notified, and then you'll
125 automatically be notified of progress on your bug as I make changes.
126
127 =head1 SUPPORT
128
129 You can find more information at:
130
131 =over 4
132
133 =item * RT: CPAN's request tracker
134
135 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=MooseX-AlwaysCoerce>
136
137 =item * AnnoCPAN: Annotated CPAN documentation
138
139 L<http://annocpan.org/dist/MooseX-AlwaysCoerce>
140
141 =item * CPAN Ratings
142
143 L<http://cpanratings.perl.org/d/MooseX-AlwaysCoerce>
144
145 =item * Search CPAN
146
147 L<http://search.cpan.org/dist/MooseX-AlwaysCoerce/>
148
149 =back
150
151 =head1 ACKNOWLEDGEMENTS
152
153 My own stupidity, for inspiring me to write this module.
154
155 Dave Rolsky, for telling me how to do it the L<Moose> way.
156
157 =head1 COPYRIGHT & LICENSE
158
159 Copyright (c) 2009-2010 Rafael Kitover
160
161 This program is free software; you can redistribute it and/or modify it
162 under the same terms as Perl itself.
163
164 =cut
165
166 1; # End of MooseX::AlwaysCoerce