1 package Class::Accessor::Grouped;
6 use Module::Runtime ();
9 # use M::R to work around the 5.8 require bugs
11 Module::Runtime::require_module('MRO::Compat');
18 our $VERSION = '0.10007';
19 $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
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' }
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;
32 package # hide from PAUSE
35 die "Huh?! No minimum C::XSA version?!\n"
36 unless $__minimum_xsa_version;
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')
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);
54 if (NO_CXSA() and $found_cxsa and !$ENV{CAG_OLD_XS_NOWARN}) {
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 '
64 constant->import( BROKEN_GOTO => ($] < '5.008009') ? 1 : 0 );
66 constant->import( UNSTABLE_DOLLARAT => ($] < '5.013002') ? 1 : 0 );
68 constant->import( TRACK_UNDEFER_FAIL => (
69 $INC{'Test/Builder.pm'} || $INC{'Test/Builder2.pm'}
71 $0 =~ m|^ x?t / .+ \.t $|x
74 *Class::Accessor::Grouped::perlstring = ($] < '5.008')
77 my $d = Data::Dumper->new([])->Indent(0)->Purity(0)->Pad('')->Useqq(1)->Terse(1)->Freezer('')->Toaster('');
78 sub { $d->Values([shift])->Dump };
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
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;
98 no warnings 'redefine';
100 # So we don't have to do lots of lookups inside the loop.
101 $maker = $self->can($maker) unless ref $maker;
105 my ($name, $field) = (ref $_) ? (@$_) : ($_, $_);
107 if ($name !~ /\A[A-Z_a-z][0-9A-Z_a-z]*\z/) {
111 "Illegal accessor name %s - nulls should never appear in stash keys",
115 elsif (! $ENV{CAG_ILLEGAL_ACCESSOR_NAME_OK} ) {
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}'
122 elsif (__CAG_ENV__::NO_SUBNAME) {
124 "Unable to install accessor with illegal name '$name': "
125 . 'Sub::Name not available'
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'
138 ! $illegal_accessors_warned->{$class}++
141 "Installing illegal accessor '$name' into $class, see "
142 . 'documentation for more details'
147 Carp::carp("Having a data accessor named '$name' in '$class' is unwise.")
148 if $name =~ /\A(?: DESTROY | AUTOLOAD | CLONE )\z/x;
150 my $alias = "_${name}_accessor";
152 for ($name, $alias) {
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, $_)
159 my $fq_meth = "${class}::$_";
161 *$fq_meth = Sub::Name::subname($fq_meth, $cref);
162 #unless defined &{$class."\:\:$field"}
167 # $gen_accessor coderef is setup at the end for clarity
172 Class::Accessor::Grouped - Lets you build groups of accessors
176 use base 'Class::Accessor::Grouped';
178 # make basic accessors for objects
179 __PACKAGE__->mk_group_accessors(simple => qw(id name email));
181 # make accessor that works for objects and classes
182 __PACKAGE__->mk_group_accessors(inherited => 'awesome_level');
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');
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.
197 =head2 Notes on accessor names
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).
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>).
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.
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).
231 =head2 mk_group_accessors
233 __PACKAGE__->mk_group_accessors(simple => 'hair_length', [ hair_color => 'hc' ]);
237 =item Arguments: $group, @fieldspec
243 Creates a set of accessors in a given group.
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.
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
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 ].
258 sub mk_group_accessors {
259 my ($self, $group, @fields) = @_;
261 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
265 =head2 mk_group_ro_accessors
267 __PACKAGE__->mk_group_ro_accessors(simple => 'birthdate', [ social_security_number => 'ssn' ]);
271 =item Arguments: $group, @fieldspec
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.
283 sub mk_group_ro_accessors {
284 my($self, $group, @fields) = @_;
286 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
290 =head2 mk_group_wo_accessors
292 __PACKAGE__->mk_group_wo_accessors(simple => 'lie', [ subject => 'subj' ]);
296 =item Arguments: $group, @fieldspec
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.
308 sub mk_group_wo_accessors {
309 my($self, $group, @fields) = @_;
311 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
319 =item Arguments: $field
325 Simple getter for hash-based objects which returns the value for the field
326 name passed as an argument.
338 =item Arguments: $field, $new_value
344 Simple setter for hash-based objects which sets and then returns the value
345 for the field name passed as an argument.
350 $_[0]->{$_[1]} = $_[2];
358 =item Arguments: $field
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
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]);
380 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
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)
388 no warnings 'uninitialized';
390 my $cag_slot = '::__cag_'. $_[1];
391 return ${$_[0].$cag_slot} if defined(${$_[0].$cag_slot});
393 do { return ${$_.$cag_slot} if defined(${$_.$cag_slot}) }
394 for $_[0]->get_super_paths;
403 =item Arguments: $field, $new_value
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.
414 B<Note:>: This method will die if you try to set an object variable on a non
420 if (length (ref ($_[0]) ) ) {
421 if (Scalar::Util::reftype $_[0] eq 'HASH') {
422 return $_[0]->{$_[1]} = $_[2];
424 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
429 ${$_[0].'::__cag_'.$_[1]} = $_[2];
432 =head2 get_component_class
436 =item Arguments: $field
442 Gets the value of the specified component class.
444 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
446 $self->result_class->method();
449 $self->get_component_class('result_class')->method();
453 sub get_component_class {
454 $_[0]->get_inherited($_[1]);
457 =head2 set_component_class
461 =item Arguments: $field, $class
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.
470 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
471 __PACKAGE__->result_class('MyClass');
473 $self->result_class->method();
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
483 if (__CAG_ENV__::UNSTABLE_DOLLARAT) {
487 eval { Module::Runtime::use_package_optimistically($_[2]) }
490 Carp::croak("Could not load $_[1] '$_[2]': $err") if defined $err;
494 eval { Module::Runtime::use_package_optimistically($_[2]) }
495 or Carp::croak("Could not load $_[1] '$_[2]': $@");
499 $_[0]->set_inherited($_[1], $_[2]);
502 =head1 INTERNAL METHODS
504 These methods are documented for clarity, but are never meant to be called
505 directly, and are not really meant for overriding either.
507 =head2 get_super_paths
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>.
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] )};
521 =head2 make_group_accessor
523 __PACKAGE__->make_group_accessor('simple', 'hair_length', 'hair_length');
524 __PACKAGE__->make_group_accessor('simple', 'hc', 'hair_color');
528 =item Arguments: $group, $field, $accessor
530 Returns: \&accessor_coderef ?
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.
540 sub make_group_accessor { $gen_accessor->('rw', @_) }
542 =head2 make_group_ro_accessor
544 __PACKAGE__->make_group_ro_accessor('simple', 'birthdate', 'birthdate');
545 __PACKAGE__->make_group_ro_accessor('simple', 'ssn', 'social_security_number');
549 =item Arguments: $group, $field, $accessor
551 Returns: \&accessor_coderef ?
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.
561 sub make_group_ro_accessor { $gen_accessor->('ro', @_) }
563 =head2 make_group_wo_accessor
565 __PACKAGE__->make_group_wo_accessor('simple', 'lie', 'lie');
566 __PACKAGE__->make_group_wo_accessor('simple', 'subj', 'subject');
570 =item Arguments: $group, $field, $accessor
572 Returns: \&accessor_coderef ?
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.
582 sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
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.
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>
607 Rate CAG_INHP CAG_INH CA CAG_S CAF moOse OTRW CAL mo moUse HANDMADE moo CAF_XS moUse_XS XSA
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%
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%
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%
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%
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%
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%
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%
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%
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%
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%
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%
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%
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%
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%
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% --
639 Benchmarking program is available in the root of the
640 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
642 =head2 Notes on Class::XSAccessor
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.
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
661 Matt S. Trout <mst@shadowcatsystems.co.uk>
663 Christopher H. Laco <claco@chrislaco.com>
667 Caelum: Rafael Kitover <rkitover@cpan.org>
669 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
671 groditi: Guillermo Roditi <groditi@cpan.org>
673 Jason Plum <jason.plum@bmmsi.com>
675 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
678 =head1 COPYRIGHT & LICENSE
680 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
682 This program is free software; you can redistribute it and/or modify
683 it under the same terms as perl itself.
687 ########################################################################
688 ########################################################################
689 ########################################################################
691 # Here be many angry dragons
692 # (all code is in private coderefs since everything inherits CAG)
694 ########################################################################
695 ########################################################################
697 # Autodetect unless flag supplied
698 my $xsa_autodetected;
699 if (! defined $USE_XS) {
700 $USE_XS = __CAG_ENV__::NO_CXSA ? 0 : 1;
705 my $maker_templates = {
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;
714 ? shift->set_%s(%s, @_)
721 cxsa_call => 'getters',
722 pp_generator => sub {
723 # my ($group, $fieldname) = @_;
724 my $quoted_fieldname = perlstring($_[1]);
725 sprintf <<'EOS', $_[0], $quoted_fieldname;
729 my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
730 my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
732 "'$meth' cannot alter its value (read-only attribute of class $class)"
741 cxsa_call => 'setters',
742 pp_generator => sub {
743 # my ($group, $fieldname) = @_;
744 my $quoted_fieldname = perlstring($_[1]);
745 sprintf <<'EOS', $_[0], $quoted_fieldname;
748 ? shift->set_%s(%s, @_)
750 my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
751 my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
753 "'$meth' cannot access its value (write-only attribute of class $class)"
763 #my ($src, $no_warnings, $err_msg) = @_;
765 my $src = sprintf "{ %s warnings; use strict; no strict 'refs'; %s }",
766 $_[1] ? 'no' : 'use',
772 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
777 $err = $@ if $@ ne '';
780 Carp::croak(join ': ', ($_[2] || 'String-eval failed'), "$err\n$src\n" )
783 wantarray ? @rv : $rv[0];
786 my ($accessor_maker_cache, $no_xsa_warned_classes);
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');
793 # Note!!! Unusual signature
794 $gen_accessor = sub {
795 my ($type, $class, $group, $field, $methname) = @_;
796 $class = ref $class if length ref $class;
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
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;
811 my ($expected_cref, $cached_implementation);
812 my $ret = $expected_cref = sub {
813 my $current_class = length (ref ($_[0] ) ) ? ref ($_[0]) : $_[0];
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 {
820 ($current_class->can('get_simple')||0) == $original_simple_getter
822 ($current_class->can('set_simple')||0) == $original_simple_setter
824 # nothing has changed, might as well use the XS crefs
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! :)
831 # The weird breeder thingy is because XSA does not have an
832 # interface returning *just* a coderef, without installing it
834 Class::XSAccessor->import(
836 class => '__CAG__XSA__BREEDER__',
837 $maker_templates->{$type}{cxsa_call} => {
841 __CAG__XSA__BREEDER__->can($methname);
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 "
852 # that's faster than local
854 my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
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) ) {
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;
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;
874 goto $resolved_implementation;
877 if (__CAG_ENV__::TRACK_UNDEFER_FAIL) {
878 my $deferred_calls_seen = do {
880 \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
882 my @cframe = caller(0);
883 if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
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'
892 $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
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
901 no warnings 'redefine';
903 my $fq_name = "${current_class}::${methname}";
904 *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
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);
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;
916 goto $resolved_implementation;
919 Scalar::Util::weaken($expected_cref); # to break the self-reference
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);
929 "no warnings 'redefine'; sub ${class}::${methname} { $src }; 1",
932 undef; # so that no further attempt will be made to install anything
935 # a coderef generator with a variable pad (returns a fresh cref on every invocation)
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);
941 $cag_eval->( "sub { my \$dummy; sub { \$dummy if 0; $src } }" );