File Coverage

blib/lib/MooseX/XSAccessor/Trait/Attribute.pm
Criterion Covered Total %
statement 45 46 97.8
branch 21 24 87.5
condition 5 6 83.3
subroutine 13 14 92.8
pod 5 5 100.0
total 89 95 93.6


line stmt bran cond sub pod time code
1             package MooseX::XSAccessor::Trait::Attribute;
2              
3 44     44   1108 use 5.008;
  44         167  
4 44     44   235 use strict;
  44         99  
  44         923  
5 44     44   203 use warnings;
  44         88  
  44         1392  
6              
7 44     44   23246 use Class::XSAccessor 1.09 ();
  44         115500  
  44         1537  
8 44     44   375 use Scalar::Util qw(reftype);
  44         124  
  44         2691  
9 44     44   330 use B qw(perlstring);
  44         135  
  44         3106  
10              
11             BEGIN {
12 44     44   199 $MooseX::XSAccessor::Trait::Attribute::AUTHORITY = 'cpan:TOBYINK';
13 44         2704 $MooseX::XSAccessor::Trait::Attribute::VERSION = '0.010';
14             }
15              
16             # Map Moose terminology to Class::XSAccessor options.
17             my %cxsa_opt = (
18             accessor => "accessors",
19             reader => "getters",
20             writer => "setters",
21             );
22              
23             $cxsa_opt{predicate} = "exists_predicates"
24             if Class::XSAccessor->VERSION > 1.16;
25              
26 44     44   16374 use Moose::Role;
  44         181752  
  44         193  
27              
28             sub accessor_is_simple {
29 66     66 1 146 my $self = shift;
30 66 100 100     2570 return !!0 if $self->has_type_constraint && $self->type_constraint ne "Any";
31 31 50       1358 return !!0 if $self->should_coerce;
32 31 100       1354 return !!0 if $self->has_trigger;
33 27 100       1051 return !!0 if $self->is_weak_ref;
34 26 100       1073 return !!0 if $self->is_lazy;
35 24 50       1040 return !!0 if $self->should_auto_deref;
36 24         242 !!1;
37             }
38              
39             sub reader_is_simple {
40 92     92 1 201 my $self = shift;
41 92 100       3330 return !!0 if $self->is_lazy;
42 75 100       3223 return !!0 if $self->should_auto_deref;
43 71         753 !!1;
44             }
45              
46             sub writer_is_simple {
47 14     14 1 37 my $self = shift;
48 14 100 66     604 return !!0 if $self->has_type_constraint && $self->type_constraint ne "Any";
49 9 50       404 return !!0 if $self->should_coerce;
50 9 100       372 return !!0 if $self->has_trigger;
51 8 100       331 return !!0 if $self->is_weak_ref;
52 7         73 !!1;
53             }
54              
55             sub predicate_is_simple {
56 13     13 1 31 my $self = shift;
57 13         36 !!1;
58             }
59              
60             # Class::XSAccessor doesn't do clearers
61             sub clearer_is_simple {
62 0     0 1   !!0;
63             }
64              
65             after install_accessors => sub {
66             my $self = shift;
67              
68             my $slot = $self->name;
69             my $class = $self->associated_class;
70             my $classname = $class->name;
71              
72             # Don't attempt to do anything with instances that are not blessed hashes.
73             my $is_hash = q(HASH) eq reftype( $class->get_meta_instance->create_instance );
74             return unless $is_hash && $class->get_meta_instance->is_inlinable;
75              
76             # Use inlined get method as a heuristic to detect weird shit.
77             my $inline_get = $self->_inline_instance_get( '$X' );
78             return unless $inline_get eq sprintf( '$X->{%s}', perlstring $slot );
79              
80             # Detect use of MooseX::Attribute::Chained
81             my $is_chained = $self->does( 'MooseX::Traits::Attribute::Chained' );
82              
83             # Detect use of MooseX::LvalueAttribute
84             my $is_lvalue = $self->does( 'MooseX::LvalueAttribute::Trait::Attribute' );
85              
86             for my $type ( qw/ accessor reader writer predicate clearer / ) {
87              
88             # Only accelerate methods if CXSA can deal with them
89             next unless exists $cxsa_opt{$type};
90              
91             # Only accelerate methods that exist!
92             next unless $self->${\"has_$type"};
93              
94             # Check to see they're simple (no type constraint checks, etc)
95             next unless $self->${\"$type\_is_simple"};
96              
97             my $methodname = $self->$type;
98             my $metamethod = $class->get_method( $methodname );
99              
100             # Perform the actual acceleration
101             if ( $type eq 'accessor' and $is_lvalue ) {
102             next if $is_chained;
103             next if !$MooseX::XSAccessor::LVALUE;
104              
105             "Class::XSAccessor"->import(
106             class => $classname,
107             replace => 1,
108             lvalue_accessors => +{ $methodname => $slot },
109             );
110             }
111             else {
112             "Class::XSAccessor"->import(
113             class => $classname,
114             replace => 1,
115             chained => $is_chained,
116             $cxsa_opt{$type} => +{ $methodname => $slot },
117             );
118             }
119              
120             # Naughty stuff!!!
121             # We've overwritten a Moose-generated accessor, so now we need to
122             # inform Moose's metathingies about the new coderef.
123             # $metamethod->body is read-only, so dive straight into the blessed
124             # hash.
125 44     44   284181 no strict "refs";
  44         138  
  44         6577  
126             $metamethod->{"body"} = \&{"$classname\::$methodname"};
127             }
128              
129             return;
130             };
131              
132             1;
133              
134             __END__
135              
136             =pod
137              
138             =for stopwords booleans
139              
140             =encoding utf-8
141              
142             =head1 NAME
143              
144             MooseX::XSAccessor::Trait::Attribute - get the Class::XSAccessor effect for a single attribute
145              
146             =head1 SYNOPSIS
147              
148             package MyClass;
149            
150             use Moose;
151            
152             has foo => (
153             traits => ["MooseX::XSAccessor::Trait::Attribute"],
154             ...,
155             );
156            
157             say __PACKAGE__->meta->get_attribute("foo")->accessor_is_simple;
158              
159             =head1 DESCRIPTION
160              
161             Attributes with this trait have the following additional methods, which
162             each return booleans:
163              
164             =over
165              
166             =item C<< accessor_is_simple >>
167              
168             =item C<< reader_is_simple >>
169              
170             =item C<< writer_is_simple >>
171              
172             =item C<< predicate_is_simple >>
173              
174             =item C<< clearer_is_simple >>
175              
176             =back
177              
178             What is meant by simple? Simple enough for L<Class::XSAccessor> to take
179             over the accessor's duties.
180              
181             =head1 BUGS
182              
183             Please report any bugs to
184             L<https://github.com/tobyink/p5-moosex-xsaccessor/issues>.
185              
186             =head1 SEE ALSO
187              
188             L<MooseX::XSAccessor>.
189              
190             =head1 AUTHOR
191              
192             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
193              
194             =head1 COPYRIGHT AND LICENCE
195              
196             This software is copyright (c) 2013, 2022 by Toby Inkster.
197              
198             This is free software; you can redistribute it and/or modify it under
199             the same terms as the Perl 5 programming language system itself.
200              
201             =head1 DISCLAIMER OF WARRANTIES
202              
203             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
204             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
205             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
206