this gives class attributes to the metaclass, which isn't what we want
[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.09
22
23 =cut
24
25 our $VERSION = '0.09';
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 $current_val if defined $current_val;
64
65         return 1 if $self->type_constraint && $self->type_constraint->has_coercion;
66         return 0;
67     };
68
69     package MooseX::AlwaysCoerce::Role::Meta::Class;
70     use namespace::autoclean;
71     use Moose::Role;
72     use Moose::Util::TypeConstraints;
73
74     around add_class_attribute => sub {
75         my $next = shift;
76         my $self = shift;
77         my ($what, %opts) = @_;
78
79         if (exists $opts{isa}) {
80             my $type = Moose::Util::TypeConstraints::find_or_parse_type_constraint($opts{isa});
81             $opts{coerce} = 1 if not exists $opts{coerce} and $type->has_coercion;
82         }
83
84         $self->$next($what, %opts);
85     };
86 }
87
88 my (undef, undef, $init_meta) = Moose::Exporter->build_import_methods(
89
90     install => [ qw(import unimport) ],
91
92     class_metaroles => {
93         attribute   => ['MooseX::AlwaysCoerce::Role::Meta::Attribute'],
94         class       => ['MooseX::AlwaysCoerce::Role::Meta::Class'],
95     },
96
97     role_metaroles => {
98         # applied_attribute should be available soon, for now roles are borked
99         # applied_attribute   => ['MooseX::AlwaysCoerce::Role::Meta::Attribute'],
100         role                => ['MooseX::AlwaysCoerce::Role::Meta::Class'],
101     }
102 );
103
104 sub init_meta {
105     my ($class, %options) = @_;
106     my $for_class = $options{for_class};
107
108     MooseX::ClassAttribute->import({ into => $for_class });
109
110     # call generated method to do the rest of the work.
111     goto $init_meta;
112 }
113
114 =head1 AUTHOR
115
116 Rafael Kitover, C<< <rkitover at cpan.org> >>
117
118 =head1 CONTRIBUTORS
119
120 Schwern: Michael G. Schwern <mschwern@cpan.org>
121 Ether: Karen Etheridge <ether@cpan.org>
122
123 =head1 BUGS
124
125 Please report any bugs or feature requests to C<bug-moosex-alwayscoerce at rt.cpan.org>, or through
126 the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=MooseX-AlwaysCoerce>.  I will be notified, and then you'll
127 automatically be notified of progress on your bug as I make changes.
128
129 =head1 SUPPORT
130
131 You can find more information at:
132
133 =over 4
134
135 =item * RT: CPAN's request tracker
136
137 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=MooseX-AlwaysCoerce>
138
139 =item * AnnoCPAN: Annotated CPAN documentation
140
141 L<http://annocpan.org/dist/MooseX-AlwaysCoerce>
142
143 =item * CPAN Ratings
144
145 L<http://cpanratings.perl.org/d/MooseX-AlwaysCoerce>
146
147 =item * Search CPAN
148
149 L<http://search.cpan.org/dist/MooseX-AlwaysCoerce/>
150
151 =back
152
153 =head1 ACKNOWLEDGEMENTS
154
155 My own stupidity, for inspiring me to write this module.
156
157 Dave Rolsky, for telling me how to do it the L<Moose> way.
158
159 =head1 COPYRIGHT & LICENSE
160
161 Copyright (c) 2009-2010 Rafael Kitover
162
163 This program is free software; you can redistribute it and/or modify it
164 under the same terms as Perl itself.
165
166 =cut
167
168 1; # End of MooseX::AlwaysCoerce
169 # vim:et sts=4 sw=4 tw=0: