1 package Class::Accessor::Grouped;
16 our $VERSION = '0.10004';
17 $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
19 # when changing minimum version don't forget to adjust Makefile.PL as well
20 our $__minimum_xsa_version;
21 BEGIN { $__minimum_xsa_version = '1.13' }
24 # the unless defined is here so that we can override the value
25 # before require/use, *regardless* of the state of $ENV{CAG_USE_XS}
26 $USE_XS = $ENV{CAG_USE_XS}
27 unless defined $USE_XS;
29 # Yes this method is undocumented
30 # Yes it should be a private coderef like all the rest at the end of this file
31 # No we can't do that (yet) because the DBIC-CDBI compat layer overrides it
33 sub _mk_group_accessors {
34 my($self, $maker, $group, @fields) = @_;
35 my $class = Scalar::Util::blessed $self || $self;
38 no warnings 'redefine';
40 # So we don't have to do lots of lookups inside the loop.
41 $maker = $self->can($maker) unless ref $maker;
44 if( $_ eq 'DESTROY' ) {
45 Carp::carp("Having a data accessor named DESTROY in ".
46 "'$class' is unwise.");
49 my ($name, $field) = (ref $_)
54 my $alias = "_${name}_accessor";
56 for my $meth ($name, $alias) {
58 # the maker may elect to not return anything, meaning it already
59 # installed the coderef for us (e.g. lack of Sub::Name)
60 my $cref = $self->$maker($group, $field, $meth)
63 my $fq_meth = "${class}::${meth}";
65 *$fq_meth = Sub::Name::subname($fq_meth, $cref);
66 #unless defined &{$class."\:\:$field"}
71 # coderef is setup at the end for clarity
76 Class::Accessor::Grouped - Lets you build groups of accessors
80 use base 'Class::Accessor::Grouped';
82 # make basic accessors for objects
83 __PACKAGE__->mk_group_accessors(simple => qw(id name email));
85 # make accessor that works for objects and classes
86 __PACKAGE__->mk_group_accessors(inherited => 'awesome_level');
90 This class lets you build groups of accessors that will call different
95 =head2 mk_group_accessors
97 __PACKAGE__->mk_group_accessors(simple => 'hair_length', [ hair_color => 'hc' ]);
101 =item Arguments: $group, @fieldspec
107 Creates a set of accessors in a given group.
109 $group is the name of the accessor group for the generated accessors; they
110 will call get_$group($field) on get and set_$group($field, $value) on set.
112 If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
113 to tell Class::Accessor::Grouped to use its own get_simple and set_simple
116 @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
117 this is used as both field and accessor name, if a listref it is expected to
118 be of the form [ $accessor, $field ].
122 sub mk_group_accessors {
123 my ($self, $group, @fields) = @_;
125 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
129 =head2 mk_group_ro_accessors
131 __PACKAGE__->mk_group_ro_accessors(simple => 'birthdate', [ social_security_number => 'ssn' ]);
135 =item Arguments: $group, @fieldspec
141 Creates a set of read only accessors in a given group. Identical to
142 L</mk_group_accessors> but accessors will throw an error if passed a value
143 rather than setting the value.
147 sub mk_group_ro_accessors {
148 my($self, $group, @fields) = @_;
150 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
153 =head2 mk_group_wo_accessors
155 __PACKAGE__->mk_group_wo_accessors(simple => 'lie', [ subject => 'subj' ]);
159 =item Arguments: $group, @fieldspec
165 Creates a set of write only accessors in a given group. Identical to
166 L</mk_group_accessors> but accessors will throw an error if not passed a
167 value rather than getting the value.
171 sub mk_group_wo_accessors {
172 my($self, $group, @fields) = @_;
174 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
181 =item Arguments: $field
187 Simple getter for hash-based objects which returns the value for the field
188 name passed as an argument.
193 return $_[0]->{$_[1]};
200 =item Arguments: $field, $new_value
206 Simple setter for hash-based objects which sets and then returns the value
207 for the field name passed as an argument.
212 return $_[0]->{$_[1]} = $_[2];
220 =item Arguments: $field
226 Simple getter for Classes and hash-based objects which returns the value for
227 the field name passed as an argument. This behaves much like
228 L<Class::Data::Accessor> where the field can be set in a base class,
229 inherited and changed in subclasses, and inherited and changed for object
237 if ( defined( $class = Scalar::Util::blessed $_[0] ) ) {
238 if (Scalar::Util::reftype $_[0] eq 'HASH') {
239 return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
242 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
250 no warnings 'uninitialized';
252 my $cag_slot = '::__cag_'. $_[1];
253 return ${$class.$cag_slot} if defined(${$class.$cag_slot});
255 # we need to be smarter about recalculation, as @ISA (thus supers) can very well change in-flight
256 my $cur_gen = mro::get_pkg_gen ($class);
257 if ( $cur_gen != ${$class.'::__cag_pkg_gen__'} ) {
258 @{$class.'::__cag_supers__'} = $_[0]->get_super_paths;
259 ${$class.'::__cag_pkg_gen__'} = $cur_gen;
262 for (@{$class.'::__cag_supers__'}) {
263 return ${$_.$cag_slot} if defined(${$_.$cag_slot});
273 =item Arguments: $field, $new_value
279 Simple setter for Classes and hash-based objects which sets and then returns
280 the value for the field name passed as an argument. When called on a hash-based
281 object it will set the appropriate hash key value. When called on a class, it
282 will set a class level variable.
284 B<Note:>: This method will die if you try to set an object variable on a non
290 if (defined Scalar::Util::blessed $_[0]) {
291 if (Scalar::Util::reftype $_[0] eq 'HASH') {
292 return $_[0]->{$_[1]} = $_[2];
294 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
299 return ${$_[0].'::__cag_'.$_[1]} = $_[2];
303 =head2 get_component_class
307 =item Arguments: $field
313 Gets the value of the specified component class.
315 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
317 $self->result_class->method();
320 $self->get_component_class('result_class')->method();
324 sub get_component_class {
325 return $_[0]->get_inherited($_[1]);
328 =head2 set_component_class
332 =item Arguments: $field, $class
338 Inherited accessor that automatically loads the specified class before setting
339 it. This method will die if the specified class could not be loaded.
341 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
342 __PACKAGE__->result_class('MyClass');
344 $self->result_class->method();
348 sub set_component_class {
351 require Class::Inspector;
352 if (Class::Inspector->installed($_[2]) && !Class::Inspector->loaded($_[2])) {
353 eval "require $_[2]";
355 Carp::croak("Could not load $_[1] '$_[2]': ", $@) if $@;
359 return $_[0]->set_inherited($_[1], $_[2]);
362 =head1 INTERNAL METHODS
364 These methods are documented for clarity, but are never meant to be called
365 directly, and are not really meant for overriding either.
367 =head2 get_super_paths
369 Returns a list of 'parent' or 'super' class names that the current class
370 inherited from. This is what drives the traversal done by L</get_inherited>.
374 sub get_super_paths {
375 return @{mro::get_linear_isa( ref($_[0]) || $_[0] )};
378 =head2 make_group_accessor
380 __PACKAGE__->make_group_accessor('simple', 'hair_length', 'hair_length');
381 __PACKAGE__->make_group_accessor('simple', 'hc', 'hair_color');
385 =item Arguments: $group, $field, $accessor
387 Returns: \&accessor_coderef ?
391 Called by mk_group_accessors for each entry in @fieldspec. Either returns
392 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
393 C<undef> if it elects to install the coderef on its own.
397 sub make_group_accessor { $gen_accessor->('rw', @_) }
399 =head2 make_group_ro_accessor
401 __PACKAGE__->make_group_ro_accessor('simple', 'birthdate', 'birthdate');
402 __PACKAGE__->make_group_ro_accessor('simple', 'ssn', 'social_security_number');
406 =item Arguments: $group, $field, $accessor
408 Returns: \&accessor_coderef ?
412 Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
413 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
414 C<undef> if it elects to install the coderef on its own.
418 sub make_group_ro_accessor { $gen_accessor->('ro', @_) }
420 =head2 make_group_wo_accessor
422 __PACKAGE__->make_group_wo_accessor('simple', 'lie', 'lie');
423 __PACKAGE__->make_group_wo_accessor('simple', 'subj', 'subject');
427 =item Arguments: $group, $field, $accessor
429 Returns: \&accessor_coderef ?
433 Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
434 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
435 C<undef> if it elects to install the coderef on its own.
439 sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
444 To provide total flexibility L<Class::Accessor::Grouped> calls methods
445 internally while performing get/set actions, which makes it noticeably
446 slower than similar modules. To compensate, this module will automatically
447 use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
448 accessors if this module is available on your system.
452 This is the result of a set/get/set loop benchmark on perl 5.12.1 with
453 thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
454 L<Moo>, L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>,
455 L<XSA|Class::XSAccessor>, and L<CAF_XSA|Class::XSAccessor::Compat>:
457 Rate CAG moOse CAF moUse moo HANDMADE CAF_XS moUse_XS moo_XS CAF_XSA XSA CAG_XS
458 CAG 169/s -- -21% -24% -32% -32% -34% -59% -63% -67% -67% -67% -67%
459 moOse 215/s 27% -- -3% -13% -13% -15% -48% -53% -58% -58% -58% -58%
460 CAF 222/s 31% 3% -- -10% -10% -13% -46% -52% -57% -57% -57% -57%
461 moUse 248/s 46% 15% 11% -- -0% -3% -40% -46% -52% -52% -52% -52%
462 moo 248/s 46% 15% 11% 0% -- -3% -40% -46% -52% -52% -52% -52%
463 HANDMADE 255/s 50% 18% 14% 3% 3% -- -38% -45% -50% -51% -51% -51%
464 CAF_XS 411/s 143% 91% 85% 66% 66% 61% -- -11% -20% -20% -21% -21%
465 moUse_XS 461/s 172% 114% 107% 86% 86% 81% 12% -- -10% -11% -11% -11%
466 moo_XS 514/s 204% 139% 131% 107% 107% 102% 25% 12% -- -0% -1% -1%
467 CAF_XSA 516/s 205% 140% 132% 108% 108% 103% 26% 12% 0% -- -0% -0%
468 XSA 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% -- -0%
469 CAG_XS 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% 0% --
471 Benchmark program is available in the root of the
472 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
474 =head2 Notes on Class::XSAccessor
476 You can force (or disable) the use of L<Class::XSAccessor> before creating a
477 particular C<simple> accessor by either manipulating the global variable
478 C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
479 L<localization|perlfunc/local>, or you can do so before runtime via the
480 C<CAG_USE_XS> environment variable.
482 Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
483 L</set_simple> this module does its best to detect if you are overriding
484 one of these methods and will fall back to using the perl version of the
485 accessor in order to maintain consistency. However be aware that if you
486 enable use of C<Class::XSAccessor> (automatically or explicitly), create
487 an object, invoke a simple accessor on that object, and B<then> manipulate
488 the symbol table to install a C<get/set_simple> override - you get to keep
493 Matt S. Trout <mst@shadowcatsystems.co.uk>
495 Christopher H. Laco <claco@chrislaco.com>
499 Caelum: Rafael Kitover <rkitover@cpan.org>
501 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
503 groditi: Guillermo Roditi <groditi@cpan.org>
505 Jason Plum <jason.plum@bmmsi.com>
507 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
510 =head1 COPYRIGHT & LICENSE
512 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
514 This program is free software; you can redistribute it and/or modify
515 it under the same terms as perl itself.
519 ########################################################################
520 ########################################################################
521 ########################################################################
523 # Here be many angry dragons
524 # (all code is in private coderefs since everything inherits CAG)
526 ########################################################################
527 ########################################################################
531 die "Huh?! No minimum C::XSA version?!\n"
532 unless $__minimum_xsa_version;
538 $err = eval { require Sub::Name; 1; } ? undef : do {
539 delete $INC{'Sub/Name.pm'}; # because older perls suck
542 *__CAG_ENV__::NO_SUBNAME = $err
549 require Class::XSAccessor;
550 Class::XSAccessor->VERSION($__minimum_xsa_version);
554 delete $INC{'Sub/Name.pm'}; # because older perls suck
555 delete $INC{'Class/XSAccessor.pm'};
558 *__CAG_ENV__::NO_CXSA = $err
564 *__CAG_ENV__::BROKEN_GOTO = ($] < '5.008009')
570 *__CAG_ENV__::UNSTABLE_DOLLARAT = ($] < '5.013002')
576 *__CAG_ENV__::TRACK_UNDEFER_FAIL = (
577 $INC{'Test/Builder.pm'} || $INC{'Test/Builder2.pm'}
579 $0 =~ m|^ x?t / .+ \.t $|x
585 # Autodetect unless flag supplied
586 my $xsa_autodetected;
587 if (! defined $USE_XS) {
588 $USE_XS = __CAG_ENV__::NO_CXSA ? 0 : 1;
592 my $maker_templates = {
594 xs_call => 'accessors',
596 my $set = "set_$_[0]";
597 my $get = "get_$_[0]";
603 ? shift->$set('$field', \@_)
604 : shift->$get('$field')
609 xs_call => 'getters',
611 my $get = "get_$_[0]";
617 ? shift->$get('$field')
619 my \$caller = caller;
620 my \$class = ref \$_[0] || \$_[0];
621 Carp::croak(\"'\$caller' cannot alter the value of '$field' \".
622 \"(read-only attributes of class '\$class')\");
628 xs_call => 'setters',
630 my $set = "set_$_[0]";
636 ? shift->$set('$field', \@_)
638 my \$caller = caller;
639 my \$class = ref \$_[0] || \$_[0];
640 Carp::croak(\"'\$caller' cannot access the value of '$field' \".
641 \"(write-only attributes of class '\$class')\");
649 my ($accessor_maker_cache, $no_xsa_warned_classes);
651 # can't use pkg_gen to track this stuff, as it doesn't
652 # detect superclass mucking
653 my $original_simple_getter = __PACKAGE__->can ('get_simple');
654 my $original_simple_setter = __PACKAGE__->can ('set_simple');
656 # Note!!! Unusual signature
657 $gen_accessor = sub {
658 my ($type, $class, $group, $field, $methname) = @_;
659 if (my $c = Scalar::Util::blessed( $class )) {
663 # When installing an XSA simple accessor, we need to make sure we are not
664 # short-circuiting a (compile or runtime) get_simple/set_simple override.
665 # What we do here is install a lazy first-access check, which will decide
666 # the ultimate coderef being placed in the accessor slot
668 # Also note that the *original* class will always retain this shim, as
669 # different branches inheriting from it may have different overrides.
670 # Thus the final method (properly labeled and all) is installed in the
671 # calling-package's namespace
672 if ($USE_XS and $group eq 'simple') {
673 die sprintf( "Class::XSAccessor requested but not available:\n%s\n", __CAG_ENV__::NO_CXSA )
674 if __CAG_ENV__::NO_CXSA;
676 my ($expected_cref, $cached_implementation);
677 my $ret = $expected_cref = sub {
678 my $current_class = Scalar::Util::blessed( $_[0] ) || $_[0];
680 # $cached_implementation will be set only if the shim got
681 # 'around'ed, in which case it is handy to avoid re-running
682 # this block over and over again
683 my $resolved_implementation = $cached_implementation->{$current_class} || do {
685 $current_class->can('get_simple') == $original_simple_getter
687 $current_class->can('set_simple') == $original_simple_setter
689 # nothing has changed, might as well use the XS crefs
691 # note that by the time this code executes, we already have
692 # *objects* (since XSA works on 'simple' only by definition).
693 # If someone is mucking with the symbol table *after* there
694 # are some objects already - look! many, shiny pieces! :)
696 # The weird breeder thingy is because XSA does not have an
697 # interface returning *just* a coderef, without installing it
699 Class::XSAccessor->import(
701 class => '__CAG__XSA__BREEDER__',
702 $maker_templates->{$type}{xs_call} => {
706 __CAG__XSA__BREEDER__->can($methname);
709 if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
710 # not using Carp since the line where this happens doesn't mean much
711 warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
712 . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
717 # that's faster than local
719 my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
726 # if after this shim was created someone wrapped it with an 'around',
727 # we can not blindly reinstall the method slot - we will destroy the
728 # wrapper. Silently chain execution further...
729 if ( !$expected_cref or $expected_cref != $current_class->can($methname) ) {
731 # there is no point in re-determining it on every subsequent call,
732 # just store for future reference
733 $cached_implementation->{$current_class} ||= $resolved_implementation;
735 # older perls segfault if the cref behind the goto throws
736 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
737 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
739 goto $resolved_implementation;
742 if (__CAG_ENV__::TRACK_UNDEFER_FAIL) {
743 my $deferred_calls_seen = do {
745 \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
747 my @cframe = caller(0);
748 if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
750 "Deferred version of method $cframe[3] invoked more than once (originally "
751 . "invoked at $already_seen). This is a strong indication your code has "
752 . 'cached the original ->can derived method coderef, and is using it instead '
753 . 'of the proper method re-lookup, causing performance regressions'
757 $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
761 # install the resolved implementation into the code slot so we do not
762 # come here anymore (hopefully)
763 # since XSAccessor was available - so is Sub::Name
766 no warnings 'redefine';
768 my $fq_name = "${current_class}::${methname}";
769 *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
771 # need to update what the shim expects too *in case* its
772 # ->can was cached for some moronic reason
773 $expected_cref = $resolved_implementation;
774 Scalar::Util::weaken($expected_cref);
777 # older perls segfault if the cref behind the goto throws
778 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
779 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
781 goto $resolved_implementation;
784 Scalar::Util::weaken($expected_cref); # to break the self-reference
788 # no Sub::Name - just install the coderefs directly (compiling every time)
789 elsif (__CAG_ENV__::NO_SUBNAME) {
790 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
791 $maker_templates->{$type}{pp_code}->($group, $field);
793 no warnings 'redefine';
794 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
795 eval "sub ${class}::${methname} { $src }";
797 undef; # so that no further attempt will be made to install anything
800 # a coderef generator with a variable pad (returns a fresh cref on every invocation)
802 ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
803 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
804 $maker_templates->{$type}{pp_code}->($group, $field);
806 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
807 eval "sub { my \$dummy; sub { \$dummy if 0; $src } }" or die $@;