1 package Class::Accessor::Grouped;
8 our $VERSION = '0.10001';
9 $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
11 # when changing minimum version don't forget to adjust L</PERFORMANCE> and
12 # the Makefile.PL as well
13 our $__minimum_xsa_version;
15 $__minimum_xsa_version = '1.06';
19 # the unless defined is here so that we can override the value
20 # before require/use, *regardless* of the state of $ENV{CAG_USE_XS}
21 $USE_XS = $ENV{CAG_USE_XS}
22 unless defined $USE_XS;
24 # Yes this method is undocumented
25 # Yes it should be a private coderef like all the rest at the end of this file
26 # No we can't do that (yet) because the DBIC-CDBI compat layer overrides it
28 sub _mk_group_accessors {
29 my($self, $maker, $group, @fields) = @_;
30 my $class = Scalar::Util::blessed $self || $self;
33 no warnings 'redefine';
35 # So we don't have to do lots of lookups inside the loop.
36 $maker = $self->can($maker) unless ref $maker;
39 if( $_ eq 'DESTROY' ) {
40 Carp::carp("Having a data accessor named DESTROY in ".
41 "'$class' is unwise.");
44 my ($name, $field) = (ref $_)
49 my $alias = "_${name}_accessor";
51 for my $meth ($name, $alias) {
53 # the maker may elect to not return anything, meaning it already
54 # installed the coderef for us (e.g. lack of Sub::Name)
55 my $cref = $self->$maker($group, $field, $meth)
58 my $fq_meth = "${class}::${meth}";
60 *$fq_meth = Sub::Name::subname($fq_meth, $cref);
61 #unless defined &{$class."\:\:$field"}
66 # coderef is setup at the end for clarity
71 Class::Accessor::Grouped - Lets you build groups of accessors
77 This class lets you build groups of accessors that will call different
82 =head2 mk_group_accessors
86 =item Arguments: $group, @fieldspec
92 Creates a set of accessors in a given group.
94 $group is the name of the accessor group for the generated accessors; they
95 will call get_$group($field) on get and set_$group($field, $value) on set.
97 If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
98 to tell Class::Accessor::Grouped to use its own get_simple and set_simple
101 @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
102 this is used as both field and accessor name, if a listref it is expected to
103 be of the form [ $accessor, $field ].
107 sub mk_group_accessors {
108 my ($self, $group, @fields) = @_;
110 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
114 =head2 mk_group_ro_accessors
118 =item Arguments: $group, @fieldspec
124 Creates a set of read only accessors in a given group. Identical to
125 L</mk_group_accessors> but accessors will throw an error if passed a value
126 rather than setting the value.
130 sub mk_group_ro_accessors {
131 my($self, $group, @fields) = @_;
133 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
136 =head2 mk_group_wo_accessors
140 =item Arguments: $group, @fieldspec
146 Creates a set of write only accessors in a given group. Identical to
147 L</mk_group_accessors> but accessors will throw an error if not passed a
148 value rather than getting the value.
152 sub mk_group_wo_accessors {
153 my($self, $group, @fields) = @_;
155 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
158 =head2 make_group_accessor
162 =item Arguments: $group, $field, $method
164 Returns: \&accessor_coderef ?
168 Called by mk_group_accessors for each entry in @fieldspec. Either returns
169 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
170 C<undef> if it elects to install the coderef on its own.
174 sub make_group_accessor { $gen_accessor->('rw', @_) }
176 =head2 make_group_ro_accessor
180 =item Arguments: $group, $field, $method
182 Returns: \&accessor_coderef ?
186 Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
187 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
188 C<undef> if it elects to install the coderef on its own.
192 sub make_group_ro_accessor { $gen_accessor->('ro', @_) }
194 =head2 make_group_wo_accessor
198 =item Arguments: $group, $field, $method
200 Returns: \&accessor_coderef ?
204 Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
205 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
206 C<undef> if it elects to install the coderef on its own.
210 sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
216 =item Arguments: $field
222 Simple getter for hash-based objects which returns the value for the field
223 name passed as an argument.
228 return $_[0]->{$_[1]};
235 =item Arguments: $field, $new_value
241 Simple setter for hash-based objects which sets and then returns the value
242 for the field name passed as an argument.
247 return $_[0]->{$_[1]} = $_[2];
255 =item Arguments: $field
261 Simple getter for Classes and hash-based objects which returns the value for
262 the field name passed as an argument. This behaves much like
263 L<Class::Data::Accessor> where the field can be set in a base class,
264 inherited and changed in subclasses, and inherited and changed for object
272 if ( defined( $class = Scalar::Util::blessed $_[0] ) ) {
273 if (Scalar::Util::reftype $_[0] eq 'HASH') {
274 return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
277 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
285 no warnings 'uninitialized';
287 my $cag_slot = '::__cag_'. $_[1];
288 return ${$class.$cag_slot} if defined(${$class.$cag_slot});
290 # we need to be smarter about recalculation, as @ISA (thus supers) can very well change in-flight
291 my $cur_gen = mro::get_pkg_gen ($class);
292 if ( $cur_gen != ${$class.'::__cag_pkg_gen__'} ) {
293 @{$class.'::__cag_supers__'} = $_[0]->get_super_paths;
294 ${$class.'::__cag_pkg_gen__'} = $cur_gen;
297 for (@{$class.'::__cag_supers__'}) {
298 return ${$_.$cag_slot} if defined(${$_.$cag_slot});
308 =item Arguments: $field, $new_value
314 Simple setter for Classes and hash-based objects which sets and then returns
315 the value for the field name passed as an argument. When called on a hash-based
316 object it will set the appropriate hash key value. When called on a class, it
317 will set a class level variable.
319 B<Note:>: This method will die if you try to set an object variable on a non
325 if (defined Scalar::Util::blessed $_[0]) {
326 if (Scalar::Util::reftype $_[0] eq 'HASH') {
327 return $_[0]->{$_[1]} = $_[2];
329 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
334 return ${$_[0].'::__cag_'.$_[1]} = $_[2];
338 =head2 get_component_class
342 =item Arguments: $field
348 Gets the value of the specified component class.
350 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
352 $self->result_class->method();
355 $self->get_component_class('result_class')->method();
359 sub get_component_class {
360 return $_[0]->get_inherited($_[1]);
363 =head2 set_component_class
367 =item Arguments: $field, $class
373 Inherited accessor that automatically loads the specified class before setting
374 it. This method will die if the specified class could not be loaded.
376 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
377 __PACKAGE__->result_class('MyClass');
379 $self->result_class->method();
383 sub set_component_class {
386 require Class::Inspector;
387 if (Class::Inspector->installed($_[2]) && !Class::Inspector->loaded($_[2])) {
388 eval "require $_[2]";
390 Carp::croak("Could not load $_[1] '$_[2]': ", $@) if $@;
394 return $_[0]->set_inherited($_[1], $_[2]);
397 =head2 get_super_paths
399 Returns a list of 'parent' or 'super' class names that the current class inherited from.
403 sub get_super_paths {
404 return @{mro::get_linear_isa( ref($_[0]) || $_[0] )};
409 To provide total flexibility L<Class::Accessor::Grouped> calls methods
410 internally while performing get/set actions, which makes it noticeably
411 slower than similar modules. To compensate, this module will automatically
412 use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
413 accessors, if L<< Class::XSAccessor >= 1.06|Class::XSAccessor >> is
414 available on your system.
418 This is the result of a set/get/set loop benchmark on perl 5.12.1 with
419 thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
420 L<Moo>, L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>,
421 L<XSA|Class::XSAccessor>, and L<CAF_XSA|Class::XSAccessor::Compat>:
423 Rate CAG moOse CAF moUse moo HANDMADE CAF_XS moUse_XS moo_XS CAF_XSA XSA CAG_XS
424 CAG 169/s -- -21% -24% -32% -32% -34% -59% -63% -67% -67% -67% -67%
425 moOse 215/s 27% -- -3% -13% -13% -15% -48% -53% -58% -58% -58% -58%
426 CAF 222/s 31% 3% -- -10% -10% -13% -46% -52% -57% -57% -57% -57%
427 moUse 248/s 46% 15% 11% -- -0% -3% -40% -46% -52% -52% -52% -52%
428 moo 248/s 46% 15% 11% 0% -- -3% -40% -46% -52% -52% -52% -52%
429 HANDMADE 255/s 50% 18% 14% 3% 3% -- -38% -45% -50% -51% -51% -51%
430 CAF_XS 411/s 143% 91% 85% 66% 66% 61% -- -11% -20% -20% -21% -21%
431 moUse_XS 461/s 172% 114% 107% 86% 86% 81% 12% -- -10% -11% -11% -11%
432 moo_XS 514/s 204% 139% 131% 107% 107% 102% 25% 12% -- -0% -1% -1%
433 CAF_XSA 516/s 205% 140% 132% 108% 108% 103% 26% 12% 0% -- -0% -0%
434 XSA 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% -- -0%
435 CAG_XS 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% 0% --
437 Benchmark program is available in the root of the
438 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
440 =head2 Notes on Class::XSAccessor
442 You can force (or disable) the use of L<Class::XSAccessor> before creating a
443 particular C<simple> accessor by either manipulating the global variable
444 C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
445 L<localization|perlfunc/local>, or you can do so before runtime via the
446 C<CAG_USE_XS> environment variable.
448 Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
449 L</set_simple> this module does its best to detect if you are overriding
450 one of these methods and will fall back to using the perl version of the
451 accessor in order to maintain consistency. However be aware that if you
452 enable use of C<Class::XSAccessor> (automatically or explicitly), create
453 an object, invoke a simple accessor on that object, and B<then> manipulate
454 the symbol table to install a C<get/set_simple> override - you get to keep
457 While L<Class::XSAccessor> works surprisingly well for the amount of black
458 magic it tries to pull off, it's still black magic. At present (Sep 2010)
459 the module is known to have problems on Windows under heavy thread-stress
460 (e.g. Win32+Apache+mod_perl). Thus for the time being L<Class::XSAccessor>
461 will not be used automatically if you are running under C<MSWin32>.
465 Matt S. Trout <mst@shadowcatsystems.co.uk>
467 Christopher H. Laco <claco@chrislaco.com>
471 Caelum: Rafael Kitover <rkitover@cpan.org>
473 groditi: Guillermo Roditi <groditi@cpan.org>
475 Jason Plum <jason.plum@bmmsi.com>
477 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
480 =head1 COPYRIGHT & LICENSE
482 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
484 This program is free software; you can redistribute it and/or modify
485 it under the same terms as perl itself.
489 ########################################################################
490 ########################################################################
491 ########################################################################
493 # Here be many angry dragons
494 # (all code is in private coderefs since everything inherits CAG)
496 ########################################################################
497 ########################################################################
501 die "Huh?! No minimum C::XSA version?!\n"
502 unless $__minimum_xsa_version;
508 $err = eval { require Sub::Name; 1; } ? undef : do {
509 delete $INC{'Sub/Name.pm'}; # because older perls suck
512 *__CAG_NO_SUBNAME = $err
519 require Class::XSAccessor;
520 Class::XSAccessor->VERSION($__minimum_xsa_version);
524 delete $INC{'Sub/Name.pm'}; # because older perls suck
525 delete $INC{'Class/XSAccessor.pm'};
528 *__CAG_NO_CXSA = $err
534 *__CAG_BROKEN_GOTO = ($] < '5.008009')
540 *__CAG_UNSTABLE_DOLLARAT = ($] < '5.013002')
546 *__CAG_TRACK_UNDEFER_FAIL = (
547 $INC{'Test/Builder.pm'} || $INC{'Test/Builder2.pm'}
549 $0 =~ m|^ x?t / .+ \.t $|x
555 # Autodetect unless flag supplied
556 # Class::XSAccessor is segfaulting on win32, in some
557 # esoteric heavily-threaded scenarios
558 # Win32 users can set $USE_XS/CAG_USE_XS to try to use it anyway
559 my $xsa_autodetected;
560 if (! defined $USE_XS) {
561 $USE_XS = (!__CAG_NO_CXSA and $^O ne 'MSWin32') ? 1 : 0;
565 my $maker_templates = {
567 xs_call => 'accessors',
569 my $set = "set_$_[0]";
570 my $get = "get_$_[0]";
576 ? shift->$set('$field', \@_)
577 : shift->$get('$field')
582 xs_call => 'getters',
584 my $get = "get_$_[0]";
590 ? shift->$get('$field')
592 my \$caller = caller;
593 my \$class = ref \$_[0] || \$_[0];
594 Carp::croak(\"'\$caller' cannot alter the value of '$field' \".
595 \"(read-only attributes of class '\$class')\");
601 xs_call => 'setters',
603 my $set = "set_$_[0]";
609 ? shift->$set('$field', \@_)
611 my \$caller = caller;
612 my \$class = ref \$_[0] || \$_[0];
613 Carp::croak(\"'\$caller' cannot access the value of '$field' \".
614 \"(write-only attributes of class '\$class')\");
622 my ($accessor_maker_cache, $no_xsa_warned_classes);
624 # can't use pkg_gen to track this stuff, as it doesn't
625 # detect superclass mucking
626 my $original_simple_getter = __PACKAGE__->can ('get_simple');
627 my $original_simple_setter = __PACKAGE__->can ('set_simple');
629 # Note!!! Unusual signature
630 $gen_accessor = sub {
631 my ($type, $class, $group, $field, $methname) = @_;
632 if (my $c = Scalar::Util::blessed( $class )) {
636 # When installing an XSA simple accessor, we need to make sure we are not
637 # short-circuiting a (compile or runtime) get_simple/set_simple override.
638 # What we do here is install a lazy first-access check, which will decide
639 # the ultimate coderef being placed in the accessor slot
641 # Also note that the *original* class will always retain this shim, as
642 # different branches inheriting from it may have different overrides.
643 # Thus the final method (properly labeled and all) is installed in the
644 # calling-package's namespace
645 if ($USE_XS and $group eq 'simple') {
646 die sprintf( "Class::XSAccessor requested but not available:\n%s\n", __CAG_NO_CXSA )
649 my ($expected_cref, $cached_implementation);
650 my $ret = $expected_cref = sub {
651 my $current_class = Scalar::Util::blessed( $_[0] ) || $_[0];
653 # $cached_implementation will be set only if the shim got
654 # 'around'ed, in which case it is handy to avoid re-running
655 # this block over and over again
656 my $resolved_implementation = $cached_implementation->{$current_class} || do {
658 $current_class->can('get_simple') == $original_simple_getter
660 $current_class->can('set_simple') == $original_simple_setter
662 # nothing has changed, might as well use the XS crefs
664 # note that by the time this code executes, we already have
665 # *objects* (since XSA works on 'simple' only by definition).
666 # If someone is mucking with the symbol table *after* there
667 # are some objects already - look! many, shiny pieces! :)
669 # The weird breeder thingy is because XSA does not have an
670 # interface returning *just* a coderef, without installing it
672 Class::XSAccessor->import(
674 class => '__CAG__XSA__BREEDER__',
675 $maker_templates->{$type}{xs_call} => {
679 __CAG__XSA__BREEDER__->can($methname);
682 if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
683 # not using Carp since the line where this happens doesn't mean much
684 warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
685 . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
690 # that's faster than local
692 my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
699 # if after this shim was created someone wrapped it with an 'around',
700 # we can not blindly reinstall the method slot - we will destroy the
701 # wrapper. Silently chain execution further...
702 if ($expected_cref != $current_class->can($methname)) {
704 # there is no point in re-determining it on every subsequent call,
705 # just store for future reference
706 $cached_implementation->{$current_class} ||= $resolved_implementation;
708 # older perls segfault if the cref behind the goto throws
709 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
710 return $resolved_implementation->(@_) if __CAG_BROKEN_GOTO;
712 goto $resolved_implementation;
715 if (__CAG_TRACK_UNDEFER_FAIL) {
716 my $deferred_calls_seen = do {
718 \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
720 my @cframe = caller(0);
721 if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
723 "Deferred version of method $cframe[3] invoked more than once (originally "
724 . "invoked at $already_seen). This is a strong indication your code has "
725 . 'cached the original ->can derived method coderef, and is using it instead '
726 . 'of the proper method re-lookup, causing performance regressions'
730 $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
734 # install the resolved implementation into the code slot so we do not
735 # come here anymore (hopefully)
736 # since XSAccessor was available - so is Sub::Name
739 no warnings 'redefine';
741 my $fq_name = "${current_class}::${methname}";
742 *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
744 # need to update what the shim expects too *in case* its
745 # ->can was cached for some moronic reason
746 $expected_cref = $resolved_implementation;
747 Scalar::Util::weaken($expected_cref);
750 # older perls segfault if the cref behind the goto throws
751 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
752 return $resolved_implementation->(@_) if __CAG_BROKEN_GOTO;
754 goto $resolved_implementation;
757 Scalar::Util::weaken($expected_cref); # to break the self-reference
761 # no Sub::Name - just install the coderefs directly (compiling every time)
762 elsif (__CAG_NO_SUBNAME) {
763 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
764 $maker_templates->{$type}{pp_code}->($group, $field);
766 no warnings 'redefine';
767 local $@ if __CAG_UNSTABLE_DOLLARAT;
768 eval "sub ${class}::${methname} { $src }";
770 undef; # so that no further attempt will be made to install anything
773 # a coderef generator with a variable pad (returns a fresh cref on every invocation)
775 ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
776 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
777 $maker_templates->{$type}{pp_code}->($group, $field);
779 local $@ if __CAG_UNSTABLE_DOLLARAT;
780 eval "sub { my \$dummy; sub { \$dummy if 0; $src } }" or die $@;