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() || ( 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');
133 # make an accessor which calls a custom pair of getters/setters
134 sub get_column { ... this will be called when you do $obj->name() ... }
135 sub set_column { ... this will be called when you do $obj->name('foo') ... }
136 __PACKAGE__->mk_group_accessors(column => 'name');
140 This class lets you build groups of accessors that will call different
141 getters and setters. The documentation of this module still requires a lot
142 of work (B<< volunteers welcome >.> >>), but in the meantime you can refer to
143 L<this post|http://lo-f.at/glahn/2009/08/WritingPowerfulAccessorsForPerlClasses.html>
144 for more information.
148 =head2 mk_group_accessors
150 __PACKAGE__->mk_group_accessors(simple => 'hair_length', [ hair_color => 'hc' ]);
154 =item Arguments: $group, @fieldspec
160 Creates a set of accessors in a given group.
162 $group is the name of the accessor group for the generated accessors; they
163 will call get_$group($field) on get and set_$group($field, $value) on set.
165 If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
166 to tell Class::Accessor::Grouped to use its own get_simple and set_simple
169 @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
170 this is used as both field and accessor name, if a listref it is expected to
171 be of the form [ $accessor, $field ].
175 sub mk_group_accessors {
176 my ($self, $group, @fields) = @_;
178 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
182 =head2 mk_group_ro_accessors
184 __PACKAGE__->mk_group_ro_accessors(simple => 'birthdate', [ social_security_number => 'ssn' ]);
188 =item Arguments: $group, @fieldspec
194 Creates a set of read only accessors in a given group. Identical to
195 L</mk_group_accessors> but accessors will throw an error if passed a value
196 rather than setting the value.
200 sub mk_group_ro_accessors {
201 my($self, $group, @fields) = @_;
203 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
207 =head2 mk_group_wo_accessors
209 __PACKAGE__->mk_group_wo_accessors(simple => 'lie', [ subject => 'subj' ]);
213 =item Arguments: $group, @fieldspec
219 Creates a set of write only accessors in a given group. Identical to
220 L</mk_group_accessors> but accessors will throw an error if not passed a
221 value rather than getting the value.
225 sub mk_group_wo_accessors {
226 my($self, $group, @fields) = @_;
228 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
236 =item Arguments: $field
242 Simple getter for hash-based objects which returns the value for the field
243 name passed as an argument.
255 =item Arguments: $field, $new_value
261 Simple setter for hash-based objects which sets and then returns the value
262 for the field name passed as an argument.
267 $_[0]->{$_[1]} = $_[2];
275 =item Arguments: $field
281 Simple getter for Classes and hash-based objects which returns the value for
282 the field name passed as an argument. This behaves much like
283 L<Class::Data::Accessor> where the field can be set in a base class,
284 inherited and changed in subclasses, and inherited and changed for object
290 if ( length (ref ($_[0]) ) ) {
291 if (Scalar::Util::reftype $_[0] eq 'HASH') {
292 return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
293 # everything in @_ is aliased, an assignment won't work
294 splice @_, 0, 1, ref($_[0]);
297 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
301 # if we got this far there is nothing in the instance
302 # OR this is a class call
303 # in any case $_[0] contains the class name (see splice above)
305 no warnings 'uninitialized';
307 my $cag_slot = '::__cag_'. $_[1];
308 return ${$_[0].$cag_slot} if defined(${$_[0].$cag_slot});
310 do { return ${$_.$cag_slot} if defined(${$_.$cag_slot}) }
311 for $_[0]->get_super_paths;
320 =item Arguments: $field, $new_value
326 Simple setter for Classes and hash-based objects which sets and then returns
327 the value for the field name passed as an argument. When called on a hash-based
328 object it will set the appropriate hash key value. When called on a class, it
329 will set a class level variable.
331 B<Note:>: This method will die if you try to set an object variable on a non
337 if (length (ref ($_[0]) ) ) {
338 if (Scalar::Util::reftype $_[0] eq 'HASH') {
339 return $_[0]->{$_[1]} = $_[2];
341 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
346 ${$_[0].'::__cag_'.$_[1]} = $_[2];
349 =head2 get_component_class
353 =item Arguments: $field
359 Gets the value of the specified component class.
361 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
363 $self->result_class->method();
366 $self->get_component_class('result_class')->method();
370 sub get_component_class {
371 $_[0]->get_inherited($_[1]);
374 =head2 set_component_class
378 =item Arguments: $field, $class
384 Inherited accessor that automatically loads the specified class before setting
385 it. This method will die if the specified class could not be loaded.
387 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
388 __PACKAGE__->result_class('MyClass');
390 $self->result_class->method();
394 sub set_component_class {
395 if (defined $_[2] and length $_[2]) {
396 # disable warnings, and prevent $_ being eaten away by a behind-the-scenes
400 if (__CAG_ENV__::UNSTABLE_DOLLARAT) {
404 eval { Module::Runtime::use_package_optimistically($_[2]) }
407 Carp::croak("Could not load $_[1] '$_[2]': $err") if defined $err;
411 eval { Module::Runtime::use_package_optimistically($_[2]) }
412 or Carp::croak("Could not load $_[1] '$_[2]': $@");
416 $_[0]->set_inherited($_[1], $_[2]);
419 =head1 INTERNAL METHODS
421 These methods are documented for clarity, but are never meant to be called
422 directly, and are not really meant for overriding either.
424 =head2 get_super_paths
426 Returns a list of 'parent' or 'super' class names that the current class
427 inherited from. This is what drives the traversal done by L</get_inherited>.
431 sub get_super_paths {
432 # get_linear_isa returns the class itself as the 1st element
433 # use @_ as a pre-allocated scratch array
434 (undef, @_) = @{mro::get_linear_isa( length( ref($_[0]) ) ? ref($_[0]) : $_[0] )};
438 =head2 make_group_accessor
440 __PACKAGE__->make_group_accessor('simple', 'hair_length', 'hair_length');
441 __PACKAGE__->make_group_accessor('simple', 'hc', 'hair_color');
445 =item Arguments: $group, $field, $accessor
447 Returns: \&accessor_coderef ?
451 Called by mk_group_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_accessor { $gen_accessor->('rw', @_) }
459 =head2 make_group_ro_accessor
461 __PACKAGE__->make_group_ro_accessor('simple', 'birthdate', 'birthdate');
462 __PACKAGE__->make_group_ro_accessor('simple', 'ssn', 'social_security_number');
466 =item Arguments: $group, $field, $accessor
468 Returns: \&accessor_coderef ?
472 Called by mk_group_ro_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_ro_accessor { $gen_accessor->('ro', @_) }
480 =head2 make_group_wo_accessor
482 __PACKAGE__->make_group_wo_accessor('simple', 'lie', 'lie');
483 __PACKAGE__->make_group_wo_accessor('simple', 'subj', 'subject');
487 =item Arguments: $group, $field, $accessor
489 Returns: \&accessor_coderef ?
493 Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
494 a coderef which will be installed at C<&__PACKAGE__::$accessor>, or returns
495 C<undef> if it elects to install the coderef on its own.
499 sub make_group_wo_accessor { $gen_accessor->('wo', @_) }
504 To provide total flexibility L<Class::Accessor::Grouped> calls methods
505 internally while performing get/set actions, which makes it noticeably
506 slower than similar modules. To compensate, this module will automatically
507 use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
508 accessors if this module is available on your system.
512 This is the result of a set/get/set loop benchmark on perl 5.12.1 with
513 thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
514 L<Moo>, L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>,
515 L<XSA|Class::XSAccessor>, and L<CAF_XSA|Class::XSAccessor::Compat>:
517 Rate CAG moOse CAF moUse moo HANDMADE CAF_XS moUse_XS moo_XS CAF_XSA XSA CAG_XS
518 CAG 169/s -- -21% -24% -32% -32% -34% -59% -63% -67% -67% -67% -67%
519 moOse 215/s 27% -- -3% -13% -13% -15% -48% -53% -58% -58% -58% -58%
520 CAF 222/s 31% 3% -- -10% -10% -13% -46% -52% -57% -57% -57% -57%
521 moUse 248/s 46% 15% 11% -- -0% -3% -40% -46% -52% -52% -52% -52%
522 moo 248/s 46% 15% 11% 0% -- -3% -40% -46% -52% -52% -52% -52%
523 HANDMADE 255/s 50% 18% 14% 3% 3% -- -38% -45% -50% -51% -51% -51%
524 CAF_XS 411/s 143% 91% 85% 66% 66% 61% -- -11% -20% -20% -21% -21%
525 moUse_XS 461/s 172% 114% 107% 86% 86% 81% 12% -- -10% -11% -11% -11%
526 moo_XS 514/s 204% 139% 131% 107% 107% 102% 25% 12% -- -0% -1% -1%
527 CAF_XSA 516/s 205% 140% 132% 108% 108% 103% 26% 12% 0% -- -0% -0%
528 XSA 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% -- -0%
529 CAG_XS 519/s 206% 141% 133% 109% 109% 104% 26% 13% 1% 0% 0% --
531 Benchmark program is available in the root of the
532 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
534 =head2 Notes on Class::XSAccessor
536 You can force (or disable) the use of L<Class::XSAccessor> before creating a
537 particular C<simple> accessor by either manipulating the global variable
538 C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
539 L<localization|perlfunc/local>, or you can do so before runtime via the
540 C<CAG_USE_XS> environment variable.
542 Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
543 L</set_simple> this module does its best to detect if you are overriding
544 one of these methods and will fall back to using the perl version of the
545 accessor in order to maintain consistency. However be aware that if you
546 enable use of C<Class::XSAccessor> (automatically or explicitly), create
547 an object, invoke a simple accessor on that object, and B<then> manipulate
548 the symbol table to install a C<get/set_simple> override - you get to keep
553 Matt S. Trout <mst@shadowcatsystems.co.uk>
555 Christopher H. Laco <claco@chrislaco.com>
559 Caelum: Rafael Kitover <rkitover@cpan.org>
561 frew: Arthur Axel "fREW" Schmidt <frioux@gmail.com>
563 groditi: Guillermo Roditi <groditi@cpan.org>
565 Jason Plum <jason.plum@bmmsi.com>
567 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
570 =head1 COPYRIGHT & LICENSE
572 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
574 This program is free software; you can redistribute it and/or modify
575 it under the same terms as perl itself.
579 ########################################################################
580 ########################################################################
581 ########################################################################
583 # Here be many angry dragons
584 # (all code is in private coderefs since everything inherits CAG)
586 ########################################################################
587 ########################################################################
589 # Autodetect unless flag supplied
590 my $xsa_autodetected;
591 if (! defined $USE_XS) {
592 $USE_XS = __CAG_ENV__::NO_CXSA ? 0 : 1;
598 require Data::Dumper;
599 my $d = Data::Dumper->new([])->Indent(0)->Purity(0)->Pad('')->Useqq(1)->Terse(1)->Freezer('')->Toaster('');
600 $perlstring = sub { $d->Values([shift])->Dump };
604 $perlstring = \&B::perlstring;
608 my $maker_templates = {
610 cxsa_call => 'accessors',
611 pp_generator => sub {
612 # my ($group, $fieldname) = @_;
613 my $quoted_fieldname = $perlstring->($_[1]);
614 sprintf <<'EOS', ($_[0], $quoted_fieldname) x 2;
617 ? shift->set_%s(%s, @_)
624 cxsa_call => 'getters',
625 pp_generator => sub {
626 # my ($group, $fieldname) = @_;
627 my $quoted_fieldname = $perlstring->($_[1]);
628 sprintf <<'EOS', $_[0], $quoted_fieldname;
632 my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
633 my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
635 "'$meth' cannot alter its value (read-only attribute of class $class)"
644 cxsa_call => 'setters',
645 pp_generator => sub {
646 # my ($group, $fieldname) = @_;
647 my $quoted_fieldname = $perlstring->($_[1]);
648 sprintf <<'EOS', $_[0], $quoted_fieldname;
651 ? shift->set_%s(%s, @_)
653 my ($meth) = (caller(0))[3] =~ /([^\:]+)$/;
654 my $class = length( ref($_[0]) ) ? ref($_[0]) : $_[0];
656 "'$meth' cannot access its value (write-only attribute of class $class)"
666 #my ($src, $no_warnings, $err_msg) = @_;
668 my $src = sprintf "{ %s warnings; use strict; no strict 'refs'; %s }",
669 $_[1] ? 'no' : 'use',
675 local $@ if __CAG_ENV__::UNSTABLE_DOLLARAT;
680 $err = $@ if $@ ne '';
683 Carp::croak(join ': ', ($_[2] || 'String-eval failed'), "$err\n$src\n" )
686 wantarray ? @rv : $rv[0];
689 my ($accessor_maker_cache, $no_xsa_warned_classes);
691 # can't use pkg_gen to track this stuff, as it doesn't
692 # detect superclass mucking
693 my $original_simple_getter = __PACKAGE__->can ('get_simple');
694 my $original_simple_setter = __PACKAGE__->can ('set_simple');
696 # Note!!! Unusual signature
697 $gen_accessor = sub {
698 my ($type, $class, $group, $field, $methname) = @_;
699 $class = ref $class if length ref $class;
701 # When installing an XSA simple accessor, we need to make sure we are not
702 # short-circuiting a (compile or runtime) get_simple/set_simple override.
703 # What we do here is install a lazy first-access check, which will decide
704 # the ultimate coderef being placed in the accessor slot
706 # Also note that the *original* class will always retain this shim, as
707 # different branches inheriting from it may have different overrides.
708 # Thus the final method (properly labeled and all) is installed in the
709 # calling-package's namespace
710 if ($USE_XS and $group eq 'simple') {
711 die sprintf( "Class::XSAccessor requested but not available:\n%s\n", __CAG_ENV__::NO_CXSA )
712 if __CAG_ENV__::NO_CXSA;
714 my ($expected_cref, $cached_implementation);
715 my $ret = $expected_cref = sub {
716 my $current_class = length (ref ($_[0] ) ) ? ref ($_[0]) : $_[0];
718 # $cached_implementation will be set only if the shim got
719 # 'around'ed, in which case it is handy to avoid re-running
720 # this block over and over again
721 my $resolved_implementation = $cached_implementation->{$current_class} || do {
723 ($current_class->can('get_simple')||0) == $original_simple_getter
725 ($current_class->can('set_simple')||0) == $original_simple_setter
727 # nothing has changed, might as well use the XS crefs
729 # note that by the time this code executes, we already have
730 # *objects* (since XSA works on 'simple' only by definition).
731 # If someone is mucking with the symbol table *after* there
732 # are some objects already - look! many, shiny pieces! :)
734 # The weird breeder thingy is because XSA does not have an
735 # interface returning *just* a coderef, without installing it
737 Class::XSAccessor->import(
739 class => '__CAG__XSA__BREEDER__',
740 $maker_templates->{$type}{cxsa_call} => {
744 __CAG__XSA__BREEDER__->can($methname);
747 if (! $xsa_autodetected and ! $no_xsa_warned_classes->{$current_class}++) {
748 # not using Carp since the line where this happens doesn't mean much
749 warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
750 . "'$current_class' inheriting from '$class' due to an overriden get_simple and/or "
755 # that's faster than local
757 my $c = $gen_accessor->($type, $class, 'simple', $field, $methname);
764 # if after this shim was created someone wrapped it with an 'around',
765 # we can not blindly reinstall the method slot - we will destroy the
766 # wrapper. Silently chain execution further...
767 if ( !$expected_cref or $expected_cref != ($current_class->can($methname)||0) ) {
769 # there is no point in re-determining it on every subsequent call,
770 # just store for future reference
771 $cached_implementation->{$current_class} ||= $resolved_implementation;
773 # older perls segfault if the cref behind the goto throws
774 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
775 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
777 goto $resolved_implementation;
780 if (__CAG_ENV__::TRACK_UNDEFER_FAIL) {
781 my $deferred_calls_seen = do {
783 \%{"${current_class}::__cag_deferred_xs_shim_invocations"}
785 my @cframe = caller(0);
786 if (my $already_seen = $deferred_calls_seen->{$cframe[3]}) {
788 "Deferred version of method $cframe[3] invoked more than once (originally "
789 . "invoked at $already_seen). This is a strong indication your code has "
790 . 'cached the original ->can derived method coderef, and is using it instead '
791 . 'of the proper method re-lookup, causing minor performance regressions'
795 $deferred_calls_seen->{$cframe[3]} = "$cframe[1] line $cframe[2]";
799 # install the resolved implementation into the code slot so we do not
800 # come here anymore (hopefully)
801 # since XSAccessor was available - so is Sub::Name
804 no warnings 'redefine';
806 my $fq_name = "${current_class}::${methname}";
807 *$fq_name = Sub::Name::subname($fq_name, $resolved_implementation);
809 # need to update what the shim expects too *in case* its
810 # ->can was cached for some moronic reason
811 $expected_cref = $resolved_implementation;
812 Scalar::Util::weaken($expected_cref);
815 # older perls segfault if the cref behind the goto throws
816 # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
817 return $resolved_implementation->(@_) if __CAG_ENV__::BROKEN_GOTO;
819 goto $resolved_implementation;
822 Scalar::Util::weaken($expected_cref); # to break the self-reference
826 # no Sub::Name - just install the coderefs directly (compiling every time)
827 elsif (__CAG_ENV__::NO_SUBNAME) {
828 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
829 $maker_templates->{$type}{pp_generator}->($group, $field);
832 "no warnings 'redefine'; sub ${class}::${methname} { $src }; 1",
835 undef; # so that no further attempt will be made to install anything
838 # a coderef generator with a variable pad (returns a fresh cref on every invocation)
840 ($accessor_maker_cache->{pp}{$type}{$group}{$field} ||= do {
841 my $src = $accessor_maker_cache->{source}{$type}{$group}{$field} ||=
842 $maker_templates->{$type}{pp_generator}->($group, $field);
844 $cag_eval->( "sub { my \$dummy; sub { \$dummy if 0; $src } }" );