File Coverage

blib/lib/MooX/ClassAttribute.pm
Criterion Covered Total %
statement 58 59 98.3
branch 6 8 75.0
condition 2 5 40.0
subroutine 19 19 100.0
pod n/a
total 85 91 93.4


line stmt bran cond sub pod time code
1             package MooX::ClassAttribute;
2              
3 5     14   296094 use 5.008;
  5         26  
  5         214  
4 5     8   32 use strict;
  5         11  
  5         171  
5 5     5   27 use warnings;
  5         17  
  5         296  
6              
7             BEGIN {
8 5     5   13 $MooX::ClassAttribute::AUTHORITY = 'cpan:TOBYINK';
9 5         120 $MooX::ClassAttribute::VERSION = '0.010';
10             }
11              
12 5     5   36 use Carp;
  5         8  
  5         505  
13 5     5   1856 use Moo ();
  5         3985  
  5         100  
14 5     5   3710 use Moo::Role ();
  5         33792  
  5         131  
15 5     5   4139 use MooX::CaptainHook qw( on_application on_inflation is_role );
  5         16  
  5         48  
16              
17 5     5   850 BEGIN { *ROLE = \%Role::Tiny::INFO }
18             our %ROLE;
19 5     5   257 BEGIN { *CLASS = \%Moo::MAKERS }
20             our %CLASS;
21             our %ATTRIBUTES;
22              
23             sub import
24             {
25 10     10   6228 my $me = shift;
26 10         24 my $target = caller;
27            
28 10         11 my $install_tracked;
29             {
30 5     5   28 no warnings;
  5         9  
  5         2474  
  10         13  
31 10 100       38 if ($CLASS{$target})
    50          
32             {
33 6         11 $install_tracked = \&Moo::_install_tracked;
34             }
35             elsif ($ROLE{$target})
36             {
37 4         9 $install_tracked = \&Moo::Role::_install_tracked;
38             }
39             else
40             {
41 0         0 croak "MooX::ClassAttribute applied to a non-Moo package"
42             . "(need: use Moo or use Moo::Role)";
43             }
44             }
45              
46 10         31 my $is_role = is_role($target);
47            
48             $install_tracked->(
49             $target, class_has => sub
50             {
51 9     9   378777 my ($proto, %spec) = @_;
        9      
52 9 50       47 for my $name (ref $proto ? @$proto : $proto)
53             {
54 9         42 my $spec = +{ %spec }; # shallow clone
55 9 100       108 $is_role
56             ? $me->_process_for_role($target, $name, $spec)
57             : $me->_class_accessor_maker_for($target)->generate_method($target, $name, $spec);
58 9   50     42 push @{$ATTRIBUTES{$target}||=[]}, $name, $spec;
  9         79  
59             }
60 9         43 return;
61             },
62 10         75 );
63            
64 10         303 $me->_setup_inflation($target);
65             }
66              
67             sub _process_for_role
68             {
69 4     4   13 my ($me, $target, $name, $spec) = @_;
70             on_application {
71 4     4   9 my $applied_to = $_;
72 4         25 $me
73             -> _class_accessor_maker_for($applied_to)
74             -> generate_method($applied_to, $name, $spec);
75 4         41 } $target;
76 4         29 'Moo::Role'->_maybe_reset_handlemoose($target);
77             }
78              
79             sub _class_accessor_maker_for
80             {
81 9     9   23 my ($me, $target) = @_;
82 9   33     63 $CLASS{$target}{class_accessor} ||= do {
83 9         5043 require Method::Generate::ClassAccessor;
84 9         104 'Method::Generate::ClassAccessor'->new;
85             };
86             }
87              
88             sub _setup_inflation
89             {
90 10     10   16 my ($me, $target) = @_;
91             on_inflation {
92 14     14   3540 require MooX::ClassAttribute::HandleMoose;
93 14         105 $me->_on_inflation($target, @_)
94 10         56 } $target;
95             }
96              
97             1;
98              
99             __END__
100              
101             =head1 NAME
102              
103             MooX::ClassAttribute - declare class attributes Moose-style... but without Moose
104              
105             =head1 SYNOPSIS
106              
107             {
108             package Foo;
109             use Moo;
110             use MooX::ClassAttribute;
111             class_has ua => (
112             is => 'rw',
113             default => sub { LWP::UserAgent->new },
114             );
115             }
116            
117             my $r = Foo->ua->get("http://www.example.com/");
118              
119             =head1 DESCRIPTION
120              
121             This module adds support for class attributes to L<Moo>. Class attributes
122             are attributes whose values are not associated with any particular instance
123             of the class.
124              
125             For example, the C<Person> class might have a class attribute "binomial_name";
126             its value "Homo sapiens" is not associated with any particular individual, but
127             the class as a whole.
128              
129             say Person->binomial_name; # "Homo sapiens"
130             my $bob = Person->new;
131             say $bob->binomial_name; # "Homo sapiens"
132            
133             my $alice = Person->new;
134             $alice->binomial_name("H. sapiens");
135             say $bob->binomial_name; # "H. sapiens"
136              
137             Class attributes may be defined in roles, however they cannot be called as
138             methods using the role package name. Instead the role must be composed with
139             a class; the class attributes will be installed into that class.
140              
141             This module mostly tries to behave like L<MooseX::ClassAttribute>.
142              
143             =head1 CAVEATS
144              
145             =over
146              
147             =item *
148              
149             Overriding class attributes and their accessors in subclasses is not yet
150             supported. The implementation, and expected behaviour hasn't been figured
151             out yet.
152              
153             =item *
154              
155             When Moo classes are inflated to Moose classes, this module will I<attempt>
156             to load MooseX::ClassAttribute, and use that to provide class attribute
157             meta objects.
158              
159             If MooseX::ClassAttribute cannot be loaded, a loud warning will be printed,
160             and the inflation will fall back to representing class attribute accessors
161             as plain old class methods.
162              
163             =item *
164              
165             This module uses some pretty experimental techniques, especially to handle
166             inflation. There are probably all sorts of bugs lurking. Don't let that
167             scare you though; I'm usually pretty quick to fix bugs once they're reported.
168             ;-)
169              
170             =back
171              
172             =head1 BUGS
173              
174             Please report any bugs to
175             L<http://rt.cpan.org/Dist/Display.html?Queue=MooX-ClassAttribute>.
176              
177             See also: L<Method::Generate::ClassAccessor/CAVEATS>.
178              
179             =head1 SEE ALSO
180              
181             L<Moo>,
182             L<MooseX::ClassAttribute>.
183              
184             =head1 AUTHOR
185              
186             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
187              
188             =head1 COPYRIGHT AND LICENCE
189              
190             This software is copyright (c) 2013 by Toby Inkster.
191              
192             This is free software; you can redistribute it and/or modify it under
193             the same terms as the Perl 5 programming language system itself.
194              
195             =head1 DISCLAIMER OF WARRANTIES
196              
197             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
198             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
199             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
200