1 package Class::Accessor::Grouped;
16 our $VERSION = '0.10002';
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
102 =item Arguments: $group, @fieldspec
108 Creates a set of accessors in a given group.
110 $group is the name of the accessor group for the generated accessors; they
111 will call get_$group($field) on get and set_$group($field, $value) on set.
113 If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
114 to tell Class::Accessor::Grouped to use its own get_simple and set_simple
117 @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
118 this is used as both field and accessor name, if a listref it is expected to
119 be of the form [ $accessor, $field ].
123 sub mk_group_accessors {
124 my ($self, $group, @fields) = @_;
126 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
130 =head2 mk_group_ro_accessors
134 =item Arguments: $group, @fieldspec
140 Creates a set of read only accessors in a given group. Identical to
141 L</mk_group_accessors> but accessors will throw an error if passed a value
142 rather than setting the value.
146 sub mk_group_ro_accessors {
147 my($self, $group, @fields) = @_;
149 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
152 =head2 mk_group_wo_accessors
156 =item Arguments: $group, @fieldspec
162 Creates a set of write only accessors in a given group. Identical to
163 L</mk_group_accessors> but accessors will throw an error if not passed a
164 value rather than getting the value.
168 sub mk_group_wo_accessors {
169 my($self, $group, @fields) = @_;
171 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
174 =head2 make_group_accessor
178 =item Arguments: $group, $field, $method
180 Returns: \&accessor_coderef ?
184 Called by mk_group_accessors for each entry in @fieldspec. Either returns
185 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
186 C<undef> if it elects to install the coderef on its own.
190 sub make_group_accessor { $gen_accessor->('rw', @_) }
192 =head2 make_group_ro_accessor
196 =item Arguments: $group, $field, $method
198 Returns: \&accessor_coderef ?
202 Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
203 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
204 C<undef> if it elects to install the coderef on its own.
208 sub make_group_ro_accessor { $gen_accessor->('ro', @_) }
210 =head2 make_group_wo_accessor
214 =item Arguments: $group, $field, $method
216 Returns: \&accessor_coderef ?
220 Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
221 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
222 C<undef> if it elects to install the coderef on its own.
226 sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
232 =item Arguments: $field
238 Simple getter for hash-based objects which returns the value for the field
239 name passed as an argument.
244 return $_[0]->{$_[1]};
251 =item Arguments: $field, $new_value
257 Simple setter for hash-based objects which sets and then returns the value
258 for the field name passed as an argument.
263 return $_[0]->{$_[1]} = $_[2];
271 =item Arguments: $field
277 Simple getter for Classes and hash-based objects which returns the value for
278 the field name passed as an argument. This behaves much like
279 L<Class::Data::Accessor> where the field can be set in a base class,
280 inherited and changed in subclasses, and inherited and changed for object
288 if ( defined( $class = Scalar::Util::blessed $_[0] ) ) {
289 if (Scalar::Util::reftype $_[0] eq 'HASH') {
290 return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
293 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
301 no warnings 'uninitialized';
303 my $cag_slot = '::__cag_'. $_[1];
304 return ${$class.$cag_slot} if defined(${$class.$cag_slot});
306 # we need to be smarter about recalculation, as @ISA (thus supers) can very well change in-flight
307 my $cur_gen = mro::get_pkg_gen ($class);
308 if ( $cur_gen != ${$class.'::__cag_pkg_gen__'} ) {
309 @{$class.'::__cag_supers__'} = $_[0]->get_super_paths;
310 ${$class.'::__cag_pkg_gen__'} = $cur_gen;
313 for (@{$class.'::__cag_supers__'}) {
314 return ${$_.$cag_slot} if defined(${$_.$cag_slot});
324 =item Arguments: $field, $new_value
330 Simple setter for Classes and hash-based objects which sets and then returns
331 the value for the field name passed as an argument. When called on a hash-based
332 object it will set the appropriate hash key value. When called on a class, it
333 will set a class level variable.
335 B<Note:>: This method will die if you try to set an object variable on a non
341 if (defined Scalar::Util::blessed $_[0]) {
342 if (Scalar::Util::reftype $_[0] eq 'HASH') {
343 return $_[0]->{$_[1]} = $_[2];
345 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
350 return ${$_[0].'::__cag_'.$_[1]} = $_[2];
354 =head2 get_component_class
358 =item Arguments: $field
364 Gets the value of the specified component class.
366 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
368 $self->result_class->method();
371 $self->get_component_class('result_class')->method();
375 sub get_component_class {
376 return $_[0]->get_inherited($_[1]);
379 =head2 set_component_class
383 =item Arguments: $field, $class
389 Inherited accessor that automatically loads the specified class before setting
390 it. This method will die if the specified class could not be loaded.
392 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
393 __PACKAGE__->result_class('MyClass');
395 $self->result_class->method();
399 sub set_component_class {
402 require Class::Inspector;
403 if (Class::Inspector->installed($_[2]) && !Class::Inspector->loaded($_[2])) {
404 eval "require $_[2]";
406 Carp::croak("Could not load $_[1] '$_[2]': ", $@) if $@;
410 return $_[0]->set_inherited($_[1], $_[2]);
413 =head2 get_super_paths
415 Returns a list of 'parent' or 'super' class names that the current class inherited from.
419 sub get_super_paths {
420 return @{mro::get_linear_isa( ref($_[0]) || $_[0] )};
425 To provide total flexibility L<Class::Accessor::Grouped> calls methods
426 internally while performing get/set actions, which makes it noticeably
427 slower than similar modules. To compensate, this module will automatically
428 use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
429 accessors if this module is available on your system.
433 This is the result of a set/get/set loop benchmark on perl 5.12.1 with
434 thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
435 L<Moo>, L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>,
436 L<XSA|Class::XSAccessor>, and L<CAF_XSA|Class::XSAccessor::Compat>:
438 Rate CAG moOse CAF moUse moo HANDMADE CAF_XS moUse_XS moo_XS CAF_XSA XSA CAG_XS
439 CAG 169/s -- -21% -24% -32% -32% -34% -59% -63% -67% -67% -67% -67%
440 moOse 215/s 27% -- -3% -13% -13% -15% -48% -53% -58% -58% -58% -58%
441 CAF 222/s 31% 3% -- -10% -10% -13% -46% -52% -57% -57% -57% -57%
442 moUse 248/s 46% 15% 11% -- -0% -3% -40% -46% -52% -52% -52% -52%
443 moo 248/s 46% 15% 11% 0% -- -3% -40% -46% -52% -52% -52% -52%
444 HANDMADE 255/s 50% 18% 14% 3% 3% -- -38% -45% -50% -51% -51% -51%
445 CAF_XS 411/s 143% 91% 85% 66% 66% 61% -- -11% -20% -20% -21% -21%
446 moUse_XS 461/s 172% 114% 107% 86% 86% 81% 12% -- -10% -11% -11% -11%
447 moo_XS 514/s 204% 139% 131% 107% 107% 102% 25% 12% -- -0% -1% -1%
448 CAF_XSA 516/s 205% 140% 132% 108% 108% 103% 26% 12% 0% -- -0% -0%
449 XSA 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% -- -0%
450 CAG_XS 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% 0% --
452 Benchmark program is available in the root of the
453 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
455 =head2 Notes on Class::XSAccessor
457 You can force (or disable) the use of L<Class::XSAccessor> before creating a
458 particular C<simple> accessor by either manipulating the global variable
459 C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
460 L<localization|perlfunc/local>, or you can do so before runtime via the
461 C<CAG_USE_XS> environment variable.
463 Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
464 L</set_simple> this module does its best to detect if you are overriding
465 one of these methods and will fall back to using the perl version of the
466 accessor in order to maintain consistency. However be aware that if you
467 enable use of C<Class::XSAccessor> (automatically or explicitly), create
468 an object, invoke a simple accessor on that object, and B<then> manipulate
469 the symbol table to install a C<get/set_simple> override - you get to keep
474 Matt S. Trout <mst@shadowcatsystems.co.uk>
476 Christopher H. Laco <claco@chrislaco.com>
480 Caelum: Rafael Kitover <rkitover@cpan.org>
482 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
484 groditi: Guillermo Roditi <groditi@cpan.org>
486 Jason Plum <jason.plum@bmmsi.com>
488 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
491 =head1 COPYRIGHT & LICENSE
493 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
495 This program is free software; you can redistribute it and/or modify
496 it under the same terms as perl itself.
500 ########################################################################
501 ########################################################################
502 ########################################################################
504 # Here be many angry dragons
505 # (all code is in private coderefs since everything inherits CAG)
507 ########################################################################
508 ########################################################################
512 die "Huh?! No minimum C::XSA version?!\n"
513 unless $__minimum_xsa_version;
519 $err = eval { require Sub::Name; 1; } ? undef : do {
520 delete $INC{'Sub/Name.pm'}; # because older perls suck
523 *__CAG_NO_SUBNAME = $err
530 require Class::XSAccessor;
531 Class::XSAccessor->VERSION($__minimum_xsa_version);
535 delete $INC{'Sub/Name.pm'}; # because older perls suck
536 delete $INC{'Class/XSAccessor.pm'};
539 *__CAG_NO_CXSA = $err
545 *__CAG_BROKEN_GOTO = ($] < '5.008009')
551 *__CAG_UNSTABLE_DOLLARAT = ($] < '5.013002')
557 *__CAG_TRACK_UNDEFER_FAIL = (
558 $INC{'Test/Builder.pm'} || $INC{'Test/Builder2.pm'}
560 $0 =~ m|^ x?t / .+ \.t $|x
566 # Autodetect unless flag supplied
567 my $xsa_autodetected;
568 if (! defined $USE_XS) {
569 $USE_XS = __CAG_NO_CXSA ? 0 : 1;
573 my $maker_templates = {
575 xs_call => 'accessors',
577 my $set = "set_$_[0]";
578 my $get = "get_$_[0]";
584 ? shift->$set('$field', \@_)
585 : shift->$get('$field')
590 xs_call => 'getters',
592 my $get = "get_$_[0]";
598 ? shift->$get('$field')
600 my \$caller = caller;
601 my \$class = ref \$_[0] || \$_[0];
602 Carp::croak(\"'\$caller' cannot alter the value of '$field' \".
603 \"(read-only attributes of class '\$class')\");
609 xs_call => 'setters',
611 my $set = "set_$_[0]";
617 ? shift->$set('$field', \@_)
619 my \$caller = caller;
620 my \$class = ref \$_[0] || \$_[0];
621 Carp::croak(\"'\$caller' cannot access the value of '$field' \".
622 \"(write-only attributes of class '\$class')\");
630 my ($accessor_maker_cache, $no_xsa_warned_classes);
632 # can't use pkg_gen to track this stuff, as it doesn't
633 # detect superclass mucking
634 my $original_simple_getter = __PACKAGE__->can ('get_simple');
635 my $original_simple_setter = __PACKAGE__->can ('set_simple');
637 # Note!!! Unusual signature
638 $gen_accessor = sub {
639 my ($type, $class, $group, $field, $methname) = @_;
640 if (my $c = Scalar::Util::blessed( $class )) {
644 # When installing an XSA simple accessor, we need to make sure we are not
645 # short-circuiting a (compile or runtime) get_simple/set_simple override.
646 # What we do here is install a lazy first-access check, which will decide
647 # the ultimate coderef being placed in the accessor slot
649 # Also note that the *original* class will always retain this shim, as
650 # different branches inheriting from it may have different overrides.
651 # Thus the final method (properly labeled and all) is installed in the
652 # calling-package's namespace
653 if ($USE_XS and $group eq 'simple') {
654 die sprintf( "Class::XSAccessor requested but not available:\n%s\n", __CAG_NO_CXSA )
657 my ($expected_cref, $cached_implementation);
658 my $ret = $expected_cref = sub {
659 my $current_class = Scalar::Util::blessed( $_[0] ) || $_[0];
661 # $cached_implementation will be set only if the shim got
662 # 'around'ed, in which case it is handy to avoid re-running
663 # this block over and over again
664 my $resolved_implementation = $cached_implementation->{$current_class} || do {
666 $current_class->can('get_simple') == $original_simple_getter
668 $current_class->can('set_simple') == $original_simple_setter
670 # nothing has changed, might as well use the XS crefs
672 # note that by the time this code executes, we already have
673 # *objects* (since XSA works on 'simple' only by definition).
674 # If someone is mucking with the symbol table *after* there
675 # are some objects already - look! many, shiny pieces! :)
677 # The weird breeder thingy is because XSA does not have an
678 # interface returning *just* a coderef, without installing it
680 Class::XSAccessor->import(
682 class => '__CAG__XSA__BREEDER__',
683 $maker_templates->{$type}{xs_call} => {
687 __CAG__XSA__BREEDER__->can($methname);
690 if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
691 # not using Carp since the line where this happens doesn't mean much
692 warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
693 . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
698 # that's faster than local
700 my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
707 # if after this shim was created someone wrapped it with an 'around',
708 # we can not blindly reinstall the method slot - we will destroy the
709 # wrapper. Silently chain execution further...
710 if ( !$expected_cref or $expected_cref != $current_class->can($methname) ) {
712 # there is no point in re-determining it on every subsequent call,
713 # just store for future reference
714 $cached_implementation->{$current_class} ||= $resolved_implementation;
716 # older perls segfault if the cref behind the goto throws
717 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
718 return $resolved_implementation->(@_) if __CAG_BROKEN_GOTO;
720 goto $resolved_implementation;
723 if (__CAG_TRACK_UNDEFER_FAIL) {
724 my $deferred_calls_seen = do {
726 \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
728 my @cframe = caller(0);
729 if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
731 "Deferred version of method $cframe[3] invoked more than once (originally "
732 . "invoked at $already_seen). This is a strong indication your code has "
733 . 'cached the original ->can derived method coderef, and is using it instead '
734 . 'of the proper method re-lookup, causing performance regressions'
738 $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
742 # install the resolved implementation into the code slot so we do not
743 # come here anymore (hopefully)
744 # since XSAccessor was available - so is Sub::Name
747 no warnings 'redefine';
749 my $fq_name = "${current_class}::${methname}";
750 *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
752 # need to update what the shim expects too *in case* its
753 # ->can was cached for some moronic reason
754 $expected_cref = $resolved_implementation;
755 Scalar::Util::weaken($expected_cref);
758 # older perls segfault if the cref behind the goto throws
759 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
760 return $resolved_implementation->(@_) if __CAG_BROKEN_GOTO;
762 goto $resolved_implementation;
765 Scalar::Util::weaken($expected_cref); # to break the self-reference
769 # no Sub::Name - just install the coderefs directly (compiling every time)
770 elsif (__CAG_NO_SUBNAME) {
771 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
772 $maker_templates->{$type}{pp_code}->($group, $field);
774 no warnings 'redefine';
775 local $@ if __CAG_UNSTABLE_DOLLARAT;
776 eval "sub ${class}::${methname} { $src }";
778 undef; # so that no further attempt will be made to install anything
781 # a coderef generator with a variable pad (returns a fresh cref on every invocation)
783 ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
784 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
785 $maker_templates->{$type}{pp_code}->($group, $field);
787 local $@ if __CAG_UNSTABLE_DOLLARAT;
788 eval "sub { my \$dummy; sub { \$dummy if 0; $src } }" or die $@;