c1f2fab2a1e6545ef270b5421fc23d854dd041b3
[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 benchmark of 200 get/get/set/get/set cycles on perl 5.16.2 with
596 thread support, showcasing how this modules L<simple (CAG_S)|/get_simple>,
597 L<inherited (CAG_INH)|/get_inherited> and L<inherited with parent-class data
598 (CAG_INHP)|/get_inherited> accessors stack up against most popular accessor 
599 builders:  L<Moose>, L<Moo>, L<Mo>, L<Mouse> (both pure-perl and XS variant),
600 L<Object::Tiny::RW (OTRW)|Object::Tiny::RW>,
601 L<Class::Accessor (CA)|Class::Accessor>,
602 L<Class::Accessor::Lite (CAL)|Class::Accessor::Lite>,
603 L<Class::Accessor::Fast (CAF)|Class::Accessor::Fast>,
604 L<Class::Accessor::Fast::XS (CAF_XS)|Class::Accessor::Fast::XS>
605 and L<Class::XSAccessor (XSA)|Class::XSAccessor>
606
607                       Rate CAG_INHP CAG_INH     CA  CAG_S    CAF  moOse   OTRW    CAL     mo  moUse HANDMADE    moo CAF_XS moUse_XS    XSA
608
609  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%
610
611  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%
612
613  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%
614
615  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%
616
617  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%
618
619  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%
620
621  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%
622
623  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%
624
625  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%
626
627  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%
628
629  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%
630
631  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%
632
633  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%
634
635  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%
636
637  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%     --
638
639 Benchmarking program is available in the root of the
640 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
641
642 =head2 Notes on Class::XSAccessor
643
644 You can force (or disable) the use of L<Class::XSAccessor> before creating a
645 particular C<simple> accessor by either manipulating the global variable
646 C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
647 L<localization|perlfunc/local>, or you can do so before runtime via the
648 C<CAG_USE_XS> environment variable.
649
650 Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
651 L</set_simple> this module does its best to detect if you are overriding
652 one of these methods and will fall back to using the perl version of the
653 accessor in order to maintain consistency. However be aware that if you
654 enable use of C<Class::XSAccessor> (automatically or explicitly), create
655 an object, invoke a simple accessor on that object, and B<then> manipulate
656 the symbol table to install a C<get/set_simple> override - you get to keep
657 all the pieces.
658
659 =head1 AUTHORS
660
661 Matt S. Trout <mst@shadowcatsystems.co.uk>
662
663 Christopher H. Laco <claco@chrislaco.com>
664
665 =head1 CONTRIBUTORS
666
667 Caelum: Rafael Kitover <rkitover@cpan.org>
668
669 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
670
671 groditi: Guillermo Roditi <groditi@cpan.org>
672
673 Jason Plum <jason.plum@bmmsi.com>
674
675 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
676
677
678 =head1 COPYRIGHT & LICENSE
679
680 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
681
682 This program is free software; you can redistribute it and/or modify
683 it under the same terms as perl itself.
684
685 =cut
686
687 ########################################################################
688 ########################################################################
689 ########################################################################
690 #
691 # Here be many angry dragons
692 # (all code is in private coderefs since everything inherits CAG)
693 #
694 ########################################################################
695 ########################################################################
696
697 # Autodetect unless flag supplied
698 my $xsa_autodetected;
699 if (! defined $USE_XS) {
700   $USE_XS = __CAG_ENV__::NO_CXSA ? 0 : 1;
701   $xsa_autodetected++;
702 }
703
704
705 my $maker_templates = {
706   rw => {
707     cxsa_call => 'accessors',
708     pp_generator => sub {
709       # my ($group, $fieldname) = @_;
710       my $quoted_fieldname = perlstring($_[1]);
711       sprintf <<'EOS', ($_[0], $quoted_fieldname) x 2;
712
713 @_ > 1
714   ? shift->set_%s(%s, @_)
715   : shift->get_%s(%s)
716 EOS
717
718     },
719   },
720   ro => {
721     cxsa_call => 'getters',
722     pp_generator => sub {
723       # my ($group, $fieldname) = @_;
724       my $quoted_fieldname = perlstring($_[1]);
725       sprintf  <<'EOS', $_[0], $quoted_fieldname;
726
727 @_ > 1
728   ? do {
729     my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
730     my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
731     Carp::croak(
732       "'$meth' cannot alter its value (read-only attribute of class $class)"
733     );
734   }
735   : shift->get_%s(%s)
736 EOS
737
738     },
739   },
740   wo => {
741     cxsa_call => 'setters',
742     pp_generator => sub {
743       # my ($group, $fieldname) = @_;
744       my $quoted_fieldname = perlstring($_[1]);
745       sprintf  <<'EOS', $_[0], $quoted_fieldname;
746
747 @_ > 1
748   ? shift->set_%s(%s, @_)
749   : do {
750     my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
751     my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
752     Carp::croak(
753       "'$meth' cannot access its value (write-only attribute of class $class)"
754     );
755   }
756 EOS
757
758     },
759   },
760 };
761
762 my $cag_eval = sub {
763   #my ($src, $no_warnings, $err_msg) = @_;
764
765   my $src = sprintf "{ %s warnings; use strict; no strict 'refs'; %s }",
766     $_[1] ? 'no' : 'use',
767     $_[0],
768   ;
769
770   my (@rv, $err);
771   {
772     local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
773     wantarray
774       ? @rv = eval $src
775       : $rv[0] = eval $src
776     ;
777     $err = $@ if $@ ne '';
778   }
779
780   Carp::croak(join ': ', ($_[2] || 'String-eval failed'), "$err\n$src\n" )
781     if defined $err;
782
783   wantarray ? @rv : $rv[0];
784 };
785
786 my ($accessor_maker_cache, $no_xsa_warned_classes);
787
788 # can't use pkg_gen to track this stuff, as it doesn't
789 # detect superclass mucking
790 my $original_simple_getter = __PACKAGE__->can ('get_simple');
791 my $original_simple_setter = __PACKAGE__->can ('set_simple');
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 ($expected_cref, $cached_implementation);
812     my $ret = $expected_cref = sub {
813       my $current_class = length (ref ($_[0] ) ) ? ref ($_[0]) : $_[0];
814
815       # $cached_implementation will be set only if the shim got
816       # 'around'ed, in which case it is handy to avoid re-running
817       # this block over and over again
818       my $resolved_implementation = $cached_implementation->{$current_class} || do {
819         if (
820           ($current_class->can('get_simple')||0) == $original_simple_getter
821             &&
822           ($current_class->can('set_simple')||0) == $original_simple_setter
823         ) {
824           # nothing has changed, might as well use the XS crefs
825           #
826           # note that by the time this code executes, we already have
827           # *objects* (since XSA works on 'simple' only by definition).
828           # If someone is mucking with the symbol table *after* there
829           # are some objects already - look! many, shiny pieces! :)
830           #
831           # The weird breeder thingy is because XSA does not have an
832           # interface returning *just* a coderef, without installing it
833           # anywhere :(
834           Class::XSAccessor->import(
835             replace => 1,
836             class => '__CAG__XSA__BREEDER__',
837             $maker_templates->{$type}{cxsa_call} => {
838               $methname => $field,
839             },
840           );
841           __CAG__XSA__BREEDER__->can($methname);
842         }
843         else {
844           if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
845             # not using Carp since the line where this happens doesn't mean much
846             warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
847               . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
848               . "set_simple\n";
849           }
850
851           do {
852             # that's faster than local
853             $USE_XS = 0;
854             my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
855             $USE_XS = 1;
856             $c;
857           };
858         }
859       };
860
861       # if after this shim was created someone wrapped it with an 'around',
862       # we can not blindly reinstall the method slot - we will destroy the
863       # wrapper. Silently chain execution further...
864       if ( !$expected_cref or $expected_cref != ($current_class->can($methname)||0) ) {
865
866         # there is no point in re-determining it on every subsequent call,
867         # just store for future reference
868         $cached_implementation->{$current_class} ||= $resolved_implementation;
869
870         # older perls segfault if the cref behind the goto throws
871         # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
872         return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
873
874         goto $resolved_implementation;
875       }
876
877       if (__CAG_ENV__::TRACK_UNDEFER_FAIL) {
878         my $deferred_calls_seen = do {
879           no strict 'refs';
880           \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
881         };
882         my @cframe = caller(0);
883         if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
884           Carp::carp (
885             "Deferred version of method $cframe[3] invoked more than once (originally "
886           . "invoked at $already_seen). This is a strong indication your code has "
887           . 'cached the original ->can derived method coderef, and is using it instead '
888           . 'of the proper method re-lookup, causing minor performance regressions'
889           );
890         }
891         else {
892           $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
893         }
894       }
895
896       # install the resolved implementation into the code slot so we do not
897       # come here anymore (hopefully)
898       # since XSAccessor was available - so is Sub::Name
899       {
900         no strict 'refs';
901         no warnings 'redefine';
902
903         my $fq_name = "${current_class}::${methname}";
904         *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
905
906         # need to update what the shim expects too *in case* its
907         # ->can was cached for some moronic reason
908         $expected_cref = $resolved_implementation;
909         Scalar::Util::weaken($expected_cref);
910       }
911
912       # older perls segfault if the cref behind the goto throws
913       # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
914       return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
915
916       goto $resolved_implementation;
917     };
918
919     Scalar::Util::weaken($expected_cref); # to break the self-reference
920     $ret;
921   }
922
923   # no Sub::Name - just install the coderefs directly (compiling every time)
924   elsif (__CAG_ENV__::NO_SUBNAME) {
925     my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
926       $maker_templates->{$type}{pp_generator}->($group, $field);
927
928     $cag_eval->(
929       "no warnings 'redefine'; sub ${class}::${methname} { $src }; 1",
930     );
931
932     undef;  # so that no further attempt will be made to install anything
933   }
934
935   # a coderef generator with a variable pad (returns a fresh cref on every invocation)
936   else {
937     ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
938       my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
939         $maker_templates->{$type}{pp_generator}->($group, $field);
940
941       $cag_eval->( "sub { my \$dummy; sub { \$dummy if 0; $src } }" );
942     })->()
943   }
944 };
945
946 1;