File Coverage

blib/lib/Class/Accessor/Grouped.pm
Criterion Covered Total %
statement 240 245 97.9
branch 72 88 81.8
condition 15 33 45.4
subroutine 86 87 98.8
pod 13 13 100.0
total 426 466 91.4


line stmt bran cond sub pod time code
1             package Class::Accessor::Grouped;
2 14     53   171760 use strict;
  14         34  
  12         344  
3 12     14   48 use warnings;
  12         12  
  12         232  
4 12     12   49 use Carp ();
  12         19  
  12         297  
5 11     11   39 use Scalar::Util ();
  11         13  
  11         127  
6 11     11   4333 use Module::Runtime ();
  11         11949  
  11         564  
7              
8             BEGIN {
9             # use M::R to work around the 5.8 require bugs
10 11 100   11   47 if ($] < 5.009_005) {
11 1         2 Module::Runtime::require_module('MRO::Compat');
12             }
13             else {
14 11         4939 require mro;
15             }
16             }
17              
18             our $VERSION = '0.10012';
19             $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
20              
21             # when changing minimum version don't forget to adjust Makefile.PL as well
22             our $__minimum_xsa_version;
23 11     11   8172 BEGIN { $__minimum_xsa_version = '1.19' }
24              
25             our $USE_XS;
26             # the unless defined is here so that we can override the value
27             # before require/use, *regardless* of the state of $ENV{CAG_USE_XS}
28             $USE_XS = $ENV{CAG_USE_XS}
29             unless defined $USE_XS;
30              
31             BEGIN {
32             package # hide from PAUSE
33             __CAG_ENV__;
34              
35 11 50   11   42 die "Huh?! No minimum C::XSA version?!\n"
36             unless $__minimum_xsa_version;
37              
38 11         42 local $@;
39 11         60 require constant;
40              
41             # individual (one const at a time) imports so we are 5.6.2 compatible
42             # if we can - why not ;)
43 11 50       24 constant->import( NO_SUBNAME => eval {
44 11         52 Module::Runtime::require_module('Sub::Name')
45             } ? 0 : "$@" );
46              
47 11         6965 my $found_cxsa;
48 11   33     52 constant->import( NO_CXSA => ( NO_SUBNAME() || ( eval {
49             Module::Runtime::require_module('Class::XSAccessor');
50             $found_cxsa = Class::XSAccessor->VERSION;
51             Class::XSAccessor->VERSION($__minimum_xsa_version);
52             } ? 0 : "$@" ) ) );
53              
54 11 0 33     188 if (NO_CXSA() and $found_cxsa and !$ENV{CAG_OLD_XS_NOWARN}) {
      33        
55 1         5 warn(
56             'The installed version of Class::XSAccessor is too old '
57             . "(v$found_cxsa < v$__minimum_xsa_version). Please upgrade "
58             . "to instantly quadruple the performance of 'simple' accessors. "
59             . 'Set $ENV{CAG_OLD_XS_NOWARN} if you wish to disable this '
60             . "warning.\n"
61             );
62             }
63              
64 11 50       196 constant->import( BROKEN_GOTO => ($] < '5.008009') ? 1 : 0 );
65              
66 11 50       192 constant->import( UNSTABLE_DOLLARAT => ($] < '5.013002') ? 1 : 0 );
67              
68 11 50 33     889 constant->import( TRACK_UNDEFER_FAIL => (
69             $INC{'Test/Builder.pm'} || $INC{'Test/Builder2.pm'}
70             and
71             $0 =~ m{ ^ (?: \. \/ )? x?t / .+ \.t $}x
72             ) ? 1 : 0 );
73              
74 62     62   164 sub perlstring ($) { q{"}. quotemeta( shift ). q{"} };
75             }
76              
77             # Yes this method is undocumented
78             # Yes it should be a private coderef like all the rest at the end of this file
79             # No we can't do that (yet) because the DBIC-CDBI compat layer overrides it
80             # %$*@!?&!&#*$!!!
81              
82             my $illegal_accessors_warned;
83             sub _mk_group_accessors {
84 85     85   116 my($self, $maker, $group, @fields) = @_;
85 85 100       191 my $class = length (ref ($self) ) ? ref ($self) : $self;
86              
87 11     11   64 no strict 'refs';
  11         38  
  11         264  
88 11     11   39 no warnings 'redefine';
  11         134  
  11         5566  
89              
90             # So we don't have to do lots of lookups inside the loop.
91 85 50       542 $maker = $self->can($maker) unless ref $maker;
92              
93 85         125 for (@fields) {
94              
95 114 100       241 my ($name, $field) = (ref $_) ? (@$_) : ($_, $_);
96              
97 114 100       516 if ($name !~ /\A[A-Z_a-z][0-9A-Z_a-z]*\z/) {
98              
99 4 100 66     22 if ($name =~ /\0/) {
    100          
    100          
100 1         4 Carp::croak(sprintf
101             "Illegal accessor name %s - nulls should never appear in stash keys",
102             __CAG_ENV__::perlstring($name),
103             );
104             }
105             elsif (! $ENV{CAG_ILLEGAL_ACCESSOR_NAME_OK} ) {
106 1         17 Carp::croak(
107             "Illegal accessor name '$name'. If you want CAG to attempt creating "
108             . 'it anyway (possible if Sub::Name is available) set '
109             . '$ENV{CAG_ILLEGAL_ACCESSOR_NAME_OK}'
110             );
111             }
112             elsif (__CAG_ENV__::NO_SUBNAME) {
113             Carp::croak(
114             "Unable to install accessor with illegal name '$name': "
115             . 'Sub::Name not available'
116             );
117             }
118             elsif (
119             # Because one of the former maintainers of DBIC::SL is a raging
120             # idiot, there is now a ton of DBIC code out there that attempts
121             # to create column accessors with illegal names. In the interest
122             # of not cluttering the logs of unsuspecting victims (unsuspecting
123             # because these accessors are unusable anyway) we provide an
124             # explicit "do not warn at all" escape, until all such code is
125             # fixed (this will be a loooooong time >:(
126             $ENV{CAG_ILLEGAL_ACCESSOR_NAME_OK} ne 'DO_NOT_WARN'
127             and
128             ! $illegal_accessors_warned->{$class}++
129             ) {
130 1         13 Carp::carp(
131             "Installing illegal accessor '$name' into $class, see "
132             . 'documentation for more details'
133             );
134             }
135             }
136              
137 112 100       581 Carp::carp("Having a data accessor named '$name' in '$class' is unwise.")
138             if $name =~ /\A(?: DESTROY | AUTOLOAD | CLONE )\z/x;
139              
140 112         2161 my $alias = "_${name}_accessor";
141              
142 112         169 for ($name, $alias) {
143              
144             # the maker may elect to not return anything, meaning it already
145             # installed the coderef for us (e.g. lack of Sub::Name)
146 224 50       366 my $cref = $self->$maker($group, $field, $_)
147             or next;
148              
149 224         389 my $fq_meth = "${class}::$_";
150              
151 224         1632 *$fq_meth = Sub::Name::subname($fq_meth, $cref);
152             #unless defined &{$class."\:\:$field"}
153             }
154             }
155             };
156              
157             # $gen_accessor coderef is setup at the end for clarity
158             my $gen_accessor;
159              
160             =head1 NAME
161              
162             Class::Accessor::Grouped - Lets you build groups of accessors
163              
164             =head1 SYNOPSIS
165              
166             use base 'Class::Accessor::Grouped';
167              
168             # make basic accessors for objects
169             __PACKAGE__->mk_group_accessors(simple => qw(id name email));
170              
171             # make accessor that works for objects and classes
172             __PACKAGE__->mk_group_accessors(inherited => 'awesome_level');
173              
174             # make an accessor which calls a custom pair of getters/setters
175             sub get_column { ... this will be called when you do $obj->name() ... }
176             sub set_column { ... this will be called when you do $obj->name('foo') ... }
177             __PACKAGE__->mk_group_accessors(column => 'name');
178              
179             =head1 DESCRIPTION
180              
181             This class lets you build groups of accessors that will call different
182             getters and setters. The documentation of this module still requires a lot
183             of work (B<< volunteers welcome >.> >>), but in the meantime you can refer to
184             L
185             for more information.
186              
187             =head2 Notes on accessor names
188              
189             In general method names in Perl are considered identifiers, and as such need to
190             conform to the identifier specification of C.
191             While it is rather easy to invoke methods with non-standard names
192             (C<< $obj->${\"anything goes"} >>), it is not possible to properly declare such
193             methods without the use of L. Since this module must be able to
194             function identically with and without its optional dependencies, starting with
195             version C<0.10008> attempting to declare an accessor with a non-standard name
196             is a fatal error (such operations would silently succeed since version
197             C<0.08004>, as long as L is present, or otherwise would result in a
198             syntax error during a string eval).
199              
200             Unfortunately in the years since C<0.08004> a rather large body of code
201             accumulated in the wild that does attempt to declare accessors with funny
202             names. One notable perpetrator is L, which under
203             certain conditions could create accessors of the C group which start
204             with numbers and/or some other punctuation (the proper way would be to declare
205             columns with the C attribute set to C).
206              
207             Therefore an escape mechanism is provided via the environment variable
208             C. When set to a true value, one warning is
209             issued B on attempts to declare an accessor with a non-conforming
210             name, and as long as L is available all accessors will be properly
211             created. Regardless of this setting, accessor names containing nulls C<"\0">
212             are disallowed, due to various deficiencies in perl itself.
213              
214             If your code base has too many instances of illegal accessor declarations, and
215             a fix is not feasible due to time constraints, it is possible to disable the
216             warnings altogether by setting C<$ENV{CAG_ILLEGAL_ACCESSOR_NAME_OK}> to
217             C (observe capitalization).
218              
219             =head1 METHODS
220              
221             =head2 mk_group_accessors
222              
223             __PACKAGE__->mk_group_accessors(simple => 'hair_length', [ hair_color => 'hc' ]);
224              
225             =over 4
226              
227             =item Arguments: $group, @fieldspec
228              
229             Returns: none
230              
231             =back
232              
233             Creates a set of accessors in a given group.
234              
235             $group is the name of the accessor group for the generated accessors; they
236             will call get_$group($field) on get and set_$group($field, $value) on set.
237              
238             If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
239             to tell Class::Accessor::Grouped to use its own get_simple and set_simple
240             methods.
241              
242             @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
243             this is used as both field and accessor name, if a listref it is expected to
244             be of the form [ $accessor, $field ].
245              
246             =cut
247              
248             sub mk_group_accessors {
249 55     55 1 15743 my ($self, $group, @fields) = @_;
250              
251 55         189 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
252 53         100 return;
253             }
254              
255             =head2 mk_group_ro_accessors
256              
257             __PACKAGE__->mk_group_ro_accessors(simple => 'birthdate', [ social_security_number => 'ssn' ]);
258              
259             =over 4
260              
261             =item Arguments: $group, @fieldspec
262              
263             Returns: none
264              
265             =back
266              
267             Creates a set of read only accessors in a given group. Identical to
268             L but accessors will throw an error if passed a value
269             rather than setting the value.
270              
271             =cut
272              
273             sub mk_group_ro_accessors {
274 15     15 1 9440 my($self, $group, @fields) = @_;
275              
276 15         49 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
277 15         31 return;
278             }
279              
280             =head2 mk_group_wo_accessors
281              
282             __PACKAGE__->mk_group_wo_accessors(simple => 'lie', [ subject => 'subj' ]);
283              
284             =over 4
285              
286             =item Arguments: $group, @fieldspec
287              
288             Returns: none
289              
290             =back
291              
292             Creates a set of write only accessors in a given group. Identical to
293             L but accessors will throw an error if not passed a
294             value rather than getting the value.
295              
296             =cut
297              
298             sub mk_group_wo_accessors {
299 15     15 1 5782 my($self, $group, @fields) = @_;
300              
301 15         54 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
302 15         28 return;
303             }
304              
305             =head2 get_simple
306              
307             =over 4
308              
309             =item Arguments: $field
310              
311             Returns: $value
312              
313             =back
314              
315             Simple getter for hash-based objects which returns the value for the field
316             name passed as an argument.
317              
318             =cut
319              
320             sub get_simple {
321 424     424 1 2057 $_[0]->{$_[1]};
322             }
323              
324             =head2 set_simple
325              
326             =over 4
327              
328             =item Arguments: $field, $new_value
329              
330             Returns: $new_value
331              
332             =back
333              
334             Simple setter for hash-based objects which sets and then returns the value
335             for the field name passed as an argument.
336              
337             =cut
338              
339             sub set_simple {
340 143     143 1 815 $_[0]->{$_[1]} = $_[2];
341             }
342              
343              
344             =head2 get_inherited
345              
346             =over 4
347              
348             =item Arguments: $field
349              
350             Returns: $value
351              
352             =back
353              
354             Simple getter for Classes and hash-based objects which returns the value for
355             the field name passed as an argument. This behaves much like
356             L where the field can be set in a base class,
357             inherited and changed in subclasses, and inherited and changed for object
358             instances.
359              
360             =cut
361              
362             sub get_inherited {
363 36 100   36 1 81 if ( length (ref ($_[0]) ) ) {
364 15 100       59 if (Scalar::Util::reftype $_[0] eq 'HASH') {
365 14 100       58 return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
366             # everything in @_ is aliased, an assignment won't work
367 9         22 splice @_, 0, 1, ref($_[0]);
368             }
369             else {
370 1         15 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
371             }
372             }
373              
374             # if we got this far there is nothing in the instance
375             # OR this is a class call
376             # in any case $_[0] contains the class name (see splice above)
377 11     11   46 no strict 'refs';
  11         38  
  11         276  
378 11     11   44 no warnings 'uninitialized';
  11         37  
  11         1707  
379              
380 30         46 my $cag_slot = '::__cag_'. $_[1];
381 30 100       26 return ${$_[0].$cag_slot} if defined(${$_[0].$cag_slot});
  20         82  
  30         99  
382              
383 12 100       10 do { return ${$_.$cag_slot} if defined(${$_.$cag_slot}) }
  4         17  
  12         48  
384 10         37 for $_[0]->get_super_paths;
385              
386 6         23 return undef;
387             }
388              
389             =head2 set_inherited
390              
391             =over 4
392              
393             =item Arguments: $field, $new_value
394              
395             Returns: $new_value
396              
397             =back
398              
399             Simple setter for Classes and hash-based objects which sets and then returns
400             the value for the field name passed as an argument. When called on a hash-based
401             object it will set the appropriate hash key value. When called on a class, it
402             will set a class level variable.
403              
404             B: This method will die if you try to set an object variable on a non
405             hash-based object.
406              
407             =cut
408              
409             sub set_inherited {
410 19 100   19 1 50 if (length (ref ($_[0]) ) ) {
411 6 100       24 if (Scalar::Util::reftype $_[0] eq 'HASH') {
412 5         30 return $_[0]->{$_[1]} = $_[2];
413             } else {
414 1         8 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
415             };
416             }
417              
418 11     11   47 no strict 'refs';
  11         158  
  11         9386  
419 13         10 ${$_[0].'::__cag_'.$_[1]} = $_[2];
  13         49  
420             }
421              
422             =head2 get_component_class
423              
424             =over 4
425              
426             =item Arguments: $field
427              
428             Returns: $value
429              
430             =back
431              
432             Gets the value of the specified component class.
433              
434             __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
435              
436             $self->result_class->method();
437              
438             ## same as
439             $self->get_component_class('result_class')->method();
440              
441             =cut
442              
443             sub get_component_class {
444 5     5 1 14 $_[0]->get_inherited($_[1]);
445             };
446              
447             =head2 set_component_class
448              
449             =over 4
450              
451             =item Arguments: $field, $class
452              
453             Returns: $new_value
454              
455             =back
456              
457             Inherited accessor that automatically loads the specified class before setting
458             it. This method will die if the specified class could not be loaded.
459              
460             __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
461             __PACKAGE__->result_class('MyClass');
462              
463             $self->result_class->method();
464              
465             =cut
466              
467             sub set_component_class {
468 5 100 66 5 1 28 if (defined $_[2] and length $_[2]) {
469             # disable warnings, and prevent $_ being eaten away by a behind-the-scenes
470             # module loading
471 4         11 local ($^W, $_);
472              
473 4         3 if (__CAG_ENV__::UNSTABLE_DOLLARAT) {
474             my $err;
475             {
476             local $@;
477             eval { Module::Runtime::use_package_optimistically($_[2]) }
478             or $err = $@;
479             }
480             Carp::croak("Could not load $_[1] '$_[2]': $err") if defined $err;
481              
482             }
483             else {
484 4 100       4 eval { Module::Runtime::use_package_optimistically($_[2]) }
  4         15  
485             or Carp::croak("Could not load $_[1] '$_[2]': $@");
486             }
487             };
488              
489 4         593 $_[0]->set_inherited($_[1], $_[2]);
490             };
491              
492             =head1 INTERNAL METHODS
493              
494             These methods are documented for clarity, but are never meant to be called
495             directly, and are not really meant for overriding either.
496              
497             =head2 get_super_paths
498              
499             Returns a list of 'parent' or 'super' class names that the current class
500             inherited from. This is what drives the traversal done by L.
501              
502             =cut
503              
504             sub get_super_paths {
505             # get_linear_isa returns the class itself as the 1st element
506             # use @_ as a pre-allocated scratch array
507 10 50   10 1 9 (undef, @_) = @{mro::get_linear_isa( length( ref($_[0]) ) ? ref($_[0]) : $_[0] )};
  10         55  
508 10         27 @_;
509             };
510              
511             =head2 make_group_accessor
512              
513             __PACKAGE__->make_group_accessor('simple', 'hair_length', 'hair_length');
514             __PACKAGE__->make_group_accessor('simple', 'hc', 'hair_color');
515              
516             =over 4
517              
518             =item Arguments: $group, $field, $accessor
519              
520             Returns: \&accessor_coderef ?
521              
522             =back
523              
524             Called by mk_group_accessors for each entry in @fieldspec. Either returns
525             a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
526             C if it elects to install the coderef on its own.
527              
528             =cut
529              
530 140     140 1 211 sub make_group_accessor { $gen_accessor->('rw', @_) }
531              
532             =head2 make_group_ro_accessor
533              
534             __PACKAGE__->make_group_ro_accessor('simple', 'birthdate', 'birthdate');
535             __PACKAGE__->make_group_ro_accessor('simple', 'ssn', 'social_security_number');
536              
537             =over 4
538              
539             =item Arguments: $group, $field, $accessor
540              
541             Returns: \&accessor_coderef ?
542              
543             =back
544              
545             Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
546             a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
547             C if it elects to install the coderef on its own.
548              
549             =cut
550              
551 42     42 1 68 sub make_group_ro_accessor { $gen_accessor->('ro', @_) }
552              
553             =head2 make_group_wo_accessor
554              
555             __PACKAGE__->make_group_wo_accessor('simple', 'lie', 'lie');
556             __PACKAGE__->make_group_wo_accessor('simple', 'subj', 'subject');
557              
558             =over 4
559              
560             =item Arguments: $group, $field, $accessor
561              
562             Returns: \&accessor_coderef ?
563              
564             =back
565              
566             Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
567             a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
568             C if it elects to install the coderef on its own.
569              
570             =cut
571              
572 42     42 1 68 sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
573              
574              
575             =head1 PERFORMANCE
576              
577             To provide total flexibility L calls methods
578             internally while performing get/set actions, which makes it noticeably
579             slower than similar modules. To compensate, this module will automatically
580             use the insanely fast L to generate the C-group
581             accessors if this module is available on your system.
582              
583             =head2 Benchmark
584              
585             This is the benchmark of 200 get/get/set/get/set cycles on perl 5.16.2 with
586             thread support, showcasing how this modules L,
587             L and L
588             (CAG_INHP)|/get_inherited> accessors stack up against most popular accessor
589             builders: L, L, L, L (both pure-perl and XS variant),
590             L,
591             L,
592             L,
593             L,
594             L
595             and L
596              
597             Rate CAG_INHP CAG_INH CA CAG_S CAF moOse OTRW CAL mo moUse HANDMADE moo CAF_XS moUse_XS XSA
598              
599             CAG_INHP 287.021+-0.02/s -- -0.3% -10.0% -37.1% -53.1% -53.6% -53.7% -54.1% -56.9% -59.0% -59.6% -59.8% -78.7% -81.9% -83.5%
600              
601             CAG_INH 288.025+-0.031/s 0.3% -- -9.7% -36.9% -52.9% -53.5% -53.5% -53.9% -56.7% -58.8% -59.5% -59.7% -78.6% -81.9% -83.5%
602              
603             CA 318.967+-0.047/s 11.1% 10.7% -- -30.1% -47.9% -48.5% -48.5% -49.0% -52.1% -54.4% -55.1% -55.3% -76.3% -79.9% -81.7%
604              
605             CAG_S 456.107+-0.054/s 58.9% 58.4% 43.0% -- -25.4% -26.3% -26.4% -27.0% -31.5% -34.8% -35.8% -36.1% -66.1% -71.3% -73.9%
606              
607             CAF 611.745+-0.099/s 113.1% 112.4% 91.8% 34.1% -- -1.2% -1.2% -2.1% -8.1% -12.6% -14.0% -14.3% -54.5% -61.5% -64.9%
608              
609             moOse 619.051+-0.059/s 115.7% 114.9% 94.1% 35.7% 1.2% -- -0.1% -1.0% -7.0% -11.6% -12.9% -13.3% -54.0% -61.0% -64.5%
610              
611             OTRW 619.475+-0.1/s 115.8% 115.1% 94.2% 35.8% 1.3% 0.1% -- -0.9% -6.9% -11.5% -12.9% -13.2% -54.0% -61.0% -64.5%
612              
613             CAL 625.106+-0.085/s 117.8% 117.0% 96.0% 37.1% 2.2% 1.0% 0.9% -- -6.1% -10.7% -12.1% -12.5% -53.5% -60.6% -64.2%
614              
615             mo 665.44+-0.12/s 131.8% 131.0% 108.6% 45.9% 8.8% 7.5% 7.4% 6.5% -- -4.9% -6.4% -6.8% -50.5% -58.1% -61.9%
616              
617             moUse 699.9+-0.15/s 143.9% 143.0% 119.4% 53.5% 14.4% 13.1% 13.0% 12.0% 5.2% -- -1.6% -2.0% -48.0% -55.9% -59.9%
618              
619             HANDMADE 710.98+-0.16/s 147.7% 146.8% 122.9% 55.9% 16.2% 14.9% 14.8% 13.7% 6.8% 1.6% -- -0.4% -47.2% -55.2% -59.2%
620              
621             moo 714.04+-0.13/s 148.8% 147.9% 123.9% 56.6% 16.7% 15.3% 15.3% 14.2% 7.3% 2.0% 0.4% -- -46.9% -55.0% -59.1%
622              
623             CAF_XS 1345.55+-0.051/s 368.8% 367.2% 321.8% 195.0% 120.0% 117.4% 117.2% 115.3% 102.2% 92.2% 89.3% 88.4% -- -15.3% -22.9%
624              
625             moUse_XS 1588+-0.036/s 453.3% 451.3% 397.9% 248.2% 159.6% 156.5% 156.3% 154.0% 138.6% 126.9% 123.4% 122.4% 18.0% -- -9.0%
626              
627             XSA 1744.67+-0.052/s 507.9% 505.7% 447.0% 282.5% 185.2% 181.8% 181.6% 179.1% 162.2% 149.3% 145.4% 144.3% 29.7% 9.9% --
628              
629             Benchmarking program is available in the root of the
630             L:
631              
632             =head2 Notes on Class::XSAccessor
633              
634             You can force (or disable) the use of L before creating a
635             particular C accessor by either manipulating the global variable
636             C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
637             L, or you can do so before runtime via the
638             C environment variable.
639              
640             Since L has no knowledge of L and
641             L this module does its best to detect if you are overriding
642             one of these methods and will fall back to using the perl version of the
643             accessor in order to maintain consistency. However be aware that if you
644             enable use of C (automatically or explicitly), create
645             an object, invoke a simple accessor on that object, and B manipulate
646             the symbol table to install a C override - you get to keep
647             all the pieces.
648              
649             =head1 AUTHORS
650              
651             Matt S. Trout
652              
653             Christopher H. Laco
654              
655             =head1 CONTRIBUTORS
656              
657             Caelum: Rafael Kitover
658              
659             frew: Arthur Axel "fREW" Schmidt
660              
661             groditi: Guillermo Roditi
662              
663             Jason Plum
664              
665             ribasushi: Peter Rabbitson
666              
667              
668             =head1 COPYRIGHT & LICENSE
669              
670             Copyright (c) 2006-2010 Matt S. Trout
671              
672             This program is free software; you can redistribute it and/or modify
673             it under the same terms as perl itself.
674              
675             =cut
676              
677             ########################################################################
678             ########################################################################
679             ########################################################################
680             #
681             # Here be many angry dragons
682             # (all code is in private coderefs since everything inherits CAG)
683             #
684             ########################################################################
685             ########################################################################
686              
687             # Autodetect unless flag supplied
688             my $xsa_autodetected;
689             if (! defined $USE_XS) {
690             $USE_XS = __CAG_ENV__::NO_CXSA ? 0 : 1;
691             $xsa_autodetected++;
692             }
693              
694              
695             my $maker_templates = {
696             rw => {
697             cxsa_call => 'accessors',
698             pp_generator => sub {
699             # my ($group, $fieldname) = @_;
700             my $quoted_fieldname = __CAG_ENV__::perlstring($_[1]);
701             sprintf <<'EOS', ($_[0], $quoted_fieldname) x 2;
702              
703             @_ > 1
704             ? shift->set_%s(%s, @_)
705             : shift->get_%s(%s)
706             EOS
707              
708             },
709             },
710             ro => {
711             cxsa_call => 'getters',
712             pp_generator => sub {
713             # my ($group, $fieldname) = @_;
714             my $quoted_fieldname = __CAG_ENV__::perlstring($_[1]);
715             sprintf <<'EOS', $_[0], $quoted_fieldname;
716              
717             @_ > 1
718             ? do {
719             my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
720             my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
721             Carp::croak(
722             "'$meth' cannot alter its value (read-only attribute of class $class)"
723             );
724             }
725             : shift->get_%s(%s)
726             EOS
727              
728             },
729             },
730             wo => {
731             cxsa_call => 'setters',
732             pp_generator => sub {
733             # my ($group, $fieldname) = @_;
734             my $quoted_fieldname = __CAG_ENV__::perlstring($_[1]);
735             sprintf <<'EOS', $_[0], $quoted_fieldname;
736              
737             @_ > 1
738             ? shift->set_%s(%s, @_)
739             : do {
740             my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
741             my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
742             Carp::croak(
743             "'$meth' cannot access its value (write-only attribute of class $class)"
744             );
745             }
746             EOS
747              
748             },
749             },
750             };
751              
752             my $cag_eval = sub {
753             #my ($src, $no_warnings, $err_msg) = @_;
754              
755             my $src = sprintf "{ %s warnings; use strict; no strict 'refs'; %s }",
756             $_[1] ? 'no' : 'use',
757             $_[0],
758             ;
759              
760             my (@rv, $err);
761             {
762             local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
763             wantarray
764 10 100   10   41 ? @rv = eval $src
  10 100   10   42  
  10 100   10   264  
  10 100   10   35  
  10 100   10   35  
  10 100   10   252  
  10 100   9   32  
  10 100   9   150  
  10 50   9   723  
  10 50   7   47  
  10 50   7   39  
  10     6   239  
  10     6   33  
  10     6   39  
  10     6   223  
  10     5   32  
  10     5   139  
  10     5   640  
  9     5   38  
  9     5   32  
  9     5   206  
  9     3   31  
  9     3   34  
  9     3   202  
  9     20   29  
  9     16   165  
  8     44   625  
  6     44   27  
  6     44   6  
  6     24   166  
  6     44   22  
  6     24   7  
  6     16   160  
  6     37   21  
  6     25   6  
  6     28   543  
  6     8   113  
  6     44   8  
  6     44   179  
  6     44   23  
  6     24   34  
  6     44   154  
  6     24   21  
  6     16   9  
  6     43   509  
  5     31   21  
  5     9   7  
  5     49   134  
  5     17   18  
  5     9   5  
  5     48   143  
  5     57   17  
  5     10   5  
  5     7   489  
  5     7   26  
  5         12  
  5         140  
  5         42  
  5         82  
  5         164  
  5         17  
  5         6  
  5         459  
  3         37  
  3         5  
  3         87  
  3         12  
  3         4  
  3         70  
  3         9  
  3         6  
  3         253  
  20         4733  
  20         93  
  20         4782  
  20         292  
  48         8899  
  44         170  
  52         6628  
  52         585  
  60         6025  
  52         614  
  60         5922  
  52         625  
  32         1020  
  24         507  
  45         4067  
  37         149  
  9         2078  
  9         37  
  9         128  
  4         31  
  3         356  
  5         10  
  0         0  
  5         5  
  5         6  
  5         9  
  5         5  
  5         14  
  8         52  
  0         0  
  0         0  
  8         9  
  8         7  
  8         7  
  8         32  
  8         46  
  8         37  
  3         317  
  5         23  
  8         99  
  8         12  
  8         66  
  8         18  
  8         28  
  8         5  
  8         269  
  41         1567  
  41         163  
  9         1195  
  9         55  
  1         2  
  1         8  
765             : $rv[0] = eval $src
766             ;
767             $err = $@ if $@ ne '';
768             }
769              
770             Carp::croak(join ': ', ($_[2] || 'String-eval failed'), "$err\n$src\n" )
771             if defined $err;
772              
773             wantarray ? @rv : $rv[0];
774             };
775              
776             my ($accessor_maker_cache, $no_xsa_warned_classes);
777              
778             # can't use pkg_gen to track this stuff, as it doesn't
779             # detect superclass mucking
780             my $original_simple_getter = __PACKAGE__->can ('get_simple');
781             my $original_simple_setter = __PACKAGE__->can ('set_simple');
782              
783             my ($resolved_methods, $cag_produced_crefs);
784              
785             sub CLONE {
786 10 100   0   443 my @crefs = grep { defined $_ } values %{$cag_produced_crefs||{}};
  10         283  
  4         47  
787 0         0 $cag_produced_crefs = @crefs
788 0 0       0 ? { map { $_ => $_ } @crefs }
789             : undef
790             ;
791             }
792              
793             # Note!!! Unusual signature
794             $gen_accessor = sub {
795             my ($type, $class, $group, $field, $methname) = @_;
796             $class = ref $class if length ref $class;
797              
798             # When installing an XSA simple accessor, we need to make sure we are not
799             # short-circuiting a (compile or runtime) get_simple/set_simple override.
800             # What we do here is install a lazy first-access check, which will decide
801             # the ultimate coderef being placed in the accessor slot
802             #
803             # Also note that the *original* class will always retain this shim, as
804             # different branches inheriting from it may have different overrides.
805             # Thus the final method (properly labeled and all) is installed in the
806             # calling-package's namespace
807             if ($USE_XS and $group eq 'simple') {
808             die sprintf( "Class::XSAccessor requested but not available:\n%s\n", __CAG_ENV__::NO_CXSA )
809             if __CAG_ENV__::NO_CXSA;
810              
811             my $ret = sub {
812   100         my $current_class = length (ref ($_[0] ) ) ? ref ($_[0]) : $_[0];
813              
814     33       my $resolved_implementation = $resolved_methods->{$current_class}{$methname} ||= do {
815   100 50       if (
      50        
      66        
816             ($current_class->can('get_simple')||0) == $original_simple_getter
817             &&
818             ($current_class->can('set_simple')||0) == $original_simple_setter
819             ) {
820             # nothing has changed, might as well use the XS crefs
821             #
822             # note that by the time this code executes, we already have
823             # *objects* (since XSA works on 'simple' only by definition).
824             # If someone is mucking with the symbol table *after* there
825             # are some objects already - look! many, shiny pieces! :)
826             #
827             # The weird breeder thingy is because XSA does not have an
828             # interface returning *just* a coderef, without installing it
829             # anywhere :(
830             Class::XSAccessor->import(
831             replace => 1,
832             class => '__CAG__XSA__BREEDER__',
833             $maker_templates->{$type}{cxsa_call} => {
834             $methname => $field,
835             },
836             );
837             __CAG__XSA__BREEDER__->can($methname);
838             }
839             else {
840   50 33       if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
841             # not using Carp since the line where this happens doesn't mean much
842             warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
843             . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
844             . "set_simple\n";
845             }
846              
847             do {
848             # that's faster than local
849             $USE_XS = 0;
850             my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
851             $USE_XS = 1;
852             $c;
853             };
854             }
855             };
856              
857             # if after this shim was created someone wrapped it with an 'around',
858             # we can not blindly reinstall the method slot - we will destroy the
859             # wrapper. Silently chain execution further...
860   100 50       if ( ! $cag_produced_crefs->{ $current_class->can($methname) || 0 } ) {
861              
862             # older perls segfault if the cref behind the goto throws
863             # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
864             return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
865              
866             goto $resolved_implementation;
867             }
868              
869              
870             if (__CAG_ENV__::TRACK_UNDEFER_FAIL) {
871             my $deferred_calls_seen = do {
872 11     11   129 no strict 'refs';
  11         41  
  11         1208  
873             \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
874             };
875             my @cframe = caller(0);
876              
877   100         if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
878             Carp::carp (
879             "Deferred version of method $cframe[3] invoked more than once (originally "
880             . "invoked at $already_seen). This is a strong indication your code has "
881             . 'cached the original ->can derived method coderef, and is using it instead '
882             . 'of the proper method re-lookup, causing minor performance regressions'
883             );
884             }
885             else {
886             $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
887             }
888             }
889              
890             # install the resolved implementation into the code slot so we do not
891             # come here anymore (hopefully)
892             # since XSAccessor was available - so is Sub::Name
893             {
894 11     11   47 no strict 'refs';
  11         32  
  11         270  
895 11     11   38 no warnings 'redefine';
  11         140  
  11         2505  
896              
897             my $fq_name = "${current_class}::${methname}";
898             *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
899             }
900              
901             # now things are installed - one ref less to carry
902             delete $resolved_methods->{$current_class}{$methname};
903              
904             # but need to record it in the expectation registry *in case* it
905             # was cached via ->can for some moronic reason
906             Scalar::Util::weaken( $cag_produced_crefs->{$resolved_implementation} = $resolved_implementation );
907              
908              
909             # older perls segfault if the cref behind the goto throws
910             # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
911             return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
912              
913             goto $resolved_implementation;
914             };
915              
916             Scalar::Util::weaken($cag_produced_crefs->{$ret} = $ret);
917              
918             $ret; # returning shim
919             }
920              
921             # no Sub::Name - just install the coderefs directly (compiling every time)
922             elsif (__CAG_ENV__::NO_SUBNAME) {
923             my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
924             $maker_templates->{$type}{pp_generator}->($group, $field);
925              
926             $cag_eval->(
927             "no warnings 'redefine'; sub ${class}::${methname} { $src }; 1",
928             );
929              
930             undef; # so that no further attempt will be made to install anything
931             }
932              
933             # a coderef generator with a variable pad (returns a fresh cref on every invocation)
934             else {
935             ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
936             my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
937             $maker_templates->{$type}{pp_generator}->($group, $field);
938              
939             $cag_eval->( "sub { my \$dummy; sub { \$dummy if 0; $src } }" );
940             })->()
941             }
942             };
943              
944             1;