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