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