1 package Class::Accessor::Grouped;
16 our $VERSION = '0.10003';
17 $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
19 # when changing minimum version don't forget to adjust L</PERFORMANCE> and
20 # the Makefile.PL as well
21 our $__minimum_xsa_version;
23 $__minimum_xsa_version = '1.11';
27 # the unless defined is here so that we can override the value
28 # before require/use, *regardless* of the state of $ENV{CAG_USE_XS}
29 $USE_XS = $ENV{CAG_USE_XS}
30 unless defined $USE_XS;
32 # Yes this method is undocumented
33 # Yes it should be a private coderef like all the rest at the end of this file
34 # No we can't do that (yet) because the DBIC-CDBI compat layer overrides it
36 sub _mk_group_accessors {
37 my($self, $maker, $group, @fields) = @_;
38 my $class = Scalar::Util::blessed $self || $self;
41 no warnings 'redefine';
43 # So we don't have to do lots of lookups inside the loop.
44 $maker = $self->can($maker) unless ref $maker;
47 if( $_ eq 'DESTROY' ) {
48 Carp::carp("Having a data accessor named DESTROY in ".
49 "'$class' is unwise.");
52 my ($name, $field) = (ref $_)
57 my $alias = "_${name}_accessor";
59 for my $meth ($name, $alias) {
61 # the maker may elect to not return anything, meaning it already
62 # installed the coderef for us (e.g. lack of Sub::Name)
63 my $cref = $self->$maker($group, $field, $meth)
66 my $fq_meth = "${class}::${meth}";
68 *$fq_meth = Sub::Name::subname($fq_meth, $cref);
69 #unless defined &{$class."\:\:$field"}
74 # coderef is setup at the end for clarity
79 Class::Accessor::Grouped - Lets you build groups of accessors
83 use base 'Class::Accessor::Grouped';
85 # make basic accessors for objects
86 __PACKAGE__->mk_group_accessors(simple => qw(id name email));
88 # make accessor that works for objects and classes
89 __PACKAGE__->mk_group_accessors(inherited => 'awesome_level');
93 This class lets you build groups of accessors that will call different
98 =head2 mk_group_accessors
100 __PACKAGE__->mk_group_accessors(simple => 'hair_length');
104 =item Arguments: $group, @fieldspec
110 Creates a set of accessors in a given group.
112 $group is the name of the accessor group for the generated accessors; they
113 will call get_$group($field) on get and set_$group($field, $value) on set.
115 If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
116 to tell Class::Accessor::Grouped to use its own get_simple and set_simple
119 @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
120 this is used as both field and accessor name, if a listref it is expected to
121 be of the form [ $accessor, $field ].
125 sub mk_group_accessors {
126 my ($self, $group, @fields) = @_;
128 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
132 =head2 mk_group_ro_accessors
134 __PACKAGE__->mk_group_ro_accessors(simple => 'birthdate');
138 =item Arguments: $group, @fieldspec
144 Creates a set of read only accessors in a given group. Identical to
145 L</mk_group_accessors> but accessors will throw an error if passed a value
146 rather than setting the value.
150 sub mk_group_ro_accessors {
151 my($self, $group, @fields) = @_;
153 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
156 =head2 mk_group_wo_accessors
158 __PACKAGE__->mk_group_wo_accessors(simple => 'lie');
162 =item Arguments: $group, @fieldspec
168 Creates a set of write only accessors in a given group. Identical to
169 L</mk_group_accessors> but accessors will throw an error if not passed a
170 value rather than getting the value.
174 sub mk_group_wo_accessors {
175 my($self, $group, @fields) = @_;
177 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
180 =head2 make_group_accessor
182 __PACKAGE__->make_group_accessor(simple => 'hair_length', 'hair_length');
186 =item Arguments: $group, $field, $method
188 Returns: \&accessor_coderef ?
192 Called by mk_group_accessors for each entry in @fieldspec. Either returns
193 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
194 C<undef> if it elects to install the coderef on its own.
198 sub make_group_accessor { $gen_accessor->('rw', @_) }
200 =head2 make_group_ro_accessor
202 __PACKAGE__->make_group_ro_accessor(simple => 'birthdate', 'birthdate');
206 =item Arguments: $group, $field, $method
208 Returns: \&accessor_coderef ?
212 Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
213 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
214 C<undef> if it elects to install the coderef on its own.
218 sub make_group_ro_accessor { $gen_accessor->('ro', @_) }
220 =head2 make_group_wo_accessor
222 __PACKAGE__->make_group_wo_accessor(simple => 'lie', 'lie');
226 =item Arguments: $group, $field, $method
228 Returns: \&accessor_coderef ?
232 Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
233 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
234 C<undef> if it elects to install the coderef on its own.
238 sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
244 =item Arguments: $field
250 Simple getter for hash-based objects which returns the value for the field
251 name passed as an argument.
256 return $_[0]->{$_[1]};
263 =item Arguments: $field, $new_value
269 Simple setter for hash-based objects which sets and then returns the value
270 for the field name passed as an argument.
275 return $_[0]->{$_[1]} = $_[2];
283 =item Arguments: $field
289 Simple getter for Classes and hash-based objects which returns the value for
290 the field name passed as an argument. This behaves much like
291 L<Class::Data::Accessor> where the field can be set in a base class,
292 inherited and changed in subclasses, and inherited and changed for object
300 if ( defined( $class = Scalar::Util::blessed $_[0] ) ) {
301 if (Scalar::Util::reftype $_[0] eq 'HASH') {
302 return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
305 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
313 no warnings 'uninitialized';
315 my $cag_slot = '::__cag_'. $_[1];
316 return ${$class.$cag_slot} if defined(${$class.$cag_slot});
318 # we need to be smarter about recalculation, as @ISA (thus supers) can very well change in-flight
319 my $cur_gen = mro::get_pkg_gen ($class);
320 if ( $cur_gen != ${$class.'::__cag_pkg_gen__'} ) {
321 @{$class.'::__cag_supers__'} = $_[0]->get_super_paths;
322 ${$class.'::__cag_pkg_gen__'} = $cur_gen;
325 for (@{$class.'::__cag_supers__'}) {
326 return ${$_.$cag_slot} if defined(${$_.$cag_slot});
336 =item Arguments: $field, $new_value
342 Simple setter for Classes and hash-based objects which sets and then returns
343 the value for the field name passed as an argument. When called on a hash-based
344 object it will set the appropriate hash key value. When called on a class, it
345 will set a class level variable.
347 B<Note:>: This method will die if you try to set an object variable on a non
353 if (defined Scalar::Util::blessed $_[0]) {
354 if (Scalar::Util::reftype $_[0] eq 'HASH') {
355 return $_[0]->{$_[1]} = $_[2];
357 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
362 return ${$_[0].'::__cag_'.$_[1]} = $_[2];
366 =head2 get_component_class
370 =item Arguments: $field
376 Gets the value of the specified component class.
378 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
380 $self->result_class->method();
383 $self->get_component_class('result_class')->method();
387 sub get_component_class {
388 return $_[0]->get_inherited($_[1]);
391 =head2 set_component_class
395 =item Arguments: $field, $class
401 Inherited accessor that automatically loads the specified class before setting
402 it. This method will die if the specified class could not be loaded.
404 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
405 __PACKAGE__->result_class('MyClass');
407 $self->result_class->method();
411 sub set_component_class {
414 require Class::Inspector;
415 if (Class::Inspector->installed($_[2]) && !Class::Inspector->loaded($_[2])) {
416 eval "require $_[2]";
418 Carp::croak("Could not load $_[1] '$_[2]': ", $@) if $@;
422 return $_[0]->set_inherited($_[1], $_[2]);
425 =head2 get_super_paths
427 Returns a list of 'parent' or 'super' class names that the current class inherited from.
431 sub get_super_paths {
432 return @{mro::get_linear_isa( ref($_[0]) || $_[0] )};
437 To provide total flexibility L<Class::Accessor::Grouped> calls methods
438 internally while performing get/set actions, which makes it noticeably
439 slower than similar modules. To compensate, this module will automatically
440 use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
441 accessors if this module is available on your system.
445 This is the result of a set/get/set loop benchmark on perl 5.12.1 with
446 thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
447 L<Moo>, L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>,
448 L<XSA|Class::XSAccessor>, and L<CAF_XSA|Class::XSAccessor::Compat>:
450 Rate CAG moOse CAF moUse moo HANDMADE CAF_XS moUse_XS moo_XS CAF_XSA XSA CAG_XS
451 CAG 169/s -- -21% -24% -32% -32% -34% -59% -63% -67% -67% -67% -67%
452 moOse 215/s 27% -- -3% -13% -13% -15% -48% -53% -58% -58% -58% -58%
453 CAF 222/s 31% 3% -- -10% -10% -13% -46% -52% -57% -57% -57% -57%
454 moUse 248/s 46% 15% 11% -- -0% -3% -40% -46% -52% -52% -52% -52%
455 moo 248/s 46% 15% 11% 0% -- -3% -40% -46% -52% -52% -52% -52%
456 HANDMADE 255/s 50% 18% 14% 3% 3% -- -38% -45% -50% -51% -51% -51%
457 CAF_XS 411/s 143% 91% 85% 66% 66% 61% -- -11% -20% -20% -21% -21%
458 moUse_XS 461/s 172% 114% 107% 86% 86% 81% 12% -- -10% -11% -11% -11%
459 moo_XS 514/s 204% 139% 131% 107% 107% 102% 25% 12% -- -0% -1% -1%
460 CAF_XSA 516/s 205% 140% 132% 108% 108% 103% 26% 12% 0% -- -0% -0%
461 XSA 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% -- -0%
462 CAG_XS 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% 0% --
464 Benchmark program is available in the root of the
465 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
467 =head2 Notes on Class::XSAccessor
469 You can force (or disable) the use of L<Class::XSAccessor> before creating a
470 particular C<simple> accessor by either manipulating the global variable
471 C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
472 L<localization|perlfunc/local>, or you can do so before runtime via the
473 C<CAG_USE_XS> environment variable.
475 Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
476 L</set_simple> this module does its best to detect if you are overriding
477 one of these methods and will fall back to using the perl version of the
478 accessor in order to maintain consistency. However be aware that if you
479 enable use of C<Class::XSAccessor> (automatically or explicitly), create
480 an object, invoke a simple accessor on that object, and B<then> manipulate
481 the symbol table to install a C<get/set_simple> override - you get to keep
486 Matt S. Trout <mst@shadowcatsystems.co.uk>
488 Christopher H. Laco <claco@chrislaco.com>
492 Caelum: Rafael Kitover <rkitover@cpan.org>
494 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
496 groditi: Guillermo Roditi <groditi@cpan.org>
498 Jason Plum <jason.plum@bmmsi.com>
500 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
503 =head1 COPYRIGHT & LICENSE
505 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
507 This program is free software; you can redistribute it and/or modify
508 it under the same terms as perl itself.
512 ########################################################################
513 ########################################################################
514 ########################################################################
516 # Here be many angry dragons
517 # (all code is in private coderefs since everything inherits CAG)
519 ########################################################################
520 ########################################################################
524 die "Huh?! No minimum C::XSA version?!\n"
525 unless $__minimum_xsa_version;
531 $err = eval { require Sub::Name; 1; } ? undef : do {
532 delete $INC{'Sub/Name.pm'}; # because older perls suck
535 *__CAG_NO_SUBNAME = $err
542 require Class::XSAccessor;
543 Class::XSAccessor->VERSION($__minimum_xsa_version);
547 delete $INC{'Sub/Name.pm'}; # because older perls suck
548 delete $INC{'Class/XSAccessor.pm'};
551 *__CAG_NO_CXSA = $err
557 *__CAG_BROKEN_GOTO = ($] < '5.008009')
563 *__CAG_UNSTABLE_DOLLARAT = ($] < '5.013002')
569 *__CAG_TRACK_UNDEFER_FAIL = (
570 $INC{'Test/Builder.pm'} || $INC{'Test/Builder2.pm'}
572 $0 =~ m|^ x?t / .+ \.t $|x
578 # Autodetect unless flag supplied
579 my $xsa_autodetected;
580 if (! defined $USE_XS) {
581 $USE_XS = __CAG_NO_CXSA ? 0 : 1;
585 my $maker_templates = {
587 xs_call => 'accessors',
589 my $set = "set_$_[0]";
590 my $get = "get_$_[0]";
596 ? shift->$set('$field', \@_)
597 : shift->$get('$field')
602 xs_call => 'getters',
604 my $get = "get_$_[0]";
610 ? shift->$get('$field')
612 my \$caller = caller;
613 my \$class = ref \$_[0] || \$_[0];
614 Carp::croak(\"'\$caller' cannot alter the value of '$field' \".
615 \"(read-only attributes of class '\$class')\");
621 xs_call => 'setters',
623 my $set = "set_$_[0]";
629 ? shift->$set('$field', \@_)
631 my \$caller = caller;
632 my \$class = ref \$_[0] || \$_[0];
633 Carp::croak(\"'\$caller' cannot access the value of '$field' \".
634 \"(write-only attributes of class '\$class')\");
642 my ($accessor_maker_cache, $no_xsa_warned_classes);
644 # can't use pkg_gen to track this stuff, as it doesn't
645 # detect superclass mucking
646 my $original_simple_getter = __PACKAGE__->can ('get_simple');
647 my $original_simple_setter = __PACKAGE__->can ('set_simple');
649 # Note!!! Unusual signature
650 $gen_accessor = sub {
651 my ($type, $class, $group, $field, $methname) = @_;
652 if (my $c = Scalar::Util::blessed( $class )) {
656 # When installing an XSA simple accessor, we need to make sure we are not
657 # short-circuiting a (compile or runtime) get_simple/set_simple override.
658 # What we do here is install a lazy first-access check, which will decide
659 # the ultimate coderef being placed in the accessor slot
661 # Also note that the *original* class will always retain this shim, as
662 # different branches inheriting from it may have different overrides.
663 # Thus the final method (properly labeled and all) is installed in the
664 # calling-package's namespace
665 if ($USE_XS and $group eq 'simple') {
666 die sprintf( "Class::XSAccessor requested but not available:\n%s\n", __CAG_NO_CXSA )
669 my ($expected_cref, $cached_implementation);
670 my $ret = $expected_cref = sub {
671 my $current_class = Scalar::Util::blessed( $_[0] ) || $_[0];
673 # $cached_implementation will be set only if the shim got
674 # 'around'ed, in which case it is handy to avoid re-running
675 # this block over and over again
676 my $resolved_implementation = $cached_implementation->{$current_class} || do {
678 $current_class->can('get_simple') == $original_simple_getter
680 $current_class->can('set_simple') == $original_simple_setter
682 # nothing has changed, might as well use the XS crefs
684 # note that by the time this code executes, we already have
685 # *objects* (since XSA works on 'simple' only by definition).
686 # If someone is mucking with the symbol table *after* there
687 # are some objects already - look! many, shiny pieces! :)
689 # The weird breeder thingy is because XSA does not have an
690 # interface returning *just* a coderef, without installing it
692 Class::XSAccessor->import(
694 class => '__CAG__XSA__BREEDER__',
695 $maker_templates->{$type}{xs_call} => {
699 __CAG__XSA__BREEDER__->can($methname);
702 if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
703 # not using Carp since the line where this happens doesn't mean much
704 warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
705 . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
710 # that's faster than local
712 my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
719 # if after this shim was created someone wrapped it with an 'around',
720 # we can not blindly reinstall the method slot - we will destroy the
721 # wrapper. Silently chain execution further...
722 if ( !$expected_cref or $expected_cref != $current_class->can($methname) ) {
724 # there is no point in re-determining it on every subsequent call,
725 # just store for future reference
726 $cached_implementation->{$current_class} ||= $resolved_implementation;
728 # older perls segfault if the cref behind the goto throws
729 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
730 return $resolved_implementation->(@_) if __CAG_BROKEN_GOTO;
732 goto $resolved_implementation;
735 if (__CAG_TRACK_UNDEFER_FAIL) {
736 my $deferred_calls_seen = do {
738 \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
740 my @cframe = caller(0);
741 if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
743 "Deferred version of method $cframe[3] invoked more than once (originally "
744 . "invoked at $already_seen). This is a strong indication your code has "
745 . 'cached the original ->can derived method coderef, and is using it instead '
746 . 'of the proper method re-lookup, causing performance regressions'
750 $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
754 # install the resolved implementation into the code slot so we do not
755 # come here anymore (hopefully)
756 # since XSAccessor was available - so is Sub::Name
759 no warnings 'redefine';
761 my $fq_name = "${current_class}::${methname}";
762 *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
764 # need to update what the shim expects too *in case* its
765 # ->can was cached for some moronic reason
766 $expected_cref = $resolved_implementation;
767 Scalar::Util::weaken($expected_cref);
770 # older perls segfault if the cref behind the goto throws
771 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
772 return $resolved_implementation->(@_) if __CAG_BROKEN_GOTO;
774 goto $resolved_implementation;
777 Scalar::Util::weaken($expected_cref); # to break the self-reference
781 # no Sub::Name - just install the coderefs directly (compiling every time)
782 elsif (__CAG_NO_SUBNAME) {
783 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
784 $maker_templates->{$type}{pp_code}->($group, $field);
786 no warnings 'redefine';
787 local $@ if __CAG_UNSTABLE_DOLLARAT;
788 eval "sub ${class}::${methname} { $src }";
790 undef; # so that no further attempt will be made to install anything
793 # a coderef generator with a variable pad (returns a fresh cref on every invocation)
795 ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
796 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
797 $maker_templates->{$type}{pp_code}->($group, $field);
799 local $@ if __CAG_UNSTABLE_DOLLARAT;
800 eval "sub { my \$dummy; sub { \$dummy if 0; $src } }" or die $@;