6 use Scalar::Util qw/blessed refaddr reftype weaken isweak/;
12 no warnings 'recursion';
14 use namespace::clean -except => 'meta';
16 # the double not makes this no longer undef, so exempt from useless constant warnings in older perls
17 use constant DEBUG => not not our $DEBUG || $ENV{DATA_VISITOR_DEBUG};
19 our $VERSION = "0.26";
21 has tied_as_objects => (
34 my ( $self, $category, @msg ) = @_;
38 if ( $DEBUG{$category} or !exists($DEBUG{$category}) ) {
39 $self->_print_trace("$self: " . join("",
40 ( " " x ( $self->{depth} - 1 ) ),
41 ( join(" ", "$category:", map { overload::StrVal($_) } @msg) ),
47 my ( $self, @msg ) = @_;
54 local $self->{depth} = (($self->{depth}||0) + 1) if DEBUG;
55 my $seen_hash = local $self->{_seen} = ($self->{_seen} || {}); # delete it after we're done with the whole visit
59 foreach my $data ( @_ ) {
60 $self->trace( flow => visit => $data ) if DEBUG;
62 if ( my $refaddr = ref($data) && refaddr($data) ) { # only references need recursion checks
63 $seen_hash->{weak} ||= isweak($data) if $self->weaken;
65 if ( exists $seen_hash->{$refaddr} ) {
66 $self->trace( mapping => found_mapping => from => $data, to => $seen_hash->{$refaddr} ) if DEBUG;
67 push @ret, $self->visit_seen( $data, $seen_hash->{$refaddr} );
70 $self->trace( mapping => no_mapping => $data ) if DEBUG;
74 if ( defined wantarray ) {
75 push @ret, scalar($self->visit_no_rec_check($data));
77 $self->visit_no_rec_check($data);
81 return ( @_ == 1 ? $ret[0] : @ret );
85 my ( $self, $data, $result ) = @_;
90 my ( $self, $data ) = @_;
91 $self->{_seen}{ refaddr($data) };
94 sub _register_mapping {
95 my ( $self, $data, $new_data ) = @_;
96 return $new_data unless ref $data;
97 $self->trace( mapping => register_mapping => from => $data, to => $new_data, in => (caller(1))[3] ) if DEBUG;
98 $self->{_seen}{ refaddr($data) } = $new_data;
101 sub visit_no_rec_check {
102 my ( $self, $data ) = @_;
104 if ( blessed($data) ) {
105 return $self->visit_object($_[1]);
106 } elsif ( ref $data ) {
107 return $self->visit_ref($_[1]);
110 return $self->visit_value($_[1]);
114 my ( $self, $object ) = @_;
115 $self->trace( flow => visit_object => $object ) if DEBUG;
117 if ( not defined wantarray ) {
118 $self->_register_mapping( $object, $object );
119 $self->visit_value($_[1]);
122 return $self->_register_mapping( $object, $self->visit_value($_[1]) );
127 my ( $self, $data ) = @_;
129 local $self->{depth} = (($self->{depth}||0) + 1) if DEBUG;
131 $self->trace( flow => visit_ref => $data ) if DEBUG;
133 my $reftype = reftype $data;
135 $reftype = "SCALAR" if $reftype =~ /^(?:REF|LVALUE|VSTRING)$/;
137 my $method = $self->can(lc "visit_$reftype") || "visit_value";
139 return $self->$method($_[1]);
143 my ( $self, $value ) = @_;
144 $self->trace( flow => visit_value => $value ) if DEBUG;
149 my ( $self, $hash ) = @_;
151 local $self->{depth} = (($self->{depth}||0) + 1) if DEBUG;
153 if ( defined(tied(%$hash)) and $self->tied_as_objects ) {
154 return $self->visit_tied_hash(tied(%$hash), $_[1]);
156 return $self->visit_normal_hash($_[1]);
160 sub visit_normal_hash {
161 my ( $self, $hash ) = @_;
163 if ( defined wantarray ) {
165 $self->_register_mapping( $hash, $new_hash );
167 %$new_hash = $self->visit_hash_entries($_[1]);
169 return $self->retain_magic( $_[1], $new_hash );
171 $self->_register_mapping($hash, $hash);
172 $self->visit_hash_entries($_[1]);
177 sub visit_tied_hash {
178 my ( $self, $tied, $hash ) = @_;
180 if ( defined wantarray ) {
182 $self->_register_mapping( $hash, $new_hash );
184 if ( blessed(my $new_tied = $self->visit_tied($_[1], $_[2])) ) {
185 $self->trace( data => tying => var => $new_hash, to => $new_tied ) if DEBUG;
186 tie %$new_hash, 'Tie::ToObject', $new_tied;
187 return $self->retain_magic($_[2], $new_hash);
189 return $self->visit_normal_hash($_[2]);
192 $self->_register_mapping($hash, $hash);
193 $self->visit_tied($_[1], $_[2]);
198 sub visit_hash_entries {
199 my ( $self, $hash ) = @_;
201 if ( not defined wantarray ) {
202 $self->visit_hash_entry( $_, $hash->{$_}, $hash ) for keys %$hash;
204 return map { $self->visit_hash_entry( $_, $hash->{$_}, $hash ) } keys %$hash;
208 sub visit_hash_entry {
209 my ( $self, $key, $value, $hash ) = @_;
211 $self->trace( flow => visit_hash_entry => key => $key, value => $value ) if DEBUG;
213 if ( not defined wantarray ) {
214 $self->visit_hash_key($key,$value,$hash);
215 $self->visit_hash_value($_[2],$key,$hash);
218 $self->visit_hash_key($key,$value,$hash),
219 $self->visit_hash_value($_[2],$key,$hash),
225 my ( $self, $key, $value, $hash ) = @_;
229 sub visit_hash_value {
230 my ( $self, $value, $key, $hash ) = @_;
235 my ( $self, $array ) = @_;
237 if ( defined(tied(@$array)) and $self->tied_as_objects ) {
238 return $self->visit_tied_array(tied(@$array), $_[1]);
240 return $self->visit_normal_array($_[1]);
244 sub visit_normal_array {
245 my ( $self, $array ) = @_;
247 if ( defined wantarray ) {
249 $self->_register_mapping( $array, $new_array );
251 @$new_array = $self->visit_array_entries($_[1]);
253 return $self->retain_magic( $_[1], $new_array );
255 $self->_register_mapping( $array, $array );
256 $self->visit_array_entries($_[1]);
262 sub visit_tied_array {
263 my ( $self, $tied, $array ) = @_;
265 if ( defined wantarray ) {
267 $self->_register_mapping( $array, $new_array );
269 if ( blessed(my $new_tied = $self->visit_tied($_[1], $_[2])) ) {
270 $self->trace( data => tying => var => $new_array, to => $new_tied ) if DEBUG;
271 tie @$new_array, 'Tie::ToObject', $new_tied;
272 return $self->retain_magic($_[2], $new_array);
274 return $self->visit_normal_array($_[2]);
277 $self->_register_mapping( $array, $array );
278 $self->visit_tied($_[1], $_[2]);
284 sub visit_array_entries {
285 my ( $self, $array ) = @_;
287 if ( not defined wantarray ) {
288 $self->visit_array_entry( $array->[$_], $_, $array ) for 0 .. $#$array;
290 return map { $self->visit_array_entry( $array->[$_], $_, $array ) } 0 .. $#$array;
294 sub visit_array_entry {
295 my ( $self, $value, $index, $array ) = @_;
300 my ( $self, $scalar ) = @_;
302 if ( defined(tied($$scalar)) and $self->tied_as_objects ) {
303 return $self->visit_tied_scalar(tied($$scalar), $_[1]);
305 return $self->visit_normal_scalar($_[1]);
309 sub visit_normal_scalar {
310 my ( $self, $scalar ) = @_;
312 if ( defined wantarray ) {
314 $self->_register_mapping( $scalar, \$new_scalar );
316 $new_scalar = $self->visit( $$scalar );
318 return $self->retain_magic($_[1], \$new_scalar);
320 $self->_register_mapping( $scalar, $scalar );
321 $self->visit( $$scalar );
327 sub visit_tied_scalar {
328 my ( $self, $tied, $scalar ) = @_;
330 if ( defined wantarray ) {
332 $self->_register_mapping( $scalar, \$new_scalar );
334 if ( blessed(my $new_tied = $self->visit_tied($_[1], $_[2])) ) {
335 $self->trace( data => tying => var => $new_scalar, to => $new_tied ) if DEBUG;
336 tie $new_scalar, 'Tie::ToObject', $new_tied;
337 return $self->retain_magic($_[2], \$new_scalar);
339 return $self->visit_normal_scalar($_[2]);
342 $self->_register_mapping( $scalar, $scalar );
343 $self->visit_tied($_[1], $_[2]);
349 my ( $self, $code ) = @_;
350 $self->visit_value($_[1]);
354 my ( $self, $glob ) = @_;
356 if ( defined(tied(*$glob)) and $self->tied_as_objects ) {
357 return $self->visit_tied_glob(tied(*$glob), $_[1]);
359 return $self->visit_normal_glob($_[1]);
363 sub visit_normal_glob {
364 my ( $self, $glob ) = @_;
366 if ( defined wantarray ) {
367 my $new_glob = Symbol::gensym();
368 $self->_register_mapping( $glob, $new_glob );
370 no warnings 'misc'; # Undefined value assigned to typeglob
371 *$new_glob = $self->visit( *$glob{$_} || next ) for qw/SCALAR ARRAY HASH/;
373 return $self->retain_magic($_[1], $new_glob);
375 $self->_register_mapping( $glob, $glob );
376 $self->visit( *$glob{$_} || next ) for qw/SCALAR ARRAY HASH/;
381 sub visit_tied_glob {
382 my ( $self, $tied, $glob ) = @_;
384 if ( defined wantarray ) {
385 my $new_glob = Symbol::gensym();
386 $self->_register_mapping( $glob, \$new_glob );
388 if ( blessed(my $new_tied = $self->visit_tied($_[1], $_[2])) ) {
389 $self->trace( data => tying => var => $new_glob, to => $new_tied ) if DEBUG;
390 tie *$new_glob, 'Tie::ToObject', $new_tied;
391 return $self->retain_magic($_[2], $new_glob);
393 return $self->visit_normal_glob($_[2]);
396 $self->_register_mapping( $glob, $glob );
397 $self->visit_tied($_[1], $_[2]);
403 my ( $self, $proto, $new ) = @_;
405 if ( blessed($proto) and !blessed($new) ) {
406 $self->trace( data => blessing => $new, ref $proto ) if DEBUG;
407 bless $new, ref $proto;
410 my $seen_hash = $self->{_seen};
411 if ( $seen_hash->{weak} ) {
415 foreach my $value ( Data::Alias::deref($proto) ) {
416 if ( ref $value and isweak($value) ) {
417 push @weak_refs, refaddr $value;
422 my %targets = map { refaddr($_) => 1 } @{ $self->{_seen} }{@weak_refs};
423 foreach my $value ( Data::Alias::deref($new) ) {
424 if ( ref $value and $targets{refaddr($value)}) {
425 push @{ $seen_hash->{weakened} ||= [] }, $value; # keep a ref around
432 # FIXME real magic, too
438 my ( $self, $tied, $var ) = @_;
439 $self->trace( flow => visit_tied => $tied ) if DEBUG;
440 $self->visit($_[1]); # as an object eventually
443 __PACKAGE__->meta->make_immutable if __PACKAGE__->meta->can("make_immutable");
453 Data::Visitor - Visitor style traversal of Perl data structures
458 # You probably want to use Data::Visitor::Callback for trivial things
463 extends qw(Data::Visitor);
465 has number_of_foos => (
472 my ( $self, $data ) = @_;
474 if ( defined $data and $data eq "foo" ) {
475 $self->number_of_foos( $self->number_of_foos + 1 );
481 my $counter = FooCounter->new;
485 some_foos => [ qw/foo foo bar foo/ ],
489 $counter->number_of_foos; # this is now 4
493 This module is a simple visitor implementation for Perl values.
495 It has a main dispatcher method, C<visit>, which takes a single perl value and
496 then calls the methods appropriate for that value.
498 It can recursively map (cloning as necessary) or just traverse most structures,
499 with support for per object behavior, circular structures, visiting tied
500 structures, and all ref types (hashes, arrays, scalars, code, globs).
502 L<Data::Visitor> is meant to be subclassed, but also ships with a callback
503 driven subclass, L<Data::Visitor::Callback>.
511 This method takes any Perl value as it's only argument, and dispatches to the
512 various other visiting methods using C<visit_no_rec_check>, based on the data's
515 If the value is a reference and has already been seen then C<visit_seen> is
518 =item visit_seen $data, $first_result
520 When an already seen value is encountered again it's typically replaced with
521 the result of the first visitation of that value. The value and the result of
522 the first visitation are passed as arguments.
524 Returns C<$first_result>.
526 =item visit_no_rec_check $data
528 Called for any value that has not yet been seen. Does the actual type based
529 dispatch for C<visit>.
531 Should not be called directly unless forcing a circular structure to be
532 unfolded. Use with caution as this may cause infinite recursion.
534 =item visit_object $object
536 If the value is a blessed object, C<visit> calls this method. The base
537 implementation will just forward to C<visit_value>.
539 =item visit_ref $value
541 Generic recursive visitor. All non blessed values are given to this.
543 C<visit_object> can delegate to this method in order to visit the object
546 This will check if the visitor can handle C<visit_$reftype> (lowercase), and if
547 not delegate to C<visit_value> instead.
549 =item visit_array $array_ref
551 =item visit_hash $hash_ref
553 =item visit_glob $glob_ref
555 =item visit_code $code_ref
557 =item visit_scalar $scalar_ref
559 These methods are called for the corresponding container type.
561 =item visit_value $value
563 If the value is anything else, this method is called. The base implementation
566 =item visit_hash_entries $hash
568 =item visit_hash_entry $key, $value, $hash
570 Delegates to C<visit_hash_key> and C<visit_hash_value>. The value is passed as
571 C<$_[2]> so that it is aliased.
573 =item visit_hash_key $key, $value, $hash
575 Calls C<visit> on the key and returns it.
577 =item visit_hash_value $value, $key, $hash
579 The value will be aliased (passed as C<$_[1]>).
581 =item visit_array_entries $array
583 =item visit_array_entry $value, $index, $array
585 Delegates to C<visit> on value. The value is passed as C<$_[1]> to retain
588 =item visit_tied $object, $var
590 When C<tied_as_objects> is enabled and a tied variable (hash, array, glob or
591 scalar) is encountered this method will be called on the tied object. If a
592 valid mapped value is returned, the newly constructed result container will be
593 tied to the return value and no iteration of the contents of the data will be
594 made (since all storage is delegated to the tied object).
596 If a non blessed value is returned from C<visit_tied> then the structure will
597 be iterated normally, and the result container will not be tied at all.
599 This is because tying to the same class and performing the tie operations will
600 not yield the same results in many cases.
602 =item retain_magic $orig, $copy
604 Copies over magic from C<$orig> to C<$copy>.
606 Currently only handles C<bless>. In the future this might be expanded using
607 L<Variable::Magic> but it isn't clear what the correct semantics for magic
612 Called if the C<DEBUG> constant is set with a trace message.
619 This object can be used as an C<fmap> of sorts - providing an ad-hoc functor
620 interface for Perl data structures.
622 In void context this functionality is ignored, but in any other context the
623 default methods will all try to return a value of similar structure, with it's
624 children also fmapped.
628 Create instance data using the L<Class::Accessor> interface. L<Data::Visitor>
629 inherits L<Class::Accessor> to get a sane C<new>.
631 Then override the callback methods in any way you like. To retain visitor
632 behavior, make sure to retain the functionality of C<visit_array> and
641 Add support for "natural" visiting of trees.
645 Expand C<retain_magic> to support tying at the very least, or even more with
646 L<Variable::Magic> if possible.
652 L<Data::Rmap>, L<Tree::Simple::VisitorFactory>, L<Data::Traverse>
654 L<http://en.wikipedia.org/wiki/Visitor_pattern>,
655 L<http://www.ninebynine.org/Software/Learning-Haskell-Notes.html#functors>,
656 L<http://en.wikipedia.org/wiki/Functor>
660 Yuval Kogman C<< <nothingmuch@woobling.org> >>
662 Marcel GrE<uuml>nauer, C<< <marcel@cpan.org> >>
664 =head1 COPYRIGHT & LICENSE
666 Copyright (c) 2006-2008 Yuval Kogman. All rights reserved
667 This program is free software; you can redistribute
668 it and/or modify it under the same terms as Perl itself.