1 package Class::Accessor::Grouped;
9 our $VERSION = '0.09006';
10 $VERSION = eval $VERSION;
12 # when changing minimum version don't forget to adjust L</PERFROMANCE> as well
13 our $__minimum_xsa_version = '1.06';
16 # the unless defined is here so that we can override the value
17 # before require/use, *regardless* of the state of $ENV{CAG_USE_XS}
18 $USE_XS = $ENV{CAG_USE_XS}
19 unless defined $USE_XS;
21 my ($xsa_loaded, $xsa_autodetected);
24 return if $xsa_loaded++;
25 require Class::XSAccessor;
26 Class::XSAccessor->VERSION($__minimum_xsa_version);
30 if (defined $USE_XS) {
31 $load_xsa->() if ($USE_XS && ! $xsa_loaded);
35 $xsa_autodetected = 1;
38 # Class::XSAccessor is segfaulting on win32, in some
39 # esoteric heavily-threaded scenarios
40 # Win32 users can set $USE_XS/CAG_USE_XS to try to use it anyway
41 if ($^O ne 'MSWin32') {
43 eval { $load_xsa->(); $USE_XS = 1 };
49 my $add_xs_accessor = sub {
50 Class::XSAccessor->import({
59 Class::Accessor::Grouped - Lets you build groups of accessors
65 This class lets you build groups of accessors that will call different
70 =head2 mk_group_accessors
74 =item Arguments: $group, @fieldspec
80 Creates a set of accessors in a given group.
82 $group is the name of the accessor group for the generated accessors; they
83 will call get_$group($field) on get and set_$group($field, $value) on set.
85 If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
86 to tell Class::Accessor::Grouped to use its own get_simple and set_simple
89 @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
90 this is used as both field and accessor name, if a listref it is expected to
91 be of the form [ $accessor, $field ].
95 sub mk_group_accessors {
96 my ($self, $group, @fields) = @_;
98 $self->_mk_group_accessors('make_group_accessor', $group, @fields);
105 no warnings 'redefine';
107 sub _mk_group_accessors {
108 my($self, $maker, $group, @fields) = @_;
109 my $class = Scalar::Util::blessed $self || $self;
111 # So we don't have to do lots of lookups inside the loop.
112 $maker = $self->can($maker) unless ref $maker;
115 if( $_ eq 'DESTROY' ) {
116 Carp::carp("Having a data accessor named DESTROY in ".
117 "'$class' is unwise.");
120 my ($name, $field) = (ref $_)
125 my $alias = "_${name}_accessor";
127 for my $meth ($name, $alias) {
129 # the maker may elect to not return anything, meaning it already
130 # installed the coderef for us
131 my $cref = $self->$maker($group, $field, $meth)
134 my $fq_meth = join('::', $class, $meth);
136 *$fq_meth = Sub::Name::subname($fq_meth, $cref);
137 #unless defined &{$class."\:\:$field"}
143 =head2 mk_group_ro_accessors
147 =item Arguments: $group, @fieldspec
153 Creates a set of read only accessors in a given group. Identical to
154 L</mk_group_accessors> but accessors will throw an error if passed a value
155 rather than setting the value.
159 sub mk_group_ro_accessors {
160 my($self, $group, @fields) = @_;
162 $self->_mk_group_accessors('make_group_ro_accessor', $group, @fields);
165 =head2 mk_group_wo_accessors
169 =item Arguments: $group, @fieldspec
175 Creates a set of write only accessors in a given group. Identical to
176 L</mk_group_accessors> but accessors will throw an error if not passed a
177 value rather than getting the value.
181 sub mk_group_wo_accessors {
182 my($self, $group, @fields) = @_;
184 $self->_mk_group_accessors('make_group_wo_accessor', $group, @fields);
187 =head2 make_group_accessor
191 =item Arguments: $group, $field, $method
193 Returns: \&accessor_coderef ?
197 Called by mk_group_accessors for each entry in @fieldspec. Either returns
198 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
199 C<undef> if it elects to install the coderef on its own.
203 sub make_group_accessor {
204 my ($class, $group, $field, $name) = @_;
206 if ( $group eq 'simple' && $use_xs->() ) {
207 return $add_xs_accessor->({
215 my $set = "set_$group";
216 my $get = "get_$group";
220 # eval for faster fastiness
221 my $code = eval "sub {
223 return shift->$set('$field', \@_);
226 return shift->$get('$field');
229 Carp::croak $@ if $@;
234 =head2 make_group_ro_accessor
238 =item Arguments: $group, $field, $method
240 Returns: \&accessor_coderef ?
244 Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
245 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
246 C<undef> if it elects to install the coderef on its own.
250 sub make_group_ro_accessor {
251 my($class, $group, $field, $name) = @_;
253 if ( $group eq 'simple' && $use_xs->() ) {
254 return $add_xs_accessor->({
262 my $get = "get_$group";
266 my $code = eval "sub {
268 my \$caller = caller;
269 Carp::croak(\"'\$caller' cannot alter the value of '$field' on \".
270 \"objects of class '$class'\");
273 return shift->$get('$field');
276 Carp::croak $@ if $@;
281 =head2 make_group_wo_accessor
285 =item Arguments: $group, $field, $method
287 Returns: \&accessor_coderef ?
291 Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
292 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
293 C<undef> if it elects to install the coderef on its own.
297 sub make_group_wo_accessor {
298 my($class, $group, $field, $name) = @_;
300 if ( $group eq 'simple' && $use_xs->() ) {
301 return $add_xs_accessor->({
309 my $set = "set_$group";
313 my $code = eval "sub {
315 my \$caller = caller;
316 Carp::croak(\"'\$caller' cannot access the value of '$field' on \".
317 \"objects of class '$class'\");
320 return shift->$set('$field', \@_);
323 Carp::croak $@ if $@;
332 =item Arguments: $field
338 Simple getter for hash-based objects which returns the value for the field
339 name passed as an argument.
344 return $_[0]->{$_[1]};
351 =item Arguments: $field, $new_value
357 Simple setter for hash-based objects which sets and then returns the value
358 for the field name passed as an argument.
363 return $_[0]->{$_[1]} = $_[2];
371 =item Arguments: $field
377 Simple getter for Classes and hash-based objects which returns the value for
378 the field name passed as an argument. This behaves much like
379 L<Class::Data::Accessor> where the field can be set in a base class,
380 inherited and changed in subclasses, and inherited and changed for object
388 if ( ($class = ref $_[0]) && Scalar::Util::blessed $_[0]) {
389 if (Scalar::Util::reftype $_[0] eq 'HASH') {
390 return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
393 Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
401 no warnings qw/uninitialized/;
403 my $cag_slot = '::__cag_'. $_[1];
404 return ${$class.$cag_slot} if defined(${$class.$cag_slot});
406 # we need to be smarter about recalculation, as @ISA (thus supers) can very well change in-flight
407 my $cur_gen = mro::get_pkg_gen ($class);
408 if ( $cur_gen != ${$class.'::__cag_pkg_gen__'} ) {
409 @{$class.'::__cag_supers__'} = $_[0]->get_super_paths;
410 ${$class.'::__cag_pkg_gen__'} = $cur_gen;
413 for (@{$class.'::__cag_supers__'}) {
414 return ${$_.$cag_slot} if defined(${$_.$cag_slot});
424 =item Arguments: $field, $new_value
430 Simple setter for Classes and hash-based objects which sets and then returns
431 the value for the field name passed as an argument. When called on a hash-based
432 object it will set the appropriate hash key value. When called on a class, it
433 will set a class level variable.
435 B<Note:>: This method will die if you try to set an object variable on a non
441 if (Scalar::Util::blessed $_[0]) {
442 if (Scalar::Util::reftype $_[0] eq 'HASH') {
443 return $_[0]->{$_[1]} = $_[2];
445 Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
450 return ${$_[0].'::__cag_'.$_[1]} = $_[2];
454 =head2 get_component_class
458 =item Arguments: $field
464 Gets the value of the specified component class.
466 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
468 $self->result_class->method();
471 $self->get_component_class('result_class')->method();
475 sub get_component_class {
476 return $_[0]->get_inherited($_[1]);
479 =head2 set_component_class
483 =item Arguments: $field, $class
489 Inherited accessor that automatically loads the specified class before setting
490 it. This method will die if the specified class could not be loaded.
492 __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
493 __PACKAGE__->result_class('MyClass');
495 $self->result_class->method();
499 sub set_component_class {
502 require Class::Inspector;
503 if (Class::Inspector->installed($_[2]) && !Class::Inspector->loaded($_[2])) {
506 Carp::croak("Could not load $_[1] '$_[2]': ", $@) if $@;
510 return $_[0]->set_inherited($_[1], $_[2]);
513 =head2 get_super_paths
515 Returns a list of 'parent' or 'super' class names that the current class inherited from.
519 sub get_super_paths {
520 return @{mro::get_linear_isa( ref($_[0]) || $_[0] )};
527 To provide total flexibility L<Class::Accessor::Grouped> calls methods
528 internally while performing get/set actions, which makes it noticeably
529 slower than similar modules. To compensate, this module will automatically
530 use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
531 accessors, if L<< Class::XSAccessor >= 1.06|Class::XSAccessor >> is
532 available on your system.
536 This is the result of a set/get/set loop benchmark on perl 5.12.1 with
537 thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
538 L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>
539 and L<XSA|Class::XSAccessor>:
541 Rate CAG moOse CAF HANDMADE CAF_XS moUse_XS CAG_XS XSA
542 CAG 1777/s -- -27% -29% -36% -62% -67% -72% -73%
543 moOse 2421/s 36% -- -4% -13% -48% -55% -61% -63%
544 CAF 2511/s 41% 4% -- -10% -47% -53% -60% -61%
545 HANDMADE 2791/s 57% 15% 11% -- -41% -48% -56% -57%
546 CAF_XS 4699/s 164% 94% 87% 68% -- -13% -25% -28%
547 moUse_XS 5375/s 203% 122% 114% 93% 14% -- -14% -18%
548 CAG_XS 6279/s 253% 159% 150% 125% 34% 17% -- -4%
549 XSA 6515/s 267% 169% 159% 133% 39% 21% 4% --
551 Benchmark program is available in the root of the
552 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
554 =head2 Notes on Class::XSAccessor
556 While L<Class::XSAccessor> works surprisingly well for the amount of black
557 magic it tries to pull off, it's still black magic. At present (Sep 2010)
558 the module is known to have problems on Windows under heavy thread-stress
559 (e.g. Win32+Apache+mod_perl). Thus for the time being L<Class::XSAccessor>
560 will not be used automatically if you are running under C<MSWin32>.
562 You can force the use of L<Class::XSAccessor> before creating a particular
563 C<simple> accessor by either manipulating the global variable
564 C<$Class::Accessor::Grouped::USE_XS>, or you can do so before runtime via the
565 C<CAG_USE_XS> environment variable.
569 Matt S. Trout <mst@shadowcatsystems.co.uk>
571 Christopher H. Laco <claco@chrislaco.com>
575 Caelum: Rafael Kitover <rkitover@cpan.org>
577 groditi: Guillermo Roditi <groditi@cpan.org>
579 Jason Plum <jason.plum@bmmsi.com>
581 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
584 =head1 COPYRIGHT & LICENSE
586 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
588 This program is free software; you can redistribute it and/or modify
589 it under the same terms as perl itself.