2ce484701274ac0a9b423e0483babd052785b441
[p5sagit/Class-Accessor-Grouped.git] / lib / Class / Accessor / Grouped.pm
1 package Class::Accessor::Grouped;
2 use strict;
3 use warnings;
4 use Carp ();
5 use Scalar::Util ();
6 use Module::Runtime ();
7
8 BEGIN {
9   # use M::R to work around the 5.8 require bugs
10   if ($] < 5.009_005) {
11     Module::Runtime::require_module('MRO::Compat');
12   }
13   else {
14     require mro;
15   }
16 }
17
18 our $VERSION = '0.10007';
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 BEGIN { $__minimum_xsa_version = '1.15' }
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   die "Huh?! No minimum C::XSA version?!\n"
36     unless $__minimum_xsa_version;
37
38   local $@;
39   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   constant->import( NO_SUBNAME => eval {
44     Module::Runtime::require_module('Sub::Name')
45   } ? 0 : "$@" );
46
47   my $found_cxsa;
48   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   if (NO_CXSA() and $found_cxsa and !$ENV{CAG_OLD_XS_NOWARN}) {
55     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   constant->import( BROKEN_GOTO => ($] < '5.008009') ? 1 : 0 );
65
66   constant->import( UNSTABLE_DOLLARAT => ($] < '5.013002') ? 1 : 0 );
67
68   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   *Class::Accessor::Grouped::perlstring = ($] < '5.008')
75     ? do {
76       require Data::Dumper;
77       my $d = Data::Dumper->new([])->Indent(0)->Purity(0)->Pad('')->Useqq(1)->Terse(1)->Freezer('')->Toaster('');
78       sub { $d->Values([shift])->Dump };
79     }
80     : do {
81       require B;
82       \&B::perlstring;
83     }
84   ;
85 }
86
87 # Yes this method is undocumented
88 # Yes it should be a private coderef like all the rest at the end of this file
89 # No we can't do that (yet) because the DBIC-CDBI compat layer overrides it
90 # %$*@!?&!&#*$!!!
91
92 my $illegal_accessors_warned;
93 sub _mk_group_accessors {
94   my($self, $maker, $group, @fields) = @_;
95   my $class = length (ref ($self) ) ? ref ($self) : $self;
96
97   no strict 'refs';
98   no warnings 'redefine';
99
100   # So we don't have to do lots of lookups inside the loop.
101   $maker = $self->can($maker) unless ref $maker;
102
103   for (@fields) {
104
105     my ($name, $field) = (ref $_) ? (@$_) : ($_, $_);
106
107     if ($name !~ /\A[A-Z_a-z][0-9A-Z_a-z]*\z/) {
108
109       if ($name =~ /\0/) {
110         Carp::croak(sprintf
111           "Illegal accessor name %s - nulls should never appear in stash keys",
112           perlstring($name),
113         );
114       }
115       elsif (! $ENV{CAG_ILLEGAL_ACCESSOR_NAME_OK} ) {
116         Carp::croak(
117           "Illegal accessor name '$name'. If you want CAG to attempt creating "
118         . 'it anyway (possible if Sub::Name is available) set '
119         . '$ENV{CAG_ILLEGAL_ACCESSOR_NAME_OK}'
120         );
121       }
122       elsif (__CAG_ENV__::NO_SUBNAME) {
123         Carp::croak(
124           "Unable to install accessor with illegal name '$name': "
125         . 'Sub::Name not available'
126         );
127       }
128       elsif (
129         # Because one of the former maintainers of DBIC::SL is a raging
130         # idiot, there is now a ton of DBIC code out there that attempts
131         # to create column accessors with illegal names. In the interest
132         # of not cluttering the logs of unsuspecting victims (unsuspecting
133         # because these accessors are unusuable anyway) we provide an
134         # explicit "do not warn at all" escape, until all such code is
135         # fixed (this will be a loooooong time >:(
136         $ENV{CAG_ILLEGAL_ACCESSOR_NAME_OK} ne 'DO_NOT_WARN'
137           and
138         ! $illegal_accessors_warned->{$class}++
139       ) {
140         Carp::carp(
141           "Installing illegal accessor '$name' into $class, see "
142         . 'documentation for more details'
143         );
144       }
145     }
146
147     Carp::carp("Having a data accessor named '$name' in '$class' is unwise.")
148       if $name =~ /\A(?: DESTROY | AUTOLOAD | CLONE )\z/x;
149
150     my $alias = "_${name}_accessor";
151
152     for ($name, $alias) {
153
154       # the maker may elect to not return anything, meaning it already
155       # installed the coderef for us (e.g. lack of Sub::Name)
156       my $cref = $self->$maker($group, $field, $_)
157         or next;
158
159       my $fq_meth = "${class}::$_";
160
161       *$fq_meth = Sub::Name::subname($fq_meth, $cref);
162         #unless defined &{$class."\:\:$field"}
163     }
164   }
165 };
166
167 # $gen_accessor coderef is setup at the end for clarity
168 my $gen_accessor;
169
170 =head1 NAME
171
172 Class::Accessor::Grouped - Lets you build groups of accessors
173
174 =head1 SYNOPSIS
175
176  use base 'Class::Accessor::Grouped';
177
178  # make basic accessors for objects
179  __PACKAGE__->mk_group_accessors(simple => qw(id name email));
180
181  # make accessor that works for objects and classes
182  __PACKAGE__->mk_group_accessors(inherited => 'awesome_level');
183
184  # make an accessor which calls a custom pair of getters/setters
185  sub get_column { ... this will be called when you do $obj->name() ... }
186  sub set_column { ... this will be called when you do $obj->name('foo') ... }
187  __PACKAGE__->mk_group_accessors(column => 'name');
188
189 =head1 DESCRIPTION
190
191 This class lets you build groups of accessors that will call different
192 getters and setters. The documentation of this module still requires a lot
193 of work (B<< volunteers welcome >.> >>), but in the meantime you can refer to
194 L<this post|http://lo-f.at/glahn/2009/08/WritingPowerfulAccessorsForPerlClasses.html>
195 for more information.
196
197 =head2 Notes on accessor names
198
199 In general method names in Perl are considered identifiers, and as such need to
200 conform to the identifier specification of C<qr/\A[A-Z_a-z][0-9A-Z_a-z]*\z/>.
201 While it is rather easy to invoke methods with non-standard names
202 (C<< $obj->${\"anything goes"} >>), it is not possible to properly declare such
203 methods without the use of L<Sub::Name>. Since this module must be able to
204 function identically with and without its optional dependencies, starting with
205 version C<0.10008> attempting to declare an accessor with a non-standard name
206 is a fatal error (such operations would silently succeed since version
207 C<0.08004>, as long as L<Sub::Name> is present, or otherwise would result in a
208 syntax error during a string eval).
209
210 Unfortunately in the years since C<0.08004> a rather large body of code
211 accumulated in the wild that does attempt to declare accessors with funny
212 names. One notable perpetrator is L<DBIx::Class::Schema::Loader>, which under
213 certain conditions could create accessors of the C<column> group which start
214 with numbers and/or some other punctuation (the proper way would be to declare
215 columns with the C<accessor> attribute set to C<undef>).
216
217 Therefore an escape mechanism is provided via the environment variable
218 C<CAG_ILLEGAL_ACCESSOR_NAME_OK>. When set to a true value, one warning is
219 issued B<per class> on attempts to declare an accessor with a non-conforming
220 name, and as long as L<Sub::Name> is available all accessors will be properly
221 created. Regardless of this setting, accessor names containing nulls C<"\0">
222 are disallowed, due to various deficiencies in perl itself.
223
224 If your code base has too many instances of illegal accessor declarations, and
225 a fix is not feasible due to time constraints, it is possible to disable the
226 warnings altogether by setting C<$ENV{CAG_ILLEGAL_ACCESSOR_NAME_OK}> to
227 C<DO_NOT_WARN> (observe capitalization).
228
229 =head1 METHODS
230
231 =head2 mk_group_accessors
232
233  __PACKAGE__->mk_group_accessors(simple => 'hair_length', [ hair_color => 'hc' ]);
234
235 =over 4
236
237 =item Arguments: $group, @fieldspec
238
239 Returns: none
240
241 =back
242
243 Creates a set of accessors in a given group.
244
245 $group is the name of the accessor group for the generated accessors; they
246 will call get_$group($field) on get and set_$group($field, $value) on set.
247
248 If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
249 to tell Class::Accessor::Grouped to use its own get_simple and set_simple
250 methods.
251
252 @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
253 this is used as both field and accessor name, if a listref it is expected to
254 be of the form [ $accessor, $field ].
255
256 =cut
257
258 sub mk_group_accessors {
259   my ($self, $group, @fields) = @_;
260
261   $self->_mk_group_accessors('make_group_accessor', $group, @fields);
262   return;
263 }
264
265 =head2 mk_group_ro_accessors
266
267  __PACKAGE__->mk_group_ro_accessors(simple => 'birthdate', [ social_security_number => 'ssn' ]);
268
269 =over 4
270
271 =item Arguments: $group, @fieldspec
272
273 Returns: none
274
275 =back
276
277 Creates a set of read only accessors in a given group. Identical to
278 L</mk_group_accessors> but accessors will throw an error if passed a value
279 rather than setting the value.
280
281 =cut
282
283 sub mk_group_ro_accessors {
284   my($self, $group, @fields) = @_;
285
286   $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
287   return;
288 }
289
290 =head2 mk_group_wo_accessors
291
292  __PACKAGE__->mk_group_wo_accessors(simple => 'lie', [ subject => 'subj' ]);
293
294 =over 4
295
296 =item Arguments: $group, @fieldspec
297
298 Returns: none
299
300 =back
301
302 Creates a set of write only accessors in a given group. Identical to
303 L</mk_group_accessors> but accessors will throw an error if not passed a
304 value rather than getting the value.
305
306 =cut
307
308 sub mk_group_wo_accessors {
309   my($self, $group, @fields) = @_;
310
311   $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
312   return;
313 }
314
315 =head2 get_simple
316
317 =over 4
318
319 =item Arguments: $field
320
321 Returns: $value
322
323 =back
324
325 Simple getter for hash-based objects which returns the value for the field
326 name passed as an argument.
327
328 =cut
329
330 sub get_simple {
331   $_[0]->{$_[1]};
332 }
333
334 =head2 set_simple
335
336 =over 4
337
338 =item Arguments: $field, $new_value
339
340 Returns: $new_value
341
342 =back
343
344 Simple setter for hash-based objects which sets and then returns the value
345 for the field name passed as an argument.
346
347 =cut
348
349 sub set_simple {
350   $_[0]->{$_[1]} = $_[2];
351 }
352
353
354 =head2 get_inherited
355
356 =over 4
357
358 =item Arguments: $field
359
360 Returns: $value
361
362 =back
363
364 Simple getter for Classes and hash-based objects which returns the value for
365 the field name passed as an argument. This behaves much like
366 L<Class::Data::Accessor> where the field can be set in a base class,
367 inherited and changed in subclasses, and inherited and changed for object
368 instances.
369
370 =cut
371
372 sub get_inherited {
373   if ( length (ref ($_[0]) ) ) {
374     if (Scalar::Util::reftype $_[0] eq 'HASH') {
375       return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
376       # everything in @_ is aliased, an assignment won't work
377       splice @_, 0, 1, ref($_[0]);
378     }
379     else {
380       Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
381     }
382   }
383
384   # if we got this far there is nothing in the instance
385   # OR this is a class call
386   # in any case $_[0] contains the class name (see splice above)
387   no strict 'refs';
388   no warnings 'uninitialized';
389
390   my $cag_slot = '::__cag_'. $_[1];
391   return ${$_[0].$cag_slot} if defined(${$_[0].$cag_slot});
392
393   do { return ${$_.$cag_slot} if defined(${$_.$cag_slot}) }
394     for $_[0]->get_super_paths;
395
396   return undef;
397 }
398
399 =head2 set_inherited
400
401 =over 4
402
403 =item Arguments: $field, $new_value
404
405 Returns: $new_value
406
407 =back
408
409 Simple setter for Classes and hash-based objects which sets and then returns
410 the value for the field name passed as an argument. When called on a hash-based
411 object it will set the appropriate hash key value. When called on a class, it
412 will set a class level variable.
413
414 B<Note:>: This method will die if you try to set an object variable on a non
415 hash-based object.
416
417 =cut
418
419 sub set_inherited {
420   if (length (ref ($_[0]) ) ) {
421     if (Scalar::Util::reftype $_[0] eq 'HASH') {
422       return $_[0]->{$_[1]} = $_[2];
423     } else {
424       Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
425     };
426   }
427
428   no strict 'refs';
429   ${$_[0].'::__cag_'.$_[1]} = $_[2];
430 }
431
432 =head2 get_component_class
433
434 =over 4
435
436 =item Arguments: $field
437
438 Returns: $value
439
440 =back
441
442 Gets the value of the specified component class.
443
444  __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
445
446  $self->result_class->method();
447
448  ## same as
449  $self->get_component_class('result_class')->method();
450
451 =cut
452
453 sub get_component_class {
454   $_[0]->get_inherited($_[1]);
455 };
456
457 =head2 set_component_class
458
459 =over 4
460
461 =item Arguments: $field, $class
462
463 Returns: $new_value
464
465 =back
466
467 Inherited accessor that automatically loads the specified class before setting
468 it. This method will die if the specified class could not be loaded.
469
470  __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
471  __PACKAGE__->result_class('MyClass');
472
473  $self->result_class->method();
474
475 =cut
476
477 sub set_component_class {
478   if (defined $_[2] and length $_[2]) {
479     # disable warnings, and prevent $_ being eaten away by a behind-the-scenes
480     # module loading
481     local ($^W, $_);
482
483     if (__CAG_ENV__::UNSTABLE_DOLLARAT) {
484       my $err;
485       {
486         local $@;
487         eval { Module::Runtime::use_package_optimistically($_[2]) }
488           or $err = $@;
489       }
490       Carp::croak("Could not load $_[1] '$_[2]': $err") if defined $err;
491
492     }
493     else {
494       eval { Module::Runtime::use_package_optimistically($_[2]) }
495         or Carp::croak("Could not load $_[1] '$_[2]': $@");
496     }
497   };
498
499   $_[0]->set_inherited($_[1], $_[2]);
500 };
501
502 =head1 INTERNAL METHODS
503
504 These methods are documented for clarity, but are never meant to be called
505 directly, and are not really meant for overriding either.
506
507 =head2 get_super_paths
508
509 Returns a list of 'parent' or 'super' class names that the current class
510 inherited from. This is what drives the traversal done by L</get_inherited>.
511
512 =cut
513
514 sub get_super_paths {
515   # get_linear_isa returns the class itself as the 1st element
516   # use @_ as a pre-allocated scratch array
517   (undef, @_) = @{mro::get_linear_isa( length( ref($_[0]) ) ? ref($_[0]) : $_[0] )};
518   @_;
519 };
520
521 =head2 make_group_accessor
522
523  __PACKAGE__->make_group_accessor('simple', 'hair_length', 'hair_length');
524  __PACKAGE__->make_group_accessor('simple', 'hc', 'hair_color');
525
526 =over 4
527
528 =item Arguments: $group, $field, $accessor
529
530 Returns: \&accessor_coderef ?
531
532 =back
533
534 Called by mk_group_accessors for each entry in @fieldspec. Either returns
535 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
536 C<undef> if it elects to install the coderef on its own.
537
538 =cut
539
540 sub make_group_accessor { $gen_accessor->('rw', @_) }
541
542 =head2 make_group_ro_accessor
543
544  __PACKAGE__->make_group_ro_accessor('simple', 'birthdate', 'birthdate');
545  __PACKAGE__->make_group_ro_accessor('simple', 'ssn', 'social_security_number');
546
547 =over 4
548
549 =item Arguments: $group, $field, $accessor
550
551 Returns: \&accessor_coderef ?
552
553 =back
554
555 Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
556 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
557 C<undef> if it elects to install the coderef on its own.
558
559 =cut
560
561 sub make_group_ro_accessor { $gen_accessor->('ro', @_) }
562
563 =head2 make_group_wo_accessor
564
565  __PACKAGE__->make_group_wo_accessor('simple', 'lie', 'lie');
566  __PACKAGE__->make_group_wo_accessor('simple', 'subj', 'subject');
567
568 =over 4
569
570 =item Arguments: $group, $field, $accessor
571
572 Returns: \&accessor_coderef ?
573
574 =back
575
576 Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
577 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
578 C<undef> if it elects to install the coderef on its own.
579
580 =cut
581
582 sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
583
584
585 =head1 PERFORMANCE
586
587 To provide total flexibility L<Class::Accessor::Grouped> calls methods
588 internally while performing get/set actions, which makes it noticeably
589 slower than similar modules. To compensate, this module will automatically
590 use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
591 accessors if this module is available on your system.
592
593 =head2 Benchmark
594
595 This is the result of a set/get/set loop benchmark on perl 5.12.1 with
596 thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
597 L<Moo>, L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>,
598 L<XSA|Class::XSAccessor>, and L<CAF_XSA|Class::XSAccessor::Compat>:
599
600            Rate  CAG moOse  CAF moUse  moo HANDMADE CAF_XS moUse_XS moo_XS CAF_XSA  XSA CAG_XS
601  CAG      169/s   --  -21% -24%  -32% -32%     -34%   -59%     -63%   -67%    -67% -67%   -67%
602  moOse    215/s  27%    --  -3%  -13% -13%     -15%   -48%     -53%   -58%    -58% -58%   -58%
603  CAF      222/s  31%    3%   --  -10% -10%     -13%   -46%     -52%   -57%    -57% -57%   -57%
604  moUse    248/s  46%   15%  11%    --  -0%      -3%   -40%     -46%   -52%    -52% -52%   -52%
605  moo      248/s  46%   15%  11%    0%   --      -3%   -40%     -46%   -52%    -52% -52%   -52%
606  HANDMADE 255/s  50%   18%  14%    3%   3%       --   -38%     -45%   -50%    -51% -51%   -51%
607  CAF_XS   411/s 143%   91%  85%   66%  66%      61%     --     -11%   -20%    -20% -21%   -21%
608  moUse_XS 461/s 172%  114% 107%   86%  86%      81%    12%       --   -10%    -11% -11%   -11%
609  moo_XS   514/s 204%  139% 131%  107% 107%     102%    25%      12%     --     -0%  -1%    -1%
610  CAF_XSA  516/s 205%  140% 132%  108% 108%     103%    26%      12%     0%      --  -0%    -0%
611  XSA      519/s 206%  141% 133%  109% 109%     104%    26%      13%     1%      0%   --    -0%
612  CAG_XS   519/s 206%  141% 133%  109% 109%     104%    26%      13%     1%      0%   0%     --
613
614 Benchmark program is available in the root of the
615 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
616
617 =head2 Notes on Class::XSAccessor
618
619 You can force (or disable) the use of L<Class::XSAccessor> before creating a
620 particular C<simple> accessor by either manipulating the global variable
621 C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
622 L<localization|perlfunc/local>, or you can do so before runtime via the
623 C<CAG_USE_XS> environment variable.
624
625 Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
626 L</set_simple> this module does its best to detect if you are overriding
627 one of these methods and will fall back to using the perl version of the
628 accessor in order to maintain consistency. However be aware that if you
629 enable use of C<Class::XSAccessor> (automatically or explicitly), create
630 an object, invoke a simple accessor on that object, and B<then> manipulate
631 the symbol table to install a C<get/set_simple> override - you get to keep
632 all the pieces.
633
634 =head1 AUTHORS
635
636 Matt S. Trout <mst@shadowcatsystems.co.uk>
637
638 Christopher H. Laco <claco@chrislaco.com>
639
640 =head1 CONTRIBUTORS
641
642 Caelum: Rafael Kitover <rkitover@cpan.org>
643
644 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
645
646 groditi: Guillermo Roditi <groditi@cpan.org>
647
648 Jason Plum <jason.plum@bmmsi.com>
649
650 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
651
652
653 =head1 COPYRIGHT & LICENSE
654
655 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
656
657 This program is free software; you can redistribute it and/or modify
658 it under the same terms as perl itself.
659
660 =cut
661
662 ########################################################################
663 ########################################################################
664 ########################################################################
665 #
666 # Here be many angry dragons
667 # (all code is in private coderefs since everything inherits CAG)
668 #
669 ########################################################################
670 ########################################################################
671
672 # Autodetect unless flag supplied
673 my $xsa_autodetected;
674 if (! defined $USE_XS) {
675   $USE_XS = __CAG_ENV__::NO_CXSA ? 0 : 1;
676   $xsa_autodetected++;
677 }
678
679
680 my $maker_templates = {
681   rw => {
682     cxsa_call => 'accessors',
683     pp_generator => sub {
684       # my ($group, $fieldname) = @_;
685       my $quoted_fieldname = perlstring($_[1]);
686       sprintf <<'EOS', ($_[0], $quoted_fieldname) x 2;
687
688 @_ > 1
689   ? shift->set_%s(%s, @_)
690   : shift->get_%s(%s)
691 EOS
692
693     },
694   },
695   ro => {
696     cxsa_call => 'getters',
697     pp_generator => sub {
698       # my ($group, $fieldname) = @_;
699       my $quoted_fieldname = perlstring($_[1]);
700       sprintf  <<'EOS', $_[0], $quoted_fieldname;
701
702 @_ > 1
703   ? do {
704     my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
705     my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
706     Carp::croak(
707       "'$meth' cannot alter its value (read-only attribute of class $class)"
708     );
709   }
710   : shift->get_%s(%s)
711 EOS
712
713     },
714   },
715   wo => {
716     cxsa_call => 'setters',
717     pp_generator => sub {
718       # my ($group, $fieldname) = @_;
719       my $quoted_fieldname = perlstring($_[1]);
720       sprintf  <<'EOS', $_[0], $quoted_fieldname;
721
722 @_ > 1
723   ? shift->set_%s(%s, @_)
724   : do {
725     my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
726     my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
727     Carp::croak(
728       "'$meth' cannot access its value (write-only attribute of class $class)"
729     );
730   }
731 EOS
732
733     },
734   },
735 };
736
737 my $cag_eval = sub {
738   #my ($src, $no_warnings, $err_msg) = @_;
739
740   my $src = sprintf "{ %s warnings; use strict; no strict 'refs'; %s }",
741     $_[1] ? 'no' : 'use',
742     $_[0],
743   ;
744
745   my (@rv, $err);
746   {
747     local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
748     wantarray
749       ? @rv = eval $src
750       : $rv[0] = eval $src
751     ;
752     $err = $@ if $@ ne '';
753   }
754
755   Carp::croak(join ': ', ($_[2] || 'String-eval failed'), "$err\n$src\n" )
756     if defined $err;
757
758   wantarray ? @rv : $rv[0];
759 };
760
761 my ($accessor_maker_cache, $no_xsa_warned_classes);
762
763 # can't use pkg_gen to track this stuff, as it doesn't
764 # detect superclass mucking
765 my $original_simple_getter = __PACKAGE__->can ('get_simple');
766 my $original_simple_setter = __PACKAGE__->can ('set_simple');
767
768 # Note!!! Unusual signature
769 $gen_accessor = sub {
770   my ($type, $class, $group, $field, $methname) = @_;
771   $class = ref $class if length ref $class;
772
773   # When installing an XSA simple accessor, we need to make sure we are not
774   # short-circuiting a (compile or runtime) get_simple/set_simple override.
775   # What we do here is install a lazy first-access check, which will decide
776   # the ultimate coderef being placed in the accessor slot
777   #
778   # Also note that the *original* class will always retain this shim, as
779   # different branches inheriting from it may have different overrides.
780   # Thus the final method (properly labeled and all) is installed in the
781   # calling-package's namespace
782   if ($USE_XS and $group eq 'simple') {
783     die sprintf( "Class::XSAccessor requested but not available:\n%s\n", __CAG_ENV__::NO_CXSA )
784       if __CAG_ENV__::NO_CXSA;
785
786     my ($expected_cref, $cached_implementation);
787     my $ret = $expected_cref = sub {
788       my $current_class = length (ref ($_[0] ) ) ? ref ($_[0]) : $_[0];
789
790       # $cached_implementation will be set only if the shim got
791       # 'around'ed, in which case it is handy to avoid re-running
792       # this block over and over again
793       my $resolved_implementation = $cached_implementation->{$current_class} || do {
794         if (
795           ($current_class->can('get_simple')||0) == $original_simple_getter
796             &&
797           ($current_class->can('set_simple')||0) == $original_simple_setter
798         ) {
799           # nothing has changed, might as well use the XS crefs
800           #
801           # note that by the time this code executes, we already have
802           # *objects* (since XSA works on 'simple' only by definition).
803           # If someone is mucking with the symbol table *after* there
804           # are some objects already - look! many, shiny pieces! :)
805           #
806           # The weird breeder thingy is because XSA does not have an
807           # interface returning *just* a coderef, without installing it
808           # anywhere :(
809           Class::XSAccessor->import(
810             replace => 1,
811             class => '__CAG__XSA__BREEDER__',
812             $maker_templates->{$type}{cxsa_call} => {
813               $methname => $field,
814             },
815           );
816           __CAG__XSA__BREEDER__->can($methname);
817         }
818         else {
819           if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
820             # not using Carp since the line where this happens doesn't mean much
821             warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
822               . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
823               . "set_simple\n";
824           }
825
826           do {
827             # that's faster than local
828             $USE_XS = 0;
829             my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
830             $USE_XS = 1;
831             $c;
832           };
833         }
834       };
835
836       # if after this shim was created someone wrapped it with an 'around',
837       # we can not blindly reinstall the method slot - we will destroy the
838       # wrapper. Silently chain execution further...
839       if ( !$expected_cref or $expected_cref != ($current_class->can($methname)||0) ) {
840
841         # there is no point in re-determining it on every subsequent call,
842         # just store for future reference
843         $cached_implementation->{$current_class} ||= $resolved_implementation;
844
845         # older perls segfault if the cref behind the goto throws
846         # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
847         return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
848
849         goto $resolved_implementation;
850       }
851
852       if (__CAG_ENV__::TRACK_UNDEFER_FAIL) {
853         my $deferred_calls_seen = do {
854           no strict 'refs';
855           \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
856         };
857         my @cframe = caller(0);
858         if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
859           Carp::carp (
860             "Deferred version of method $cframe[3] invoked more than once (originally "
861           . "invoked at $already_seen). This is a strong indication your code has "
862           . 'cached the original ->can derived method coderef, and is using it instead '
863           . 'of the proper method re-lookup, causing minor performance regressions'
864           );
865         }
866         else {
867           $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
868         }
869       }
870
871       # install the resolved implementation into the code slot so we do not
872       # come here anymore (hopefully)
873       # since XSAccessor was available - so is Sub::Name
874       {
875         no strict 'refs';
876         no warnings 'redefine';
877
878         my $fq_name = "${current_class}::${methname}";
879         *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
880
881         # need to update what the shim expects too *in case* its
882         # ->can was cached for some moronic reason
883         $expected_cref = $resolved_implementation;
884         Scalar::Util::weaken($expected_cref);
885       }
886
887       # older perls segfault if the cref behind the goto throws
888       # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
889       return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
890
891       goto $resolved_implementation;
892     };
893
894     Scalar::Util::weaken($expected_cref); # to break the self-reference
895     $ret;
896   }
897
898   # no Sub::Name - just install the coderefs directly (compiling every time)
899   elsif (__CAG_ENV__::NO_SUBNAME) {
900     my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
901       $maker_templates->{$type}{pp_generator}->($group, $field);
902
903     $cag_eval->(
904       "no warnings 'redefine'; sub ${class}::${methname} { $src }; 1",
905     );
906
907     undef;  # so that no further attempt will be made to install anything
908   }
909
910   # a coderef generator with a variable pad (returns a fresh cref on every invocation)
911   else {
912     ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
913       my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
914         $maker_templates->{$type}{pp_generator}->($group, $field);
915
916       $cag_eval->( "sub { my \$dummy; sub { \$dummy if 0; $src } }" );
917     })->()
918   }
919 };
920
921 1;