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() and 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
75 # Yes this method is undocumented
76 # Yes it should be a private coderef like all the rest at the end of this file
77 # No we can't do that (yet) because the DBIC-CDBI compat layer overrides it
79 sub _mk_group_accessors {
80 my($self, $maker, $group, @fields) = @_;
81 my $class = length (ref ($self) ) ? ref ($self) : $self;
84 no warnings 'redefine';
86 # So we don't have to do lots of lookups inside the loop.
87 $maker = $self->can($maker) unless ref $maker;
91 my ($name, $field) = (ref $_) ? (@$_) : ($_, $_);
93 Carp::croak("Illegal accessor name '$name'")
94 unless $name =~ /\A[A-Z_a-z][0-9A-Z_a-z]*\z/;
96 Carp::carp("Having a data accessor named '$name' in '$class' is unwise.")
97 if $name =~ /\A(?: DESTROY | AUTOLOAD | CLONE )\z/x;
99 my $alias = "_${name}_accessor";
101 for ($name, $alias) {
103 # the maker may elect to not return anything, meaning it already
104 # installed the coderef for us (e.g. lack of Sub::Name)
105 my $cref = $self->$maker($group, $field, $_)
108 my $fq_meth = "${class}::$_";
110 *$fq_meth = Sub::Name::subname($fq_meth, $cref);
111 #unless defined &{$class."\:\:$field"}
116 # $gen_accessor coderef is setup at the end for clarity
121 Class::Accessor::Grouped - Lets you build groups of accessors
125 use base 'Class::Accessor::Grouped';
127 # make basic accessors for objects
128 __PACKAGE__->mk_group_accessors(simple => qw(id name email));
130 # make accessor that works for objects and classes
131 __PACKAGE__->mk_group_accessors(inherited => 'awesome_level');
135 This class lets you build groups of accessors that will call different
140 =head2 mk_group_accessors
142 __PACKAGE__->mk_group_accessors(simple => 'hair_length', [ hair_color => 'hc' ]);
146 =item Arguments: $group, @fieldspec
152 Creates a set of accessors in a given group.
154 $group is the name of the accessor group for the generated accessors; they
155 will call get_$group($field) on get and set_$group($field, $value) on set.
157 If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
158 to tell Class::Accessor::Grouped to use its own get_simple and set_simple
161 @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
162 this is used as both field and accessor name, if a listref it is expected to
163 be of the form [ $accessor, $field ].
167 sub mk_group_accessors {
168 my ($self, $group, @fields) = @_;
170 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
174 =head2 mk_group_ro_accessors
176 __PACKAGE__->mk_group_ro_accessors(simple => 'birthdate', [ social_security_number => 'ssn' ]);
180 =item Arguments: $group, @fieldspec
186 Creates a set of read only accessors in a given group. Identical to
187 L</mk_group_accessors> but accessors will throw an error if passed a value
188 rather than setting the value.
192 sub mk_group_ro_accessors {
193 my($self, $group, @fields) = @_;
195 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
199 =head2 mk_group_wo_accessors
201 __PACKAGE__->mk_group_wo_accessors(simple => 'lie', [ subject => 'subj' ]);
205 =item Arguments: $group, @fieldspec
211 Creates a set of write only accessors in a given group. Identical to
212 L</mk_group_accessors> but accessors will throw an error if not passed a
213 value rather than getting the value.
217 sub mk_group_wo_accessors {
218 my($self, $group, @fields) = @_;
220 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
228 =item Arguments: $field
234 Simple getter for hash-based objects which returns the value for the field
235 name passed as an argument.
247 =item Arguments: $field, $new_value
253 Simple setter for hash-based objects which sets and then returns the value
254 for the field name passed as an argument.
259 $_[0]->{$_[1]} = $_[2];
267 =item Arguments: $field
273 Simple getter for Classes and hash-based objects which returns the value for
274 the field name passed as an argument. This behaves much like
275 L<Class::Data::Accessor> where the field can be set in a base class,
276 inherited and changed in subclasses, and inherited and changed for object
282 if ( length (ref ($_[0]) ) ) {
283 if (Scalar::Util::reftype $_[0] eq 'HASH') {
284 return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
285 # everything in @_ is aliased, an assignment won't work
286 splice @_, 0, 1, ref($_[0]);
289 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
293 # if we got this far there is nothing in the instance
294 # OR this is a class call
295 # in any case $_[0] contains the class name (see splice above)
297 no warnings 'uninitialized';
299 my $cag_slot = '::__cag_'. $_[1];
300 return ${$_[0].$cag_slot} if defined(${$_[0].$cag_slot});
302 do { return ${$_.$cag_slot} if defined(${$_.$cag_slot}) }
303 for $_[0]->get_super_paths;
312 =item Arguments: $field, $new_value
318 Simple setter for Classes and hash-based objects which sets and then returns
319 the value for the field name passed as an argument. When called on a hash-based
320 object it will set the appropriate hash key value. When called on a class, it
321 will set a class level variable.
323 B<Note:>: This method will die if you try to set an object variable on a non
329 if (length (ref ($_[0]) ) ) {
330 if (Scalar::Util::reftype $_[0] eq 'HASH') {
331 return $_[0]->{$_[1]} = $_[2];
333 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
338 ${$_[0].'::__cag_'.$_[1]} = $_[2];
341 =head2 get_component_class
345 =item Arguments: $field
351 Gets the value of the specified component class.
353 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
355 $self->result_class->method();
358 $self->get_component_class('result_class')->method();
362 sub get_component_class {
363 $_[0]->get_inherited($_[1]);
366 =head2 set_component_class
370 =item Arguments: $field, $class
376 Inherited accessor that automatically loads the specified class before setting
377 it. This method will die if the specified class could not be loaded.
379 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
380 __PACKAGE__->result_class('MyClass');
382 $self->result_class->method();
386 sub set_component_class {
387 if (defined $_[2] and length $_[2]) {
388 # disable warnings, and prevent $_ being eaten away by a behind-the-scenes
392 if (__CAG_ENV__::UNSTABLE_DOLLARAT) {
396 eval { Module::Runtime::use_package_optimistically($_[2]) }
399 Carp::croak("Could not load $_[1] '$_[2]': $err") if defined $err;
403 eval { Module::Runtime::use_package_optimistically($_[2]) }
404 or Carp::croak("Could not load $_[1] '$_[2]': $@");
408 $_[0]->set_inherited($_[1], $_[2]);
411 =head1 INTERNAL METHODS
413 These methods are documented for clarity, but are never meant to be called
414 directly, and are not really meant for overriding either.
416 =head2 get_super_paths
418 Returns a list of 'parent' or 'super' class names that the current class
419 inherited from. This is what drives the traversal done by L</get_inherited>.
423 sub get_super_paths {
424 # get_linear_isa returns the class itself as the 1st element
425 # use @_ as a pre-allocated scratch array
426 (undef, @_) = @{mro::get_linear_isa( length( ref($_[0]) ) ? ref($_[0]) : $_[0] )};
430 =head2 make_group_accessor
432 __PACKAGE__->make_group_accessor('simple', 'hair_length', 'hair_length');
433 __PACKAGE__->make_group_accessor('simple', 'hc', 'hair_color');
437 =item Arguments: $group, $field, $accessor
439 Returns: \&accessor_coderef ?
443 Called by mk_group_accessors for each entry in @fieldspec. Either returns
444 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
445 C<undef> if it elects to install the coderef on its own.
449 sub make_group_accessor { $gen_accessor->('rw', @_) }
451 =head2 make_group_ro_accessor
453 __PACKAGE__->make_group_ro_accessor('simple', 'birthdate', 'birthdate');
454 __PACKAGE__->make_group_ro_accessor('simple', 'ssn', 'social_security_number');
458 =item Arguments: $group, $field, $accessor
460 Returns: \&accessor_coderef ?
464 Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
465 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
466 C<undef> if it elects to install the coderef on its own.
470 sub make_group_ro_accessor { $gen_accessor->('ro', @_) }
472 =head2 make_group_wo_accessor
474 __PACKAGE__->make_group_wo_accessor('simple', 'lie', 'lie');
475 __PACKAGE__->make_group_wo_accessor('simple', 'subj', 'subject');
479 =item Arguments: $group, $field, $accessor
481 Returns: \&accessor_coderef ?
485 Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
486 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
487 C<undef> if it elects to install the coderef on its own.
491 sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
496 To provide total flexibility L<Class::Accessor::Grouped> calls methods
497 internally while performing get/set actions, which makes it noticeably
498 slower than similar modules. To compensate, this module will automatically
499 use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
500 accessors if this module is available on your system.
504 This is the result of a set/get/set loop benchmark on perl 5.12.1 with
505 thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
506 L<Moo>, L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>,
507 L<XSA|Class::XSAccessor>, and L<CAF_XSA|Class::XSAccessor::Compat>:
509 Rate CAG moOse CAF moUse moo HANDMADE CAF_XS moUse_XS moo_XS CAF_XSA XSA CAG_XS
510 CAG 169/s -- -21% -24% -32% -32% -34% -59% -63% -67% -67% -67% -67%
511 moOse 215/s 27% -- -3% -13% -13% -15% -48% -53% -58% -58% -58% -58%
512 CAF 222/s 31% 3% -- -10% -10% -13% -46% -52% -57% -57% -57% -57%
513 moUse 248/s 46% 15% 11% -- -0% -3% -40% -46% -52% -52% -52% -52%
514 moo 248/s 46% 15% 11% 0% -- -3% -40% -46% -52% -52% -52% -52%
515 HANDMADE 255/s 50% 18% 14% 3% 3% -- -38% -45% -50% -51% -51% -51%
516 CAF_XS 411/s 143% 91% 85% 66% 66% 61% -- -11% -20% -20% -21% -21%
517 moUse_XS 461/s 172% 114% 107% 86% 86% 81% 12% -- -10% -11% -11% -11%
518 moo_XS 514/s 204% 139% 131% 107% 107% 102% 25% 12% -- -0% -1% -1%
519 CAF_XSA 516/s 205% 140% 132% 108% 108% 103% 26% 12% 0% -- -0% -0%
520 XSA 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% -- -0%
521 CAG_XS 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% 0% --
523 Benchmark program is available in the root of the
524 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
526 =head2 Notes on Class::XSAccessor
528 You can force (or disable) the use of L<Class::XSAccessor> before creating a
529 particular C<simple> accessor by either manipulating the global variable
530 C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
531 L<localization|perlfunc/local>, or you can do so before runtime via the
532 C<CAG_USE_XS> environment variable.
534 Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
535 L</set_simple> this module does its best to detect if you are overriding
536 one of these methods and will fall back to using the perl version of the
537 accessor in order to maintain consistency. However be aware that if you
538 enable use of C<Class::XSAccessor> (automatically or explicitly), create
539 an object, invoke a simple accessor on that object, and B<then> manipulate
540 the symbol table to install a C<get/set_simple> override - you get to keep
545 Matt S. Trout <mst@shadowcatsystems.co.uk>
547 Christopher H. Laco <claco@chrislaco.com>
551 Caelum: Rafael Kitover <rkitover@cpan.org>
553 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
555 groditi: Guillermo Roditi <groditi@cpan.org>
557 Jason Plum <jason.plum@bmmsi.com>
559 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
562 =head1 COPYRIGHT & LICENSE
564 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
566 This program is free software; you can redistribute it and/or modify
567 it under the same terms as perl itself.
571 ########################################################################
572 ########################################################################
573 ########################################################################
575 # Here be many angry dragons
576 # (all code is in private coderefs since everything inherits CAG)
578 ########################################################################
579 ########################################################################
581 # Autodetect unless flag supplied
582 my $xsa_autodetected;
583 if (! defined $USE_XS) {
584 $USE_XS = __CAG_ENV__::NO_CXSA ? 0 : 1;
590 require Data::Dumper;
591 my $d = Data::Dumper->new([])->Indent(0)->Purity(0)->Pad('')->Useqq(1)->Terse(1)->Freezer('')->Toaster('');
592 $perlstring = sub { $d->Values([shift])->Dump };
596 $perlstring = \&B::perlstring;
600 my $maker_templates = {
602 cxsa_call => 'accessors',
603 pp_generator => sub {
604 # my ($group, $fieldname) = @_;
605 my $quoted_fieldname = $perlstring->($_[1]);
606 sprintf <<'EOS', ($_[0], $quoted_fieldname) x 2;
609 ? shift->set_%s(%s, @_)
616 cxsa_call => 'getters',
617 pp_generator => sub {
618 # my ($group, $fieldname) = @_;
619 my $quoted_fieldname = $perlstring->($_[1]);
620 sprintf <<'EOS', $_[0], $quoted_fieldname;
624 my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
625 my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
627 "'$meth' cannot alter its value (read-only attribute of class $class)"
636 cxsa_call => 'setters',
637 pp_generator => sub {
638 # my ($group, $fieldname) = @_;
639 my $quoted_fieldname = $perlstring->($_[1]);
640 sprintf <<'EOS', $_[0], $quoted_fieldname;
643 ? shift->set_%s(%s, @_)
645 my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
646 my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
648 "'$meth' cannot access its value (write-only attribute of class $class)"
658 my ($accessor_maker_cache, $no_xsa_warned_classes);
660 # can't use pkg_gen to track this stuff, as it doesn't
661 # detect superclass mucking
662 my $original_simple_getter = __PACKAGE__->can ('get_simple');
663 my $original_simple_setter = __PACKAGE__->can ('set_simple');
665 # Note!!! Unusual signature
666 $gen_accessor = sub {
667 my ($type, $class, $group, $field, $methname) = @_;
668 $class = ref $class if length ref $class;
670 # When installing an XSA simple accessor, we need to make sure we are not
671 # short-circuiting a (compile or runtime) get_simple/set_simple override.
672 # What we do here is install a lazy first-access check, which will decide
673 # the ultimate coderef being placed in the accessor slot
675 # Also note that the *original* class will always retain this shim, as
676 # different branches inheriting from it may have different overrides.
677 # Thus the final method (properly labeled and all) is installed in the
678 # calling-package's namespace
679 if ($USE_XS and $group eq 'simple') {
680 die sprintf( "Class::XSAccessor requested but not available:\n%s\n", __CAG_ENV__::NO_CXSA )
681 if __CAG_ENV__::NO_CXSA;
683 my ($expected_cref, $cached_implementation);
684 my $ret = $expected_cref = sub {
685 my $current_class = length (ref ($_[0] ) ) ? ref ($_[0]) : $_[0];
687 # $cached_implementation will be set only if the shim got
688 # 'around'ed, in which case it is handy to avoid re-running
689 # this block over and over again
690 my $resolved_implementation = $cached_implementation->{$current_class} || do {
692 ($current_class->can('get_simple')||0) == $original_simple_getter
694 ($current_class->can('set_simple')||0) == $original_simple_setter
696 # nothing has changed, might as well use the XS crefs
698 # note that by the time this code executes, we already have
699 # *objects* (since XSA works on 'simple' only by definition).
700 # If someone is mucking with the symbol table *after* there
701 # are some objects already - look! many, shiny pieces! :)
703 # The weird breeder thingy is because XSA does not have an
704 # interface returning *just* a coderef, without installing it
706 Class::XSAccessor->import(
708 class => '__CAG__XSA__BREEDER__',
709 $maker_templates->{$type}{cxsa_call} => {
713 __CAG__XSA__BREEDER__->can($methname);
716 if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
717 # not using Carp since the line where this happens doesn't mean much
718 warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
719 . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
724 # that's faster than local
726 my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
733 # if after this shim was created someone wrapped it with an 'around',
734 # we can not blindly reinstall the method slot - we will destroy the
735 # wrapper. Silently chain execution further...
736 if ( !$expected_cref or $expected_cref != ($current_class->can($methname)||0) ) {
738 # there is no point in re-determining it on every subsequent call,
739 # just store for future reference
740 $cached_implementation->{$current_class} ||= $resolved_implementation;
742 # older perls segfault if the cref behind the goto throws
743 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
744 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
746 goto $resolved_implementation;
749 if (__CAG_ENV__::TRACK_UNDEFER_FAIL) {
750 my $deferred_calls_seen = do {
752 \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
754 my @cframe = caller(0);
755 if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
757 "Deferred version of method $cframe[3] invoked more than once (originally "
758 . "invoked at $already_seen). This is a strong indication your code has "
759 . 'cached the original ->can derived method coderef, and is using it instead '
760 . 'of the proper method re-lookup, causing minor performance regressions'
764 $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
768 # install the resolved implementation into the code slot so we do not
769 # come here anymore (hopefully)
770 # since XSAccessor was available - so is Sub::Name
773 no warnings 'redefine';
775 my $fq_name = "${current_class}::${methname}";
776 *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
778 # need to update what the shim expects too *in case* its
779 # ->can was cached for some moronic reason
780 $expected_cref = $resolved_implementation;
781 Scalar::Util::weaken($expected_cref);
784 # older perls segfault if the cref behind the goto throws
785 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
786 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
788 goto $resolved_implementation;
791 Scalar::Util::weaken($expected_cref); # to break the self-reference
795 # no Sub::Name - just install the coderefs directly (compiling every time)
796 elsif (__CAG_ENV__::NO_SUBNAME) {
797 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
798 $maker_templates->{$type}{pp_generator}->($group, $field);
800 no warnings 'redefine';
801 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
802 eval "sub ${class}::${methname} { $src }";
804 undef; # so that no further attempt will be made to install anything
807 # a coderef generator with a variable pad (returns a fresh cref on every invocation)
809 ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
810 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
811 $maker_templates->{$type}{pp_generator}->($group, $field);
813 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
814 eval "sub { my \$dummy; sub { \$dummy if 0; $src } }" or die $@;