File Coverage

blib/lib/Lexical/Accessor.pm
Criterion Covered Total %
statement 45 51 88.2
branch 21 32 65.6
condition 7 11 63.6
subroutine 12 13 92.3
pod 1 6 16.6
total 86 113 76.1


line stmt bran cond sub pod time code
1 7     7   1188476 use 5.008003;
  7         59  
2 7     7   26 use strict;
  7         11  
  7         108  
3 7     7   23 use warnings;
  7         9  
  7         143  
4 7     7   25 no warnings qw( void once uninitialized );
  7         8  
  7         243  
5              
6              
7             use Carp qw(croak);
8 7     7   27 use Sub::Accessor::Small ();
  7         11  
  7         284  
9 7     7   2174  
  7         16  
  7         2903  
10             our $AUTHORITY = 'cpan:TOBYINK';
11             our $VERSION = '0.014';
12             our @EXPORT = qw/ lexical_has /;
13             our @ISA = qw/ Sub::Accessor::Small /;
14              
15             {
16             my $me = shift;
17             my $code = $me->_generate_has(@_);
18 7     7   685 $code = Sub::Name::subname("$me\::lexical_has", $code)
19 7         28 if Sub::Accessor::Small::HAS_SUB_NAME;
20 7         11 return $code;
21             }
22 7         24  
23             {
24             my $has = $_[0]->can('has');
25             goto $has;
26             }
27 0     0 1 0
28 0         0 {
29             my $me = shift;
30             my ($method_type, $code) = @_;
31             my $coderef = $me->SUPER::inline_to_coderef(@_);
32             Sub::Accessor::Small::HAS_SUB_NAME && $me->{package} && defined($me->{slot})
33 44     44 0 57 ? Sub::Name::subname("$me->{package}\::__LEXICAL__[$me->{slot}]", $coderef)
34 44         61 : $coderef
35 44         101 }
36              
37 44         11802 {
38             return 'lexical';
39             }
40              
41             {
42             my $me = shift;
43 44     44 0 66
44             if ($me->{is} eq 'rw')
45             {
46             $me->{accessor} = \(my $tmp)
47             if !exists($me->{accessor});
48 22     22 0 28 }
49             elsif ($me->{is} eq 'ro')
50 22 100       87 {
    100          
    100          
    100          
51             $me->{reader} = \(my $tmp)
52             if !exists($me->{reader});
53 5 50       17 }
54             elsif ($me->{is} eq 'rwp')
55             {
56             $me->{reader} = \(my $tmp1)
57             if !exists($me->{reader});
58 4 50       12 $me->{writer} = \(my $tmp2)
59             if !exists($me->{writer});
60             }
61             elsif ($me->{is} eq 'lazy')
62             {
63 4 50       30 $me->{reader} = \(my $tmp)
64             if !exists($me->{reader});
65 4 50       20 $me->{lazy} = 1
66             if !exists($me->{lazy});
67             $me->{builder} = 1
68             unless $me->{builder} || $me->{default};
69             }
70 4 50       10 }
71              
72 4 50       14 {
73             my $me = shift;
74 4 50 33     24 $me->SUPER::canonicalize_opts(@_);
75              
76             if (defined $me->{init_arg})
77             {
78             croak("Invalid init_arg=>defined; private attributes cannot be initialized in the constructor");
79             }
80 22     22 0 36
81 22         59 if ($me->{required})
82             {
83 22 50       35 croak("Invalid required=>1; private attributes cannot be initialized in the constructor");
84             }
85 0         0
86             if (defined $me->{lazy} and not $me->{lazy})
87             {
88 22 50       35 croak("Invalid lazy=>0; private attributes cannot be eager");
89             }
90 0         0 else
91             {
92             $me->{lazy} ||= 1 if $me->{default} || $me->{builder};
93 22 50 66     50 }
94            
95 0         0 # for my $type (qw/ reader writer accessor clearer predicate /)
96             # {
97             # if (defined($me->{$type}) and not ref($me->{$type}) eq q(SCALAR))
98             # {
99 22 100 100     96 # croak("Expected $type to be a scalar ref; not '$me->{$type}'");
      66        
100             # }
101             # }
102             }
103              
104             {
105             my $me = shift;
106            
107             if (ref($me->{handles}) eq q(ARRAY))
108             {
109             return @{$me->{handles}};
110             }
111            
112             croak "Expected delegations to be a reference to an array; got $me->{handles}";
113 1     1 0 2 }
114              
115 1 50       35 1;
116              
117 1         3  
  1         5  
118             =pod
119              
120 0           =encoding utf-8
121              
122             =for stopwords benchmarking
123              
124             =head1 NAME
125              
126             Lexical::Accessor - true private attributes for Moose/Moo/Mouse
127              
128             =head1 SYNOPSIS
129              
130             my $accessor = lexical_has identifier => (
131             is => 'rw',
132             isa => Int,
133             default => sub { 0 },
134             );
135            
136             # or...
137             lexical_has identifier => (
138             is => 'rw',
139             isa => Int,
140             default => sub { 0 },
141             accessor => \$accessor,
142             );
143            
144             # later...
145             say $self->$accessor; # says 0
146             $self->$accessor( 1 ); # setter
147             say $self->$accessor; # says 1
148              
149             =head1 DESCRIPTION
150              
151             Lexical::Accessor generates coderefs which can be used as methods to
152             access private attributes for objects.
153              
154             The private attributes are stored inside-out, and do not add any
155             accessors to the class' namespace, so are completely invisible to any
156             outside code, including any subclasses. This gives your attribute
157             complete privacy: subclasses can define a private (or even public)
158             attribute with the same name as your private one and they will not
159             interfere with each other.
160              
161             Private attributes cannot be initialized by L<Moose>/L<Moo>/L<Mouse>
162             constructors, but you can safely initialize them inside a C<BUILD> sub.
163              
164             =head2 Functions
165              
166             =over
167              
168             =item C<< lexical_has $name?, %options >>
169              
170             This module exports a function L<lexical_has> which acts much like
171             Moose's C<has> function, but sets up a private (lexical) attribute
172             instead of a public one.
173              
174             Because lexical attributes are stored inside-out, the C<$name> is
175             completely optional; however a name is recommended because it allows
176             better error messages to be generated.
177              
178             The L<lexical_has> function supports the following options:
179              
180             =over
181              
182             =item C<< is >>
183              
184             Moose/Mouse/Moo-style C<ro>, C<rw>, C<rwp> and C<lazy> values are
185             supported. These control what sort of coderef is returned by the
186             C<lexical_has> function itself.
187              
188             my $reader = lexical_has "foo" => (is => "ro");
189             my $accessor = lexical_has "foo" => (is => "rw");
190             my ($reader, $writer) = lexical_has "foo" => (is => "rwp");
191              
192             If generating more than one method it is probably clearer to pass in
193             scalar references to the C<reader>, C<writer>, etc methods, rather than
194             relying on the return value of the C<lexical_has> function.
195              
196             =item C<< reader >>, C<< writer >>, C<< accessor >>, C<< predicate >>,
197             C<< clearer >>
198              
199             These accept scalar references. The relevant coderefs will be plonked
200             into them:
201              
202             my ($get_foo, $set_foo);
203            
204             lexical_has foo => (
205             reader => \$get_foo,
206             writer => \$set_foo,
207             );
208              
209             They can also be method names as strings:
210              
211             my ($set_foo);
212            
213             lexical_has foo => (
214             reader => 'get_foo',
215             writer => \$set_foo,
216             );
217              
218             This allows you to provide a partly public API for an attribute.
219              
220             =item C<< default >>, C<< builder >>, C<< lazy >>
221              
222             Lazy defaults and builders are allowed. Eager (non-lazy) defaults and
223             builders are currently disallowed. (Use a C<BUILD> sub to set private
224             attribute values at object construction time.)
225              
226             The default may be either a non-reference value, or a coderef which
227             will be called as a method to return the value.
228              
229             Builders probably make less sense than defaults because they require
230             a method in the class' namespace. The builder may be a method name, or
231             the special value C<< '1' >> which will be interpreted as meaning the
232             attribute name prefixed by "_build_". If a coderef is provided, this is
233             automatically installed into the class' namespace with the "_build_"
234             prefix. (This last feature requires L<Sub::Name>.)
235              
236             =item C<< isa >>
237              
238             A type constraint for the attribute. L<Moo>-style coderefs are
239             accepted (including those generated by L<MooX::Types::MooseLike>),
240             as are L<Moose::Meta::TypeConstraint>/L<MooseX::Types> objects,
241             and L<Mouse::Meta::TypeConstraint>/L<MouseX::Types> objects, and
242             of course L<Type::Tiny> type constraints.
243              
244             String type constraints may also be accepted, but only if
245             L<Type::Utils> is installed. (String type constraints are reified
246             using C<dwim_type>.)
247              
248             =item C<< does >>
249              
250             As an alternative to C<isa>, you can provide a role name in the
251             C<does> option.
252              
253             =item C<< coerce >>
254              
255             A coderef or L<Type::Coercion> object is accepted.
256              
257             If the special value C<< '1' >> is provided, the type constraint object
258             is consulted to find the coercion. (This doesn't work for coderef type
259             constraints.)
260              
261             =item C<< trigger >>
262              
263             A method name or coderef to trigger when a new value is set.
264              
265             =item C<< auto_deref >>
266              
267             Boolean indicating whether to automatically dereference array and hash
268             values if called in list context.
269              
270             =item C<< init_arg >>
271              
272             Must be C<undef> if provided at all.
273              
274             =item C<< required >>
275              
276             Must be false if provided at all.
277              
278             =item C<< weak_ref >>
279              
280             Boolean. Makes the setter weaken any references it is called with.
281              
282             =item C<< handles >>
283              
284             Delegates methods. Has slightly different syntax to Moose's option of
285             the same name - is required to be an arrayref of pairs such that in
286             each pair, the first is a scalar ref or a string method name that will
287             be handled, and the second is a coderef or string method name that
288             will do the handling. (The second can be an arrayref in the case of
289             currying.)
290            
291             my ($get, $post);
292            
293             lexical_has ua => (
294             isa => 'HTTP::Tiny',
295             default => sub { 'HTTP::Tiny'->new },
296             handles => [
297             \$get => 'get',
298             \$post => 'post',
299             ],
300             );
301            
302             # later...
303             my $response = $self->$get('http://example.net/');
304              
305             Supports L<Sub::HandlesVia>:
306              
307             my $remove_task;
308             lexical_has tasks => (
309             isa => ArrayRef,
310             handles_via => 'Array',
311             handles => [
312             task_count => 'count',
313             add_task => 'push',
314             next_task => [ 'get', 0 ],
315             \$remove_task => 'unshift',
316             ],
317             );
318            
319             # later...
320             while ($self->task_count) {
321             my $task = $self->next_task;
322             my $success = $self->handle_task($task);
323             if ($success) {
324             $self->$remove_task;
325             }
326             }
327              
328             =item C<< initializer >>, C<< traits >>, C<< lazy_build >>
329              
330             Not currently implemented. Providing any of these options throws an
331             error.
332              
333             =item C<< documentation >>, C<< definition_context >>
334              
335             Don't do anything, but are allowed; effectively inline comments.
336              
337             =back
338              
339             =back
340              
341             =head2 Class Methods
342              
343             =over
344              
345             =item C<< lexical_has >>
346              
347             This function may also be called as a class method.
348              
349             =back
350              
351             =head2 Comparison (benchmarking, etc)
352              
353             Lexical::Accessor is almost three times faster than
354             L<MooX::PrivateAttributes>, and almost twenty time faster than
355             L<MooseX::Privacy>. I'd also argue that it's a more "correct"
356             implementation of private accessors as (short of performing impressive
357             L<PadWalker> manipulations), the accessors generated by this module
358             are completely invisible to subclasses, method dispatch, etc.
359              
360             Compared to the usual Moose convention of using a leading underscore
361             to indicate a private method (which is a very loose convention; it is
362             quite common for subclasses to override such methods!),
363             L<Lexical::Accessor> clearly offers much better method privacy. There
364             should be little performance hit from using lexical accessors compared
365             to normal L<Moose> accessors. (However they are nowhere near the speed
366             of the XS-powered accessors that L<Moo> I<sometimes> uses and L<Mouse>
367             I<usually> uses.)
368              
369             See also: C<< examples/benchmark.pl >> bundled with this release.
370              
371             =head1 BUGS
372              
373             Please report any bugs to
374             L<http://rt.cpan.org/Dist/Display.html?Queue=Lexical-Accessor>.
375              
376             =head1 SUPPORT
377              
378             B<< IRC: >> support is available through in the I<< #moops >> channel
379             on L<irc.perl.org|http://www.irc.perl.org/channels.html>.
380              
381             =head1 SEE ALSO
382              
383             L<MooX::PrivateAttributes>,
384             L<MooX::ProtectedAttributes>,
385             L<MooseX::Privacy>,
386             L<Sub::Private>,
387             L<Method::Lexical>,
388             etc...
389              
390             =head1 AUTHOR
391              
392             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
393              
394             =head1 COPYRIGHT AND LICENCE
395              
396             This software is copyright (c) 2013-2014, 2017 by Toby Inkster.
397              
398             This is free software; you can redistribute it and/or modify it under
399             the same terms as the Perl 5 programming language system itself.
400              
401             =head1 DISCLAIMER OF WARRANTIES
402              
403             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
404             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
405             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
406