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.10006';
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.13' }
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')
47 constant->import( NO_CXSA => ( !NO_SUBNAME() and eval {
48 Module::Runtime::use_module('Class::XSAccessor' => $__minimum_xsa_version)
51 constant->import( BROKEN_GOTO => ($] < '5.008009') ? 1 : 0 );
53 constant->import( UNSTABLE_DOLLARAT => ($] < '5.013002') ? 1 : 0 );
55 constant->import( TRACK_UNDEFER_FAIL => (
56 $INC{'Test/Builder.pm'} || $INC{'Test/Builder2.pm'}
58 $0 =~ m|^ x?t / .+ \.t $|x
62 # Yes this method is undocumented
63 # Yes it should be a private coderef like all the rest at the end of this file
64 # No we can't do that (yet) because the DBIC-CDBI compat layer overrides it
66 sub _mk_group_accessors {
67 my($self, $maker, $group, @fields) = @_;
68 my $class = length (ref ($self) ) ? ref ($self) : $self;
71 no warnings 'redefine';
73 # So we don't have to do lots of lookups inside the loop.
74 $maker = $self->can($maker) unless ref $maker;
78 my ($name, $field) = (ref $_) ? (@$_) : ($_, $_);
80 for (qw/DESTROY AUTOLOAD CLONE/) {
81 Carp::carp("Having a data accessor named '$name' in '$class' is unwise.")
85 my $alias = "_${name}_accessor";
89 # the maker may elect to not return anything, meaning it already
90 # installed the coderef for us (e.g. lack of Sub::Name)
91 my $cref = $self->$maker($group, $field, $_)
94 my $fq_meth = "${class}::$_";
96 *$fq_meth = Sub::Name::subname($fq_meth, $cref);
97 #unless defined &{$class."\:\:$field"}
102 # coderef is setup at the end for clarity
107 Class::Accessor::Grouped - Lets you build groups of accessors
111 use base 'Class::Accessor::Grouped';
113 # make basic accessors for objects
114 __PACKAGE__->mk_group_accessors(simple => qw(id name email));
116 # make accessor that works for objects and classes
117 __PACKAGE__->mk_group_accessors(inherited => 'awesome_level');
121 This class lets you build groups of accessors that will call different
126 =head2 mk_group_accessors
128 __PACKAGE__->mk_group_accessors(simple => 'hair_length', [ hair_color => 'hc' ]);
132 =item Arguments: $group, @fieldspec
138 Creates a set of accessors in a given group.
140 $group is the name of the accessor group for the generated accessors; they
141 will call get_$group($field) on get and set_$group($field, $value) on set.
143 If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
144 to tell Class::Accessor::Grouped to use its own get_simple and set_simple
147 @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
148 this is used as both field and accessor name, if a listref it is expected to
149 be of the form [ $accessor, $field ].
153 sub mk_group_accessors {
154 my ($self, $group, @fields) = @_;
156 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
160 =head2 mk_group_ro_accessors
162 __PACKAGE__->mk_group_ro_accessors(simple => 'birthdate', [ social_security_number => 'ssn' ]);
166 =item Arguments: $group, @fieldspec
172 Creates a set of read only accessors in a given group. Identical to
173 L</mk_group_accessors> but accessors will throw an error if passed a value
174 rather than setting the value.
178 sub mk_group_ro_accessors {
179 my($self, $group, @fields) = @_;
181 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
185 =head2 mk_group_wo_accessors
187 __PACKAGE__->mk_group_wo_accessors(simple => 'lie', [ subject => 'subj' ]);
191 =item Arguments: $group, @fieldspec
197 Creates a set of write only accessors in a given group. Identical to
198 L</mk_group_accessors> but accessors will throw an error if not passed a
199 value rather than getting the value.
203 sub mk_group_wo_accessors {
204 my($self, $group, @fields) = @_;
206 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
214 =item Arguments: $field
220 Simple getter for hash-based objects which returns the value for the field
221 name passed as an argument.
233 =item Arguments: $field, $new_value
239 Simple setter for hash-based objects which sets and then returns the value
240 for the field name passed as an argument.
245 $_[0]->{$_[1]} = $_[2];
253 =item Arguments: $field
259 Simple getter for Classes and hash-based objects which returns the value for
260 the field name passed as an argument. This behaves much like
261 L<Class::Data::Accessor> where the field can be set in a base class,
262 inherited and changed in subclasses, and inherited and changed for object
268 if ( length (ref ($_[0]) ) ) {
269 if (Scalar::Util::reftype $_[0] eq 'HASH') {
270 return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
271 # everything in @_ is aliased, an assignment won't work
272 splice @_, 0, 1, ref($_[0]);
275 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
279 # if we got this far there is nothing in the instance
280 # OR this is a class call
281 # in any case $_[0] contains the class name (see splice above)
283 no warnings 'uninitialized';
285 my $cag_slot = '::__cag_'. $_[1];
286 return ${$_[0].$cag_slot} if defined(${$_[0].$cag_slot});
288 do { return ${$_.$cag_slot} if defined(${$_.$cag_slot}) }
289 for $_[0]->get_super_paths;
298 =item Arguments: $field, $new_value
304 Simple setter for Classes and hash-based objects which sets and then returns
305 the value for the field name passed as an argument. When called on a hash-based
306 object it will set the appropriate hash key value. When called on a class, it
307 will set a class level variable.
309 B<Note:>: This method will die if you try to set an object variable on a non
315 if (length (ref ($_[0]) ) ) {
316 if (Scalar::Util::reftype $_[0] eq 'HASH') {
317 return $_[0]->{$_[1]} = $_[2];
319 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
324 ${$_[0].'::__cag_'.$_[1]} = $_[2];
327 =head2 get_component_class
331 =item Arguments: $field
337 Gets the value of the specified component class.
339 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
341 $self->result_class->method();
344 $self->get_component_class('result_class')->method();
348 sub get_component_class {
349 $_[0]->get_inherited($_[1]);
352 =head2 set_component_class
356 =item Arguments: $field, $class
362 Inherited accessor that automatically loads the specified class before setting
363 it. This method will die if the specified class could not be loaded.
365 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
366 __PACKAGE__->result_class('MyClass');
368 $self->result_class->method();
372 sub set_component_class {
373 if (defined $_[2] and length $_[2]) {
374 # disable warnings, and prevent $_ being eaten away by a behind-the-scenes
378 if (__CAG_ENV__::UNSTABLE_DOLLARAT) {
382 eval { Module::Runtime::use_package_optimistically($_[2]) }
385 Carp::croak("Could not load $_[1] '$_[2]': $err") if defined $err;
389 eval { Module::Runtime::use_package_optimistically($_[2]) }
390 or Carp::croak("Could not load $_[1] '$_[2]': $@");
394 $_[0]->set_inherited($_[1], $_[2]);
397 =head1 INTERNAL METHODS
399 These methods are documented for clarity, but are never meant to be called
400 directly, and are not really meant for overriding either.
402 =head2 get_super_paths
404 Returns a list of 'parent' or 'super' class names that the current class
405 inherited from. This is what drives the traversal done by L</get_inherited>.
409 sub get_super_paths {
410 # get_linear_isa returns the class itself as the 1st element
411 # use @_ as a pre-allocated scratch array
412 (undef, @_) = @{mro::get_linear_isa( length( ref($_[0]) ) ? ref($_[0]) : $_[0] )};
416 =head2 make_group_accessor
418 __PACKAGE__->make_group_accessor('simple', 'hair_length', 'hair_length');
419 __PACKAGE__->make_group_accessor('simple', 'hc', 'hair_color');
423 =item Arguments: $group, $field, $accessor
425 Returns: \&accessor_coderef ?
429 Called by mk_group_accessors for each entry in @fieldspec. Either returns
430 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
431 C<undef> if it elects to install the coderef on its own.
435 sub make_group_accessor { $gen_accessor->('rw', @_) }
437 =head2 make_group_ro_accessor
439 __PACKAGE__->make_group_ro_accessor('simple', 'birthdate', 'birthdate');
440 __PACKAGE__->make_group_ro_accessor('simple', 'ssn', 'social_security_number');
444 =item Arguments: $group, $field, $accessor
446 Returns: \&accessor_coderef ?
450 Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
451 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
452 C<undef> if it elects to install the coderef on its own.
456 sub make_group_ro_accessor { $gen_accessor->('ro', @_) }
458 =head2 make_group_wo_accessor
460 __PACKAGE__->make_group_wo_accessor('simple', 'lie', 'lie');
461 __PACKAGE__->make_group_wo_accessor('simple', 'subj', 'subject');
465 =item Arguments: $group, $field, $accessor
467 Returns: \&accessor_coderef ?
471 Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
472 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
473 C<undef> if it elects to install the coderef on its own.
477 sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
482 To provide total flexibility L<Class::Accessor::Grouped> calls methods
483 internally while performing get/set actions, which makes it noticeably
484 slower than similar modules. To compensate, this module will automatically
485 use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
486 accessors if this module is available on your system.
490 This is the result of a set/get/set loop benchmark on perl 5.12.1 with
491 thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
492 L<Moo>, L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>,
493 L<XSA|Class::XSAccessor>, and L<CAF_XSA|Class::XSAccessor::Compat>:
495 Rate CAG moOse CAF moUse moo HANDMADE CAF_XS moUse_XS moo_XS CAF_XSA XSA CAG_XS
496 CAG 169/s -- -21% -24% -32% -32% -34% -59% -63% -67% -67% -67% -67%
497 moOse 215/s 27% -- -3% -13% -13% -15% -48% -53% -58% -58% -58% -58%
498 CAF 222/s 31% 3% -- -10% -10% -13% -46% -52% -57% -57% -57% -57%
499 moUse 248/s 46% 15% 11% -- -0% -3% -40% -46% -52% -52% -52% -52%
500 moo 248/s 46% 15% 11% 0% -- -3% -40% -46% -52% -52% -52% -52%
501 HANDMADE 255/s 50% 18% 14% 3% 3% -- -38% -45% -50% -51% -51% -51%
502 CAF_XS 411/s 143% 91% 85% 66% 66% 61% -- -11% -20% -20% -21% -21%
503 moUse_XS 461/s 172% 114% 107% 86% 86% 81% 12% -- -10% -11% -11% -11%
504 moo_XS 514/s 204% 139% 131% 107% 107% 102% 25% 12% -- -0% -1% -1%
505 CAF_XSA 516/s 205% 140% 132% 108% 108% 103% 26% 12% 0% -- -0% -0%
506 XSA 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% -- -0%
507 CAG_XS 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% 0% --
509 Benchmark program is available in the root of the
510 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
512 =head2 Notes on Class::XSAccessor
514 You can force (or disable) the use of L<Class::XSAccessor> before creating a
515 particular C<simple> accessor by either manipulating the global variable
516 C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
517 L<localization|perlfunc/local>, or you can do so before runtime via the
518 C<CAG_USE_XS> environment variable.
520 Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
521 L</set_simple> this module does its best to detect if you are overriding
522 one of these methods and will fall back to using the perl version of the
523 accessor in order to maintain consistency. However be aware that if you
524 enable use of C<Class::XSAccessor> (automatically or explicitly), create
525 an object, invoke a simple accessor on that object, and B<then> manipulate
526 the symbol table to install a C<get/set_simple> override - you get to keep
531 Matt S. Trout <mst@shadowcatsystems.co.uk>
533 Christopher H. Laco <claco@chrislaco.com>
537 Caelum: Rafael Kitover <rkitover@cpan.org>
539 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
541 groditi: Guillermo Roditi <groditi@cpan.org>
543 Jason Plum <jason.plum@bmmsi.com>
545 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
548 =head1 COPYRIGHT & LICENSE
550 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
552 This program is free software; you can redistribute it and/or modify
553 it under the same terms as perl itself.
557 ########################################################################
558 ########################################################################
559 ########################################################################
561 # Here be many angry dragons
562 # (all code is in private coderefs since everything inherits CAG)
564 ########################################################################
565 ########################################################################
567 # Autodetect unless flag supplied
568 my $xsa_autodetected;
569 if (! defined $USE_XS) {
570 $USE_XS = __CAG_ENV__::NO_CXSA ? 0 : 1;
574 my $maker_templates = {
576 xs_call => 'accessors',
578 my $set = "set_$_[0]";
579 my $get = "get_$_[0]";
585 ? shift->$set('$field', \@_)
586 : shift->$get('$field')
591 xs_call => 'getters',
593 my $get = "get_$_[0]";
599 ? shift->$get('$field')
601 my \$caller = caller;
602 my \$class = length( ref(\$_[0]) ) ? ref(\$_[0]) : \$_[0];
603 Carp::croak(\"'\$caller' cannot alter the value of '$field' \".
604 \"(read-only attributes of class '\$class')\");
610 xs_call => 'setters',
612 my $set = "set_$_[0]";
618 ? shift->$set('$field', \@_)
620 my \$caller = caller;
621 my \$class = length ( ref(\$_[0]) ) ? ref(\$_[0]) : \$_[0];
622 Carp::croak(\"'\$caller' cannot access the value of '$field' \".
623 \"(write-only attributes of class '\$class')\");
631 my ($accessor_maker_cache, $no_xsa_warned_classes);
633 # can't use pkg_gen to track this stuff, as it doesn't
634 # detect superclass mucking
635 my $original_simple_getter = __PACKAGE__->can ('get_simple');
636 my $original_simple_setter = __PACKAGE__->can ('set_simple');
638 # Note!!! Unusual signature
639 $gen_accessor = sub {
640 my ($type, $class, $group, $field, $methname) = @_;
641 $class = ref $class if length ref $class;
643 # When installing an XSA simple accessor, we need to make sure we are not
644 # short-circuiting a (compile or runtime) get_simple/set_simple override.
645 # What we do here is install a lazy first-access check, which will decide
646 # the ultimate coderef being placed in the accessor slot
648 # Also note that the *original* class will always retain this shim, as
649 # different branches inheriting from it may have different overrides.
650 # Thus the final method (properly labeled and all) is installed in the
651 # calling-package's namespace
652 if ($USE_XS and $group eq 'simple') {
653 die sprintf( "Class::XSAccessor requested but not available:\n%s\n", __CAG_ENV__::NO_CXSA )
654 if __CAG_ENV__::NO_CXSA;
656 my ($expected_cref, $cached_implementation);
657 my $ret = $expected_cref = sub {
658 my $current_class = length (ref ($_[0] ) ) ? ref ($_[0]) : $_[0];
660 # $cached_implementation will be set only if the shim got
661 # 'around'ed, in which case it is handy to avoid re-running
662 # this block over and over again
663 my $resolved_implementation = $cached_implementation->{$current_class} || do {
665 ($current_class->can('get_simple')||0) == $original_simple_getter
667 ($current_class->can('set_simple')||0) == $original_simple_setter
669 # nothing has changed, might as well use the XS crefs
671 # note that by the time this code executes, we already have
672 # *objects* (since XSA works on 'simple' only by definition).
673 # If someone is mucking with the symbol table *after* there
674 # are some objects already - look! many, shiny pieces! :)
676 # The weird breeder thingy is because XSA does not have an
677 # interface returning *just* a coderef, without installing it
679 Class::XSAccessor->import(
681 class => '__CAG__XSA__BREEDER__',
682 $maker_templates->{$type}{xs_call} => {
686 __CAG__XSA__BREEDER__->can($methname);
689 if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
690 # not using Carp since the line where this happens doesn't mean much
691 warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
692 . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
697 # that's faster than local
699 my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
706 # if after this shim was created someone wrapped it with an 'around',
707 # we can not blindly reinstall the method slot - we will destroy the
708 # wrapper. Silently chain execution further...
709 if ( !$expected_cref or $expected_cref != ($current_class->can($methname)||0) ) {
711 # there is no point in re-determining it on every subsequent call,
712 # just store for future reference
713 $cached_implementation->{$current_class} ||= $resolved_implementation;
715 # older perls segfault if the cref behind the goto throws
716 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
717 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
719 goto $resolved_implementation;
722 if (__CAG_ENV__::TRACK_UNDEFER_FAIL) {
723 my $deferred_calls_seen = do {
725 \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
727 my @cframe = caller(0);
728 if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
730 "Deferred version of method $cframe[3] invoked more than once (originally "
731 . "invoked at $already_seen). This is a strong indication your code has "
732 . 'cached the original ->can derived method coderef, and is using it instead '
733 . 'of the proper method re-lookup, causing performance regressions'
737 $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
741 # install the resolved implementation into the code slot so we do not
742 # come here anymore (hopefully)
743 # since XSAccessor was available - so is Sub::Name
746 no warnings 'redefine';
748 my $fq_name = "${current_class}::${methname}";
749 *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
751 # need to update what the shim expects too *in case* its
752 # ->can was cached for some moronic reason
753 $expected_cref = $resolved_implementation;
754 Scalar::Util::weaken($expected_cref);
757 # older perls segfault if the cref behind the goto throws
758 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
759 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
761 goto $resolved_implementation;
764 Scalar::Util::weaken($expected_cref); # to break the self-reference
768 # no Sub::Name - just install the coderefs directly (compiling every time)
769 elsif (__CAG_ENV__::NO_SUBNAME) {
770 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
771 $maker_templates->{$type}{pp_code}->($group, $field);
773 no warnings 'redefine';
774 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
775 eval "sub ${class}::${methname} { $src }";
777 undef; # so that no further attempt will be made to install anything
780 # a coderef generator with a variable pad (returns a fresh cref on every invocation)
782 ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
783 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
784 $maker_templates->{$type}{pp_code}->($group, $field);
786 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
787 eval "sub { my \$dummy; sub { \$dummy if 0; $src } }" or die $@;