3 package Data::Visitor::Callback;
9 use Scalar::Util qw/blessed refaddr reftype/;
11 no warnings 'recursion';
13 use namespace::clean -except => 'meta';
15 use constant DEBUG => Data::Visitor::DEBUG();
16 use constant FIVE_EIGHT => ( $] >= 5.008 );
18 extends qw(Data::Visitor);
23 default => sub { {} },
26 has class_callbacks => (
29 default => sub { [] },
32 has ignore_return_values => (
38 my ( $class, @args ) = @_;
40 my $args = $class->SUPER::BUILDARGS(@args);
42 my %init_args = map { $_->init_arg => undef } $class->meta->get_all_attributes;
44 my %callbacks = map { $_ => $args->{$_} } grep { not exists $init_args{$_} } keys %$args;
46 my @class_callbacks = do {
49 # this check can be half assed because an ->isa check will be
50 # performed later. Anything that cold plausibly be a class name
51 # should be included in the list, even if the class doesn't
54 m{ :: | ^[A-Z] }x # if it looks kinda lack a class name
56 scalar keys %{"${_}::"} # or it really is a class
60 # sort from least derived to most derived
61 @class_callbacks = sort { !$a->isa($b) <=> !$b->isa($a) } @class_callbacks;
65 callbacks => \%callbacks,
66 class_callbacks => \@class_callbacks,
73 my $replaced_hash = local $self->{_replaced} = ($self->{_replaced} || {}); # delete it after we're done with the whole visit
78 my $refaddr = ref($data) && refaddr($data); # we need this early, it may change by the time we write replaced hash
80 local *_ = \$data; # alias $_
82 if ( $refaddr and exists $replaced_hash->{ $refaddr } ) {
84 $self->trace( mapping => replace => $data, with => $replaced_hash->{$refaddr} ) if DEBUG;
85 push @ret, $data = $replaced_hash->{$refaddr};
88 carp(q{Assignment of replacement value for already seen reference } . overload::StrVal($data) . q{ to container doesn't work on Perls older than 5.8, structure shape may have lost integrity.});
94 if ( defined wantarray ) {
95 $ret = $self->SUPER::visit( $self->callback( visit => $data ) );
97 $self->SUPER::visit( $self->callback( visit => $data ) );
100 $replaced_hash->{$refaddr} = $_ if $refaddr and ( not ref $_ or $refaddr ne refaddr($_) );
102 push @ret, $ret if defined wantarray;
105 return ( @_ == 1 ? $ret[0] : @ret );
109 my ( $self, $data ) = @_;
111 my $mapped = $self->callback( ref => $data );
114 return $self->SUPER::visit_ref($mapped);
116 return $self->visit($mapped);
121 my ( $self, $data, $result ) = @_;
123 my $mapped = $self->callback( seen => $data, $result );
125 no warnings 'uninitialized';
126 if ( refaddr($mapped) == refaddr($data) ) {
134 my ( $self, $data ) = @_;
136 $data = $self->callback_and_reg( value => $data );
137 $self->callback_and_reg( ( ref($data) ? "ref_value" : "plain_value" ) => $data );
141 my ( $self, $data ) = @_;
143 $self->trace( flow => visit_object => $data ) if DEBUG;
145 $data = $self->callback_and_reg( object => $data );
149 foreach my $class ( @{ $self->class_callbacks } ) {
150 last unless blessed($data);
151 next unless $data->isa($class);
152 $self->trace( flow => class_callback => $class, on => $data ) if DEBUG;
155 $data = $self->callback_and_reg( $class => $data );
158 $data = $self->callback_and_reg( object_no_class => $data ) unless $class_cb;
160 $data = $self->callback_and_reg( object_final => $data )
167 my ( $self, $data ) = @_;
168 my $new_data = $self->callback_and_reg( scalar => $data );
169 if ( (reftype($new_data)||"") =~ /^(?: SCALAR | REF | LVALUE | VSTRING ) $/x ) {
170 my $visited = $self->SUPER::visit_scalar( $new_data );
172 no warnings "uninitialized";
173 if ( refaddr($visited) != refaddr($data) ) {
174 return $self->_register_mapping( $data, $visited );
179 return $self->_register_mapping( $data, $self->visit( $new_data ) );
183 sub subname { $_[1] }
188 no warnings 'redefine';
189 *subname = \&Sub::Name::subname;
192 foreach my $reftype ( qw/array hash glob code/ ) {
193 my $name = "visit_$reftype";
195 *$name = subname(__PACKAGE__ . "::$name", eval '
197 my ( $self, $data ) = @_;
198 my $new_data = $self->callback_and_reg( '.$reftype.' => $data );
199 if ( "'.uc($reftype).'" eq (reftype($new_data)||"") ) {
200 my $visited = $self->SUPER::visit_'.$reftype.'( $new_data );
202 no warnings "uninitialized";
203 if ( refaddr($visited) != refaddr($data) ) {
204 return $self->_register_mapping( $data, $visited );
209 return $self->_register_mapping( $data, $self->visit( $new_data ) );
216 sub visit_hash_entry {
217 my ( $self, $key, $value, $hash ) = @_;
219 my ( $new_key, $new_value ) = $self->callback( hash_entry => $_[1], $_[2], $_[3] );
221 unless ( $self->ignore_return_values ) {
222 no warnings 'uninitialized';
223 if ( ref($value) and refaddr($value) != refaddr($new_value) ) {
224 $self->_register_mapping( $value, $new_value );
225 if ( $key ne $new_key ) {
226 return $self->SUPER::visit_hash_entry($new_key, $new_value, $_[3]);
228 return $self->SUPER::visit_hash_entry($_[1], $new_value, $_[3]);
231 if ( $key ne $new_key ) {
232 return $self->SUPER::visit_hash_entry($new_key, $_[2], $_[3]);
234 return $self->SUPER::visit_hash_entry($_[1], $_[2], $_[3]);
238 return $self->SUPER::visit_hash_entry($_[1], $_[2], $_[3]);
243 my ( $self, $name, $data, @args ) = @_;
245 if ( my $code = $self->callbacks->{$name} ) {
246 $self->trace( flow => callback => $name, on => $data ) if DEBUG;
248 my @ret = $self->$code( $data, @args );
249 return $self->ignore_return_values ? ( $data, @args ) : @ret;
251 my $ret = $self->$code( $data, @args );
252 return $self->ignore_return_values ? $data : $ret ;
255 return wantarray ? ( $data, @args ) : $data;
259 sub callback_and_reg {
260 my ( $self, $name, $data, @args ) = @_;
262 my $new_data = $self->callback( $name, $data, @args );
264 unless ( $self->ignore_return_values ) {
265 no warnings 'uninitialized';
267 if ( refaddr($data) != refaddr($new_data) ) {
268 return $self->_register_mapping( $data, $new_data );
279 my ( $self, $tied, @args ) = @_;
280 $self->SUPER::visit_tied( $self->callback_and_reg( tied => $tied, @args ), @args );
283 __PACKAGE__->meta->make_immutable if __PACKAGE__->meta->can("make_immutable");
293 Data::Visitor::Callback - A Data::Visitor with callbacks.
297 use Data::Visitor::Callback;
299 my $v = Data::Visitor::Callback->new(
300 value => sub { ... },
301 array => sub { ... },
302 object => "visit_ref", # can also use method names
305 $v->visit( $some_perl_value );
309 This is a L<Data::Visitor> subclass that lets you invoke callbacks instead of
310 needing to subclass yourself.
316 =item new %opts, %callbacks
318 Construct a new visitor.
320 The options supported are:
324 =item ignore_return_values
326 When this is true (off by default) the return values from the callbacks are
327 ignored, thus disabling the fmapping behavior as documented in
330 This is useful when you want to modify $_ directly
332 =item tied_as_objects
334 Whether ot not to visit the L<perlfunc/tied> of a tied structure instead of
335 pretending the structure is just a normal one.
337 See L<Data::Visitor/visit_tied>.
345 Use these keys for the corresponding callbacks.
347 The callback is in the form:
350 my ( $visitor, $data ) = @_;
352 # or you can use $_, it's aliased
354 return $data; # or modified data
357 Within the callback $_ is aliased to the data, and this is also passed in the
360 Any method can also be used as a callback:
362 object => "visit_ref", # visit objects anyway
368 Called for all values
372 Called for non objects, non container (hash, array, glob or scalar ref) values.
376 Called after C<value>, for references to regexes, globs and code.
380 Called after C<value> for non references.
384 Called for blessed objects.
386 Since L<Data::Visitor/visit_object> will not recurse downwards unless you
387 delegate to C<visit_ref>, you can specify C<visit_ref> as the callback for
388 C<object> in order to enter objects.
390 It is reccomended that you specify the classes (or base classes) you want
391 though, instead of just visiting any object forcefully.
395 You can use any class name as a callback. This is colled only after the
398 If the object C<isa> the class then the callback will fire.
400 These callbacks are called from least derived to most derived by comparing the
401 classes' C<isa> at construction time.
403 =item object_no_class
405 Called for every object that did not have a class callback.
409 The last callback called for objects, useful if you want to post process the
410 output of any class callbacks.
414 Called for array references.
418 Called for hash references.
422 Called for glob references.
426 Called for scalar references.
430 Called on the return value of C<tied> for all tied containers. Also passes in
431 the variable as the second argument.
435 Called for a reference value encountered a second time.
437 Passes in the result mapping as the second argument.
443 Yuval Kogman <nothingmuch@woobling.org>
445 =head1 COPYRIGHT & LICENSE
447 Copyright (c) 2006 Yuval Kogman. All rights reserved
448 This program is free software; you can redistribute
449 it and/or modify it under the same terms as Perl itself.