5f9c300f386f4d7a069ad849137c3f834d1f8efc
[p5sagit/Class-Accessor-Grouped.git] / lib / Class / Accessor / Grouped.pm
1 package Class::Accessor::Grouped;
2 use strict;
3 use warnings;
4 use Carp ();
5 use Scalar::Util ();
6 use MRO::Compat;
7 use Sub::Name ();
8
9 our $VERSION = '0.09007';
10 $VERSION = eval $VERSION;
11
12 # when changing minimum version don't forget to adjust L</PERFROMANCE> as well
13 our $__minimum_xsa_version = '1.06';
14
15 our $USE_XS;
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;
20
21 my ($xsa_loaded, $xsa_autodetected);
22
23 my $load_xsa = sub {
24     return if $xsa_loaded++;
25     require Class::XSAccessor;
26     Class::XSAccessor->VERSION($__minimum_xsa_version);
27 };
28
29 my $use_xs = sub {
30     if (defined $USE_XS) {
31         $load_xsa->() if ($USE_XS && ! $xsa_loaded);
32         return $USE_XS;
33     }
34
35     $xsa_autodetected = 1;
36     $USE_XS = 0;
37
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') {
42         local $@;
43         eval { $load_xsa->(); $USE_XS = 1 };
44     }
45
46     return $USE_XS;
47 };
48
49 my $maker_type_map = {
50   rw => {
51     xsa => 'accessors',
52     cag => 'make_group_accessor',
53   },
54   ro => {
55     xsa => 'getters',
56     cag => 'make_group_ro_accessor',
57   },
58   wo => {
59     xsa => 'setters',
60     cag => 'make_group_wo_accessor',
61   },
62 };
63
64 # When installing an XSA simple accessor, we need to make sure we are not
65 # short-circuiting a (compile or runtime) get_simple/set_simple override.
66 # What we do here is install a lazy first-access check, which will decide
67 # the ultimate coderef being placed in the accessor slot
68
69 my $no_xsa_classes_warned;
70 my $add_xs_accessor = sub {
71     my ($class, $group, $field, $name, $type) = @_;
72
73     Class::XSAccessor->import({
74         replace => 1,
75         class => $class,
76         $maker_type_map->{$type}{xsa} => {
77             $name => $field,
78         },
79     });
80
81     my $xs_cref = $class->can($name);
82
83     my $pp_cref = do {
84         my $cag_method = $maker_type_map->{$type}{cag};
85         local $USE_XS = 0;
86         $class->$cag_method ($group, $field, $name, $type);
87     };
88
89     # can't use pkg_gen to track this stuff, as it doesn't
90     # detect superclass mucking
91     my $original_getter = __PACKAGE__->can ("get_$group");
92     my $original_setter = __PACKAGE__->can ("set_$group");
93
94     return sub {
95         my $self = $_[0];
96         my $current_class = Scalar::Util::blessed( $self ) || $self;
97
98         my $final_cref;
99         if (
100             $current_class->can("get_$group") == $original_getter
101                 &&
102             $current_class->can("set_$group") == $original_setter
103         ) {
104             # nothing has changed, might as well use the XS crefs
105             #
106             # note that by the time this code executes, we already have
107             # *objects* (since XSA works on 'simple' only by definition).
108             # If someone is mucking with the symbol table *after* there
109             # are some objects already - look! many, shiny pieces! :)
110             $final_cref = $xs_cref;
111         }
112         else {
113             $final_cref = $pp_cref;
114             if ($USE_XS and ! $xsa_autodetected and ! $no_xsa_classes_warned->{$current_class}++) {
115
116                 # not using Carp since the line where this happens doesn't mean much
117                 warn 'Explicitly requested use of Class::XSAccessor disabled for objects of class '
118                    . "'$current_class' due to an overriden get_$group and/or set_$group\n";
119             }
120         }
121
122         # installing an XSA cref that was originally created on a class
123         # different than $current_class is perfectly safe as per
124         # C::XSA's author
125         my $fq_meth = "${current_class}::${name}";
126
127         no strict qw/refs/;
128         no warnings qw/redefine/;
129
130         *$fq_meth = Sub::Name::subname($fq_meth, $final_cref);
131
132         # older perls segfault if the cref behind the goto throws
133         # http://rt.perl.org/rt3/Public/Bug/Display.html?id=35878
134         return $final_cref->(@_) if ($] < 5.008009);
135
136         goto $final_cref;
137     };
138 };
139
140 my $install_group_accessors = sub {
141     my($self, $maker, $group, @fields) = @_;
142     my $class = Scalar::Util::blessed $self || $self;
143
144     no strict 'refs';
145     no warnings 'redefine';
146
147     # So we don't have to do lots of lookups inside the loop.
148     $maker = $self->can($maker) unless ref $maker eq 'CODE';
149
150     foreach (@fields) {
151         if( $_ eq 'DESTROY' ) {
152             Carp::carp("Having a data accessor named DESTROY in ".
153                        "'$class' is unwise.");
154         }
155
156         my ($name, $field) = (ref $_)
157             ? (@$_)
158             : ($_, $_)
159         ;
160
161         my $alias = "_${name}_accessor";
162
163         for my $meth ($name, $alias) {
164
165             # the maker may elect to not return anything, meaning it already
166             # installed the coderef for us
167             my $cref = $self->$maker($group, $field, $meth)
168                 or next;
169
170             my $fq_meth = join('::', $class, $meth);
171
172             *$fq_meth = Sub::Name::subname($fq_meth, $cref);
173                 #unless defined &{$class."\:\:$field"}
174         }
175     }
176 };
177
178
179 =head1 NAME
180
181 Class::Accessor::Grouped - Lets you build groups of accessors
182
183 =head1 SYNOPSIS
184
185 =head1 DESCRIPTION
186
187 This class lets you build groups of accessors that will call different
188 getters and setters.
189
190 =head1 METHODS
191
192 =head2 mk_group_accessors
193
194 =over 4
195
196 =item Arguments: $group, @fieldspec
197
198 Returns: none
199
200 =back
201
202 Creates a set of accessors in a given group.
203
204 $group is the name of the accessor group for the generated accessors; they
205 will call get_$group($field) on get and set_$group($field, $value) on set.
206
207 If you want to mimic Class::Accessor's mk_accessors $group has to be 'simple'
208 to tell Class::Accessor::Grouped to use its own get_simple and set_simple
209 methods.
210
211 @fieldspec is a list of field/accessor names; if a fieldspec is a scalar
212 this is used as both field and accessor name, if a listref it is expected to
213 be of the form [ $accessor, $field ].
214
215 =cut
216
217 sub mk_group_accessors {
218   my ($self, $group, @fields) = @_;
219
220   $self->$install_group_accessors('make_group_accessor', $group, @fields);
221   return;
222 }
223
224 =head2 mk_group_ro_accessors
225
226 =over 4
227
228 =item Arguments: $group, @fieldspec
229
230 Returns: none
231
232 =back
233
234 Creates a set of read only accessors in a given group. Identical to
235 L</mk_group_accessors> but accessors will throw an error if passed a value
236 rather than setting the value.
237
238 =cut
239
240 sub mk_group_ro_accessors {
241     my($self, $group, @fields) = @_;
242
243     $self->$install_group_accessors('make_group_ro_accessor', $group, @fields);
244 }
245
246 =head2 mk_group_wo_accessors
247
248 =over 4
249
250 =item Arguments: $group, @fieldspec
251
252 Returns: none
253
254 =back
255
256 Creates a set of write only accessors in a given group. Identical to
257 L</mk_group_accessors> but accessors will throw an error if not passed a
258 value rather than getting the value.
259
260 =cut
261
262 sub mk_group_wo_accessors {
263     my($self, $group, @fields) = @_;
264
265     $self->$install_group_accessors('make_group_wo_accessor', $group, @fields);
266 }
267
268 =head2 make_group_accessor
269
270 =over 4
271
272 =item Arguments: $group, $field, $method
273
274 Returns: \&accessor_coderef ?
275
276 =back
277
278 Called by mk_group_accessors for each entry in @fieldspec. Either returns
279 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
280 C<undef> if it elects to install the coderef on its own.
281
282 =cut
283
284 sub make_group_accessor {
285     my ($class, $group, $field, $name) = @_;
286
287     if ( $group eq 'simple' && $use_xs->() ) {
288         return $add_xs_accessor->(@_, 'rw');
289     }
290
291     my $set = "set_$group";
292     my $get = "get_$group";
293
294     $field =~ s/'/\\'/g;
295
296     # eval for faster fastiness
297     my $code = eval "sub {
298         if(\@_ > 1) {
299             return shift->$set('$field', \@_);
300         }
301         else {
302             return shift->$get('$field');
303         }
304     };";
305     Carp::croak $@ if $@;
306
307     return $code;
308 }
309
310 =head2 make_group_ro_accessor
311
312 =over 4
313
314 =item Arguments: $group, $field, $method
315
316 Returns: \&accessor_coderef ?
317
318 =back
319
320 Called by mk_group_ro_accessors for each entry in @fieldspec. Either returns
321 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
322 C<undef> if it elects to install the coderef on its own.
323
324 =cut
325
326 sub make_group_ro_accessor {
327     my($class, $group, $field, $name) = @_;
328
329     if ( $group eq 'simple' && $use_xs->() ) {
330         return $add_xs_accessor->(@_, 'ro');
331     }
332
333     my $get = "get_$group";
334
335     $field =~ s/'/\\'/g;
336
337     my $code = eval "sub {
338         if(\@_ > 1) {
339             my \$caller = caller;
340             Carp::croak(\"'\$caller' cannot alter the value of '$field' on \".
341                         \"objects of class '$class'\");
342         }
343         else {
344             return shift->$get('$field');
345         }
346     };";
347     Carp::croak $@ if $@;
348
349     return $code;
350 }
351
352 =head2 make_group_wo_accessor
353
354 =over 4
355
356 =item Arguments: $group, $field, $method
357
358 Returns: \&accessor_coderef ?
359
360 =back
361
362 Called by mk_group_wo_accessors for each entry in @fieldspec. Either returns
363 a coderef which will be installed at C<&__PACKAGE__::$method>, or returns
364 C<undef> if it elects to install the coderef on its own.
365
366 =cut
367
368 sub make_group_wo_accessor {
369     my($class, $group, $field, $name) = @_;
370
371     if ( $group eq 'simple' && $use_xs->() ) {
372         return $add_xs_accessor->(@_, 'wo')
373     }
374
375     my $set = "set_$group";
376
377     $field =~ s/'/\\'/g;
378
379     my $code = eval "sub {
380         unless (\@_ > 1) {
381             my \$caller = caller;
382             Carp::croak(\"'\$caller' cannot access the value of '$field' on \".
383                         \"objects of class '$class'\");
384         }
385         else {
386             return shift->$set('$field', \@_);
387         }
388     };";
389     Carp::croak $@ if $@;
390
391     return $code;
392 }
393
394 =head2 get_simple
395
396 =over 4
397
398 =item Arguments: $field
399
400 Returns: $value
401
402 =back
403
404 Simple getter for hash-based objects which returns the value for the field
405 name passed as an argument.
406
407 =cut
408
409 sub get_simple {
410   return $_[0]->{$_[1]};
411 }
412
413 =head2 set_simple
414
415 =over 4
416
417 =item Arguments: $field, $new_value
418
419 Returns: $new_value
420
421 =back
422
423 Simple setter for hash-based objects which sets and then returns the value
424 for the field name passed as an argument.
425
426 =cut
427
428 sub set_simple {
429   return $_[0]->{$_[1]} = $_[2];
430 }
431
432
433 =head2 get_inherited
434
435 =over 4
436
437 =item Arguments: $field
438
439 Returns: $value
440
441 =back
442
443 Simple getter for Classes and hash-based objects which returns the value for
444 the field name passed as an argument. This behaves much like
445 L<Class::Data::Accessor> where the field can be set in a base class,
446 inherited and changed in subclasses, and inherited and changed for object
447 instances.
448
449 =cut
450
451 sub get_inherited {
452     my $class;
453
454     if ( defined( $class = Scalar::Util::blessed $_[0] ) ) {
455         if (Scalar::Util::reftype $_[0] eq 'HASH') {
456           return $_[0]->{$_[1]} if exists $_[0]->{$_[1]};
457         }
458         else {
459           Carp::croak('Cannot get inherited value on an object instance that is not hash-based');
460         }
461     }
462     else {
463         $class = $_[0];
464     }
465
466     no strict 'refs';
467     no warnings 'uninitialized';
468
469     my $cag_slot = '::__cag_'. $_[1];
470     return ${$class.$cag_slot} if defined(${$class.$cag_slot});
471
472     # we need to be smarter about recalculation, as @ISA (thus supers) can very well change in-flight
473     my $cur_gen = mro::get_pkg_gen ($class);
474     if ( $cur_gen != ${$class.'::__cag_pkg_gen__'} ) {
475         @{$class.'::__cag_supers__'} = $_[0]->get_super_paths;
476         ${$class.'::__cag_pkg_gen__'} = $cur_gen;
477     }
478
479     for (@{$class.'::__cag_supers__'}) {
480         return ${$_.$cag_slot} if defined(${$_.$cag_slot});
481     };
482
483     return undef;
484 }
485
486 =head2 set_inherited
487
488 =over 4
489
490 =item Arguments: $field, $new_value
491
492 Returns: $new_value
493
494 =back
495
496 Simple setter for Classes and hash-based objects which sets and then returns
497 the value for the field name passed as an argument. When called on a hash-based
498 object it will set the appropriate hash key value. When called on a class, it
499 will set a class level variable.
500
501 B<Note:>: This method will die if you try to set an object variable on a non
502 hash-based object.
503
504 =cut
505
506 sub set_inherited {
507     if (defined Scalar::Util::blessed $_[0]) {
508         if (Scalar::Util::reftype $_[0] eq 'HASH') {
509             return $_[0]->{$_[1]} = $_[2];
510         } else {
511             Carp::croak('Cannot set inherited value on an object instance that is not hash-based');
512         };
513     } else {
514         no strict 'refs';
515
516         return ${$_[0].'::__cag_'.$_[1]} = $_[2];
517     };
518 }
519
520 =head2 get_component_class
521
522 =over 4
523
524 =item Arguments: $field
525
526 Returns: $value
527
528 =back
529
530 Gets the value of the specified component class.
531
532     __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
533
534     $self->result_class->method();
535
536     ## same as
537     $self->get_component_class('result_class')->method();
538
539 =cut
540
541 sub get_component_class {
542     return $_[0]->get_inherited($_[1]);
543 };
544
545 =head2 set_component_class
546
547 =over 4
548
549 =item Arguments: $field, $class
550
551 Returns: $new_value
552
553 =back
554
555 Inherited accessor that automatically loads the specified class before setting
556 it. This method will die if the specified class could not be loaded.
557
558     __PACKAGE__->mk_group_accessors('component_class' => 'result_class');
559     __PACKAGE__->result_class('MyClass');
560
561     $self->result_class->method();
562
563 =cut
564
565 sub set_component_class {
566     if ($_[2]) {
567         local $^W = 0;
568         require Class::Inspector;
569         if (Class::Inspector->installed($_[2]) && !Class::Inspector->loaded($_[2])) {
570             eval "use $_[2]";
571
572             Carp::croak("Could not load $_[1] '$_[2]': ", $@) if $@;
573         };
574     };
575
576     return $_[0]->set_inherited($_[1], $_[2]);
577 };
578
579 =head2 get_super_paths
580
581 Returns a list of 'parent' or 'super' class names that the current class inherited from.
582
583 =cut
584
585 sub get_super_paths {
586     return @{mro::get_linear_isa( ref($_[0]) || $_[0] )};
587 };
588
589 1;
590
591 =head1 PERFORMANCE
592
593 To provide total flexibility L<Class::Accessor::Grouped> calls methods
594 internally while performing get/set actions, which makes it noticeably
595 slower than similar modules. To compensate, this module will automatically
596 use the insanely fast L<Class::XSAccessor> to generate the C<simple>-group
597 accessors, if L<< Class::XSAccessor >= 1.06|Class::XSAccessor >> is
598 available on your system.
599
600 =head2 Benchmark
601
602 This is the result of a set/get/set loop benchmark on perl 5.12.1 with
603 thread support, showcasing most popular accessor builders: L<Moose>, L<Mouse>,
604 L<CAF|Class::Accessor::Fast>, L<CAF_XS|Class::Accessor::Fast::XS>
605 and L<XSA|Class::XSAccessor>:
606
607             Rate     CAG   moOse     CAF HANDMADE  CAF_XS moUse_XS CAG_XS     XSA
608  CAG      1777/s      --    -27%    -29%     -36%    -62%     -67%   -72%    -73%
609  moOse    2421/s     36%      --     -4%     -13%    -48%     -55%   -61%    -63%
610  CAF      2511/s     41%      4%      --     -10%    -47%     -53%   -60%    -61%
611  HANDMADE 2791/s     57%     15%     11%       --    -41%     -48%   -56%    -57%
612  CAF_XS   4699/s    164%     94%     87%      68%      --     -13%   -25%    -28%
613  moUse_XS 5375/s    203%    122%    114%      93%     14%       --   -14%    -18%
614  CAG_XS   6279/s    253%    159%    150%     125%     34%      17%     --     -4%
615  XSA      6515/s    267%    169%    159%     133%     39%      21%     4%      --
616
617 Benchmark program is available in the root of the
618 L<repository|http://search.cpan.org/dist/Class-Accessor-Grouped/>:
619
620 =head2 Notes on Class::XSAccessor
621
622 You can force (or disable) the use of L<Class::XSAccessor> before creating a
623 particular C<simple> accessor by either manipulating the global variable
624 C<$Class::Accessor::Grouped::USE_XS> to true or false (preferably with
625 L<localization|perlfunc/local>, or you can do so before runtime via the
626 C<CAG_USE_XS> environment variable.
627
628 Since L<Class::XSAccessor> has no knowledge of L</get_simple> and
629 L</set_simple> this module does its best to detect if you are overriding
630 one of these methods and will fall back to using the perl version of the
631 accessor in order to maintain consistency. However be aware that if you
632 enable use of C<Class::XSAccessor> (automatically or explicitly), create
633 an object, invoke a simple accessor on that object, and B<then> manipulate
634 the symbol table to install a C<get/set_simple> override - you get to keep
635 all the pieces.
636
637 While L<Class::XSAccessor> works surprisingly well for the amount of black
638 magic it tries to pull off, it's still black magic. At present (Sep 2010)
639 the module is known to have problems on Windows under heavy thread-stress
640 (e.g. Win32+Apache+mod_perl). Thus for the time being L<Class::XSAccessor>
641 will not be used automatically if you are running under C<MSWin32>.
642
643 =head1 AUTHORS
644
645 Matt S. Trout <mst@shadowcatsystems.co.uk>
646
647 Christopher H. Laco <claco@chrislaco.com>
648
649 =head1 CONTRIBUTORS
650
651 Caelum: Rafael Kitover <rkitover@cpan.org>
652
653 groditi: Guillermo Roditi <groditi@cpan.org>
654
655 Jason Plum <jason.plum@bmmsi.com>
656
657 ribasushi: Peter Rabbitson <ribasushi@cpan.org>
658
659
660 =head1 COPYRIGHT & LICENSE
661
662 Copyright (c) 2006-2010 Matt S. Trout <mst@shadowcatsystems.co.uk>
663
664 This program is free software; you can redistribute it and/or modify
665 it under the same terms as perl itself.
666
667 =cut