Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical

File::Find incompatible with OO perl?

by vaevictus (Pilgrim)
on Feb 09, 2004 at 16:44 UTC ( #327659=perlquestion: print w/replies, xml ) Need Help??

vaevictus has asked for the wisdom of the Perl Monks concerning the following question:

Okay ... incompatible might be a bit of an exaggeration, but it doesn't play nice. :)

What I want to simply do, is use an object method as the "wanted" function for File::Find. What I get is no access to the File::Find namespace vars, and the $_ is somehow borked with the object reference taking its place.

find($obj->found,$directory); ### in the object package: sub found { my $self=shift; my ($full_name, $file_dir, $file_name) = @_; print "--------------------------\n"; print $self."\n"; print $full_name."\n"; print $file_dir."\n"; print $file_name."\n"; print $File::Find::name."\n"; print $File::Find::dir."\n"; print "--------------------------\n"; }

This produces undefined values for all but $self which is setup properly.

I'm hoping TMTOWTDI, but the only way i've been able to use my object function was to write a separate non-OO wrapper.

sub wanted { my @file_info; push @file_info, $File::Find::name; push @file_info, $File::Find::dir; push @file_info, $_; $borg->found(@file_info); }
So... am I doing something wrong, or is there a better way of doing it? Or is File::Find just not OO friendly?

Replies are listed 'Best First'.
Re: File::Find incompatible with OO perl?
by broquaint (Abbot) on Feb 09, 2004 at 16:50 UTC
    Since find expects a subroutine reference your first example won't work as it'll only get the return of the call to $obj->found. The idiomatic way of passing a method to something that expects a subroutine is to pass an anonymous wrapper function e.g
    find(sub { $obj->found }, $directory);
    Or if you want the anonymous sub call to disappear from the calling stack
    find(sub { unshift @_,$obj; goto &{$obj->can('found')} }, $directory);
    However, if you're planning to go the OO route then File::Find::Rule and File::Finder would be betters suited than File::Find.


      Or if you want the anonymous sub call to disappear from the calling stack

      Ooh, that is just so deliciously evil I must find a justification to use it...


        First they ignore you, then they laugh at you, then they fight you, then you win.
        -- Gandhi

      Just curious, but why would I "want the anonymous sub call to disappear from the calling stack"?
        In case you croak (or something else that produces a stacktrace) within the the found method e.g
        use Carp 'croak'; sub exec_anon { &{$_[0]} } sub boom { eval { croak "$_[0]\->boom" }; print "trace: $@" } exec_anon sub { main->boom }; exec_anon sub { unshift @_, 'main'; goto &{main->can("boom")} }; __output__ trace: main->boom at - line 4 eval {...} called at - line 4 main::boom('main') called at - line 6 main::__ANON__ called at - line 3 main::exec_anon('CODE(0x8107e64)') called at - line 6 trace: main->boom at - line 4 eval {...} called at - line 4 main::boom called at - line 3 main::exec_anon('main', 'CODE(0x8117378)') called at - line 7
        Not terrifically important, or necessarily desired, but it can be much easier to follow things if wrapper functions are hidden away and it's safer if you're dealing with code that looks up the stack (for whatever reason). Use with caution™.


Re: File::Find incompatible with OO perl?
by ysth (Canon) on Feb 09, 2004 at 16:48 UTC
    Just wrap your method call in a sub:
    find(sub {$obj->found}, $directory);
      This is almost good equivalent to my wanted subroutine. However, I'm still losing the contents of $_; I guess i just have to use  find(sub{$obj->found($_)},$directory); Thanks!
        Are you sure you mean $_ and not (after first shift) $_[0]? wanted doesn't get any parameters, so what you have above is only correct if your found() expects the filename via a parameter, not $_.

        This works for me:

        $ perl -MFile::Find -we'$obj=bless []; sub found { print "looking at $ +_\n" } > find(sub {$obj->found}, "pbed/fooble")' looking at . looking at a looking at b looking at c
Re: File::Find incompatible with OO perl?
by graff (Chancellor) on Feb 10, 2004 at 06:04 UTC
    I'm hoping TMTOWTDI ... is File::Find just not OO friendly?

    I seem to be getting repetitive on this point (can't help myself)... Yes, TMTOWTDI, and File::Find is, in a number of respects, somewhat unfriendly, period.

    If you like the "pure-Perl-ness" of File::Find, and you don't mind the wierd usage or the 5x typical slowdown in execution time, then go for it -- it's good to see the other replies showing that it can co-exist with OO methods.

    But have you ever used the unix "find" utility? Isn't it just easier? (It certainly runs faster.) If you know what you're looking for, and you have a starting path to look in, then you could do this:

    open( FIND, "find $dir -print0 |" ) or die "can't run find: $!"; # put any other find options you need between $dir and "-print0" { local $/ = "\0" # use null byte as input record separator while (<FIND>) { chomp; my $name = my $dir = $_; if ( s{(.+)/}{} ) { $dir = $1; else { $dir = "/"; # emulate File::Find's behavior $_ = "." if ( $name eq $dir ); } $borg->( $name, $dir, $_ ); } } close FIND;
    And if you're on an ms-windows box, of course, "find" has been ported to that OS (cf. Cygwin, GNU, among others). Note that the "standard" solaris version of find does not support "-print0"; you need GNU or FreeBSD find for that.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://327659]
Approved by bart
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (2)
As of 2022-05-17 23:24 GMT
Find Nodes?
    Voting Booth?
    Do you prefer to work remotely?

    Results (68 votes). Check out past polls.