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 Carp::croak("Illegal accessor name '$name'")
81 unless $name =~ /\A[A-Z_a-z][0-9A-Z_a-z]*\z/;
83 Carp::carp("Having a data accessor named '$name' in '$class' is unwise.")
84 if $name =~ /\A(?: DESTROY | AUTOLOAD | CLONE )\z/x;
86 my $alias = "_${name}_accessor";
90 # the maker may elect to not return anything, meaning it already
91 # installed the coderef for us (e.g. lack of Sub::Name)
92 my $cref = $self->$maker($group, $field, $_)
95 my $fq_meth = "${class}::$_";
97 *$fq_meth = Sub::Name::subname($fq_meth, $cref);
98 #unless defined &{$class."\:\:$field"}
103 # $gen_accessor coderef is setup at the end for clarity
108 Class::Accessor::Grouped - Lets you build groups of accessors
112 use base 'Class::Accessor::Grouped';
114 # make basic accessors for objects
115 __PACKAGE__->mk_group_accessors(simple => qw(id name email));
117 # make accessor that works for objects and classes
118 __PACKAGE__->mk_group_accessors(inherited => 'awesome_level');
122 This class lets you build groups of accessors that will call different
127 =head2 mk_group_accessors
129 __PACKAGE__->mk_group_accessors(simple => 'hair_length', [ hair_color => 'hc' ]);
133 =item Arguments: $group, @fieldspec
139 Creates a set of accessors in a given group.
141 $group is the name of the accessor group for the generated accessors; they
142 will call get_$group($field) on get and set_$group($field, $value) on set.
144 If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
145 to tell Class::Accessor::Grouped to use its own get_simple and set_simple
148 @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
149 this is used as both field and accessor name, if a listref it is expected to
150 be of the form [ $accessor, $field ].
154 sub mk_group_accessors {
155 my ($self, $group, @fields) = @_;
157 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
161 =head2 mk_group_ro_accessors
163 __PACKAGE__->mk_group_ro_accessors(simple => 'birthdate', [ social_security_number => 'ssn' ]);
167 =item Arguments: $group, @fieldspec
173 Creates a set of read only accessors in a given group. Identical to
174 L</mk_group_accessors> but accessors will throw an error if passed a value
175 rather than setting the value.
179 sub mk_group_ro_accessors {
180 my($self, $group, @fields) = @_;
182 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
186 =head2 mk_group_wo_accessors
188 __PACKAGE__->mk_group_wo_accessors(simple => 'lie', [ subject => 'subj' ]);
192 =item Arguments: $group, @fieldspec
198 Creates a set of write only accessors in a given group. Identical to
199 L</mk_group_accessors> but accessors will throw an error if not passed a
200 value rather than getting the value.
204 sub mk_group_wo_accessors {
205 my($self, $group, @fields) = @_;
207 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
215 =item Arguments: $field
221 Simple getter for hash-based objects which returns the value for the field
222 name passed as an argument.
234 =item Arguments: $field, $new_value
240 Simple setter for hash-based objects which sets and then returns the value
241 for the field name passed as an argument.
246 $_[0]->{$_[1]} = $_[2];
254 =item Arguments: $field
260 Simple getter for Classes and hash-based objects which returns the value for
261 the field name passed as an argument. This behaves much like
262 L<Class::Data::Accessor> where the field can be set in a base class,
263 inherited and changed in subclasses, and inherited and changed for object
269 if ( length (ref ($_[0]) ) ) {
270 if (Scalar::Util::reftype $_[0] eq 'HASH') {
271 return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
272 # everything in @_ is aliased, an assignment won't work
273 splice @_, 0, 1, ref($_[0]);
276 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
280 # if we got this far there is nothing in the instance
281 # OR this is a class call
282 # in any case $_[0] contains the class name (see splice above)
284 no warnings 'uninitialized';
286 my $cag_slot = '::__cag_'. $_[1];
287 return ${$_[0].$cag_slot} if defined(${$_[0].$cag_slot});
289 do { return ${$_.$cag_slot} if defined(${$_.$cag_slot}) }
290 for $_[0]->get_super_paths;
299 =item Arguments: $field, $new_value
305 Simple setter for Classes and hash-based objects which sets and then returns
306 the value for the field name passed as an argument. When called on a hash-based
307 object it will set the appropriate hash key value. When called on a class, it
308 will set a class level variable.
310 B<Note:>: This method will die if you try to set an object variable on a non
316 if (length (ref ($_[0]) ) ) {
317 if (Scalar::Util::reftype $_[0] eq 'HASH') {
318 return $_[0]->{$_[1]} = $_[2];
320 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
325 ${$_[0].'::__cag_'.$_[1]} = $_[2];
328 =head2 get_component_class
332 =item Arguments: $field
338 Gets the value of the specified component class.
340 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
342 $self->result_class->method();
345 $self->get_component_class('result_class')->method();
349 sub get_component_class {
350 $_[0]->get_inherited($_[1]);
353 =head2 set_component_class
357 =item Arguments: $field, $class
363 Inherited accessor that automatically loads the specified class before setting
364 it. This method will die if the specified class could not be loaded.
366 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
367 __PACKAGE__->result_class('MyClass');
369 $self->result_class->method();
373 sub set_component_class {
374 if (defined $_[2] and length $_[2]) {
375 # disable warnings, and prevent $_ being eaten away by a behind-the-scenes
379 if (__CAG_ENV__::UNSTABLE_DOLLARAT) {
383 eval { Module::Runtime::use_package_optimistically($_[2]) }
386 Carp::croak("Could not load $_[1] '$_[2]': $err") if defined $err;
390 eval { Module::Runtime::use_package_optimistically($_[2]) }
391 or Carp::croak("Could not load $_[1] '$_[2]': $@");
395 $_[0]->set_inherited($_[1], $_[2]);
398 =head1 INTERNAL METHODS
400 These methods are documented for clarity, but are never meant to be called
401 directly, and are not really meant for overriding either.
403 =head2 get_super_paths
405 Returns a list of 'parent' or 'super' class names that the current class
406 inherited from. This is what drives the traversal done by L</get_inherited>.
410 sub get_super_paths {
411 # get_linear_isa returns the class itself as the 1st element
412 # use @_ as a pre-allocated scratch array
413 (undef, @_) = @{mro::get_linear_isa( length( ref($_[0]) ) ? ref($_[0]) : $_[0] )};
417 =head2 make_group_accessor
419 __PACKAGE__->make_group_accessor('simple', 'hair_length', 'hair_length');
420 __PACKAGE__->make_group_accessor('simple', 'hc', 'hair_color');
424 =item Arguments: $group, $field, $accessor
426 Returns: \&accessor_coderef ?
430 Called by mk_group_accessors for each entry in @fieldspec. Either returns
431 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
432 C<undef> if it elects to install the coderef on its own.
436 sub make_group_accessor { $gen_accessor->('rw', @_) }
438 =head2 make_group_ro_accessor
440 __PACKAGE__->make_group_ro_accessor('simple', 'birthdate', 'birthdate');
441 __PACKAGE__->make_group_ro_accessor('simple', 'ssn', 'social_security_number');
445 =item Arguments: $group, $field, $accessor
447 Returns: \&accessor_coderef ?
451 Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
452 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
453 C<undef> if it elects to install the coderef on its own.
457 sub make_group_ro_accessor { $gen_accessor->('ro', @_) }
459 =head2 make_group_wo_accessor
461 __PACKAGE__->make_group_wo_accessor('simple', 'lie', 'lie');
462 __PACKAGE__->make_group_wo_accessor('simple', 'subj', 'subject');
466 =item Arguments: $group, $field, $accessor
468 Returns: \&accessor_coderef ?
472 Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
473 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
474 C<undef> if it elects to install the coderef on its own.
478 sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
483 To provide total flexibility L<Class::Accessor::Grouped> calls methods
484 internally while performing get/set actions, which makes it noticeably
485 slower than similar modules. To compensate, this module will automatically
486 use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
487 accessors if this module is available on your system.
491 This is the result of a set/get/set loop benchmark on perl 5.12.1 with
492 thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
493 L<Moo>, L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>,
494 L<XSA|Class::XSAccessor>, and L<CAF_XSA|Class::XSAccessor::Compat>:
496 Rate CAG moOse CAF moUse moo HANDMADE CAF_XS moUse_XS moo_XS CAF_XSA XSA CAG_XS
497 CAG 169/s -- -21% -24% -32% -32% -34% -59% -63% -67% -67% -67% -67%
498 moOse 215/s 27% -- -3% -13% -13% -15% -48% -53% -58% -58% -58% -58%
499 CAF 222/s 31% 3% -- -10% -10% -13% -46% -52% -57% -57% -57% -57%
500 moUse 248/s 46% 15% 11% -- -0% -3% -40% -46% -52% -52% -52% -52%
501 moo 248/s 46% 15% 11% 0% -- -3% -40% -46% -52% -52% -52% -52%
502 HANDMADE 255/s 50% 18% 14% 3% 3% -- -38% -45% -50% -51% -51% -51%
503 CAF_XS 411/s 143% 91% 85% 66% 66% 61% -- -11% -20% -20% -21% -21%
504 moUse_XS 461/s 172% 114% 107% 86% 86% 81% 12% -- -10% -11% -11% -11%
505 moo_XS 514/s 204% 139% 131% 107% 107% 102% 25% 12% -- -0% -1% -1%
506 CAF_XSA 516/s 205% 140% 132% 108% 108% 103% 26% 12% 0% -- -0% -0%
507 XSA 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% -- -0%
508 CAG_XS 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% 0% --
510 Benchmark program is available in the root of the
511 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
513 =head2 Notes on Class::XSAccessor
515 You can force (or disable) the use of L<Class::XSAccessor> before creating a
516 particular C<simple> accessor by either manipulating the global variable
517 C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
518 L<localization|perlfunc/local>, or you can do so before runtime via the
519 C<CAG_USE_XS> environment variable.
521 Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
522 L</set_simple> this module does its best to detect if you are overriding
523 one of these methods and will fall back to using the perl version of the
524 accessor in order to maintain consistency. However be aware that if you
525 enable use of C<Class::XSAccessor> (automatically or explicitly), create
526 an object, invoke a simple accessor on that object, and B<then> manipulate
527 the symbol table to install a C<get/set_simple> override - you get to keep
532 Matt S. Trout <mst@shadowcatsystems.co.uk>
534 Christopher H. Laco <claco@chrislaco.com>
538 Caelum: Rafael Kitover <rkitover@cpan.org>
540 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
542 groditi: Guillermo Roditi <groditi@cpan.org>
544 Jason Plum <jason.plum@bmmsi.com>
546 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
549 =head1 COPYRIGHT & LICENSE
551 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
553 This program is free software; you can redistribute it and/or modify
554 it under the same terms as perl itself.
558 ########################################################################
559 ########################################################################
560 ########################################################################
562 # Here be many angry dragons
563 # (all code is in private coderefs since everything inherits CAG)
565 ########################################################################
566 ########################################################################
568 # Autodetect unless flag supplied
569 my $xsa_autodetected;
570 if (! defined $USE_XS) {
571 $USE_XS = __CAG_ENV__::NO_CXSA ? 0 : 1;
577 require Data::Dumper;
578 my $d = Data::Dumper->new([])->Indent(0)->Purity(0)->Pad('')->Useqq(1)->Terse(1)->Freezer('')->Toaster('');
579 $perlstring = sub { $d->Values([shift])->Dump };
583 $perlstring = \&B::perlstring;
587 my $maker_templates = {
589 cxsa_call => 'accessors',
590 pp_generator => sub {
591 # my ($group, $fieldname) = @_;
592 my $quoted_fieldname = $perlstring->($_[1]);
593 sprintf <<'EOS', ($_[0], $quoted_fieldname) x 2;
596 ? shift->set_%s(%s, @_)
603 cxsa_call => 'getters',
604 pp_generator => sub {
605 # my ($group, $fieldname) = @_;
606 my $quoted_fieldname = $perlstring->($_[1]);
607 sprintf <<'EOS', $_[0], $quoted_fieldname;
611 my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
612 my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
614 "'$meth' cannot alter its value (read-only attribute of class $class)"
623 cxsa_call => 'setters',
624 pp_generator => sub {
625 # my ($group, $fieldname) = @_;
626 my $quoted_fieldname = $perlstring->($_[1]);
627 sprintf <<'EOS', $_[0], $quoted_fieldname;
630 ? shift->set_%s(%s, @_)
632 my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
633 my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
635 "'$meth' cannot access its value (write-only attribute of class $class)"
645 my ($accessor_maker_cache, $no_xsa_warned_classes);
647 # can't use pkg_gen to track this stuff, as it doesn't
648 # detect superclass mucking
649 my $original_simple_getter = __PACKAGE__->can ('get_simple');
650 my $original_simple_setter = __PACKAGE__->can ('set_simple');
652 # Note!!! Unusual signature
653 $gen_accessor = sub {
654 my ($type, $class, $group, $field, $methname) = @_;
655 $class = ref $class if length ref $class;
657 # When installing an XSA simple accessor, we need to make sure we are not
658 # short-circuiting a (compile or runtime) get_simple/set_simple override.
659 # What we do here is install a lazy first-access check, which will decide
660 # the ultimate coderef being placed in the accessor slot
662 # Also note that the *original* class will always retain this shim, as
663 # different branches inheriting from it may have different overrides.
664 # Thus the final method (properly labeled and all) is installed in the
665 # calling-package's namespace
666 if ($USE_XS and $group eq 'simple') {
667 die sprintf( "Class::XSAccessor requested but not available:\n%s\n", __CAG_ENV__::NO_CXSA )
668 if __CAG_ENV__::NO_CXSA;
670 my ($expected_cref, $cached_implementation);
671 my $ret = $expected_cref = sub {
672 my $current_class = length (ref ($_[0] ) ) ? ref ($_[0]) : $_[0];
674 # $cached_implementation will be set only if the shim got
675 # 'around'ed, in which case it is handy to avoid re-running
676 # this block over and over again
677 my $resolved_implementation = $cached_implementation->{$current_class} || do {
679 ($current_class->can('get_simple')||0) == $original_simple_getter
681 ($current_class->can('set_simple')||0) == $original_simple_setter
683 # nothing has changed, might as well use the XS crefs
685 # note that by the time this code executes, we already have
686 # *objects* (since XSA works on 'simple' only by definition).
687 # If someone is mucking with the symbol table *after* there
688 # are some objects already - look! many, shiny pieces! :)
690 # The weird breeder thingy is because XSA does not have an
691 # interface returning *just* a coderef, without installing it
693 Class::XSAccessor->import(
695 class => '__CAG__XSA__BREEDER__',
696 $maker_templates->{$type}{cxsa_call} => {
700 __CAG__XSA__BREEDER__->can($methname);
703 if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
704 # not using Carp since the line where this happens doesn't mean much
705 warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
706 . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
711 # that's faster than local
713 my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
720 # if after this shim was created someone wrapped it with an 'around',
721 # we can not blindly reinstall the method slot - we will destroy the
722 # wrapper. Silently chain execution further...
723 if ( !$expected_cref or $expected_cref != ($current_class->can($methname)||0) ) {
725 # there is no point in re-determining it on every subsequent call,
726 # just store for future reference
727 $cached_implementation->{$current_class} ||= $resolved_implementation;
729 # older perls segfault if the cref behind the goto throws
730 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
731 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
733 goto $resolved_implementation;
736 if (__CAG_ENV__::TRACK_UNDEFER_FAIL) {
737 my $deferred_calls_seen = do {
739 \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
741 my @cframe = caller(0);
742 if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
744 "Deferred version of method $cframe[3] invoked more than once (originally "
745 . "invoked at $already_seen). This is a strong indication your code has "
746 . 'cached the original ->can derived method coderef, and is using it instead '
747 . 'of the proper method re-lookup, causing minor performance regressions'
751 $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
755 # install the resolved implementation into the code slot so we do not
756 # come here anymore (hopefully)
757 # since XSAccessor was available - so is Sub::Name
760 no warnings 'redefine';
762 my $fq_name = "${current_class}::${methname}";
763 *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
765 # need to update what the shim expects too *in case* its
766 # ->can was cached for some moronic reason
767 $expected_cref = $resolved_implementation;
768 Scalar::Util::weaken($expected_cref);
771 # older perls segfault if the cref behind the goto throws
772 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
773 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
775 goto $resolved_implementation;
778 Scalar::Util::weaken($expected_cref); # to break the self-reference
782 # no Sub::Name - just install the coderefs directly (compiling every time)
783 elsif (__CAG_ENV__::NO_SUBNAME) {
784 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
785 $maker_templates->{$type}{pp_generator}->($group, $field);
787 no warnings 'redefine';
788 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
789 eval "sub ${class}::${methname} { $src }";
791 undef; # so that no further attempt will be made to install anything
794 # a coderef generator with a variable pad (returns a fresh cref on every invocation)
796 ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
797 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
798 $maker_templates->{$type}{pp_generator}->($group, $field);
800 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
801 eval "sub { my \$dummy; sub { \$dummy if 0; $src } }" or die $@;