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