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