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