Search code examples
perlmoose

How can I use Perl's File::Find inside a Moose Object?


I'm building a Perl application that relies on Moose. One task the Moose object needs to accomplish is to use File::Find to populate an attribute with a list of files. I'm having some trouble figuring out how to use find's \&wanted code reference in a way that will let me maintain access to a $self version of the Moose object.

So far, I have this:

#!/usr/bin/perl

package MyMoose;

use Modern::Perl;
use Moose;
use File::Find;
use FindBin qw($Bin);

### Attribute to hold the file list
has "file_list" => (
    is => 'rw',
    isa => 'ArrayRef',
    default => sub {[]}
);


### Method to populate the file list
sub update_file_list {

    my $self = shift;

    find(\&wanted, $Bin);

}


### File::Find wanted sub
sub wanted {

    ### This won't work, but shows what I'd like to do
    #   my $self = shift;
    #   ### Do some filtering
    #   push @{$self->file_list}, $File::Find::name;

}


1;


######################################################################
### Main package to test the object.

package main;

use Data::Dumper;

run_main() unless caller();

sub run_main {

    my $m = MyMoose->new();

    $m->update_file_list();

    print Dumper $m->file_list;

}

It runs, but obviously doesn't assemble a file list. That's the part I'm trying to figure out.

What's the proper way to use File::Find so that it will let you have access to the Moose object during processing?


Solution

  • The problem is that you don't have access to $self within wanted sub. You can use inline closure and default or builder to build the list.

    Edit: updated code per updated question

    has "file_list" => (
        is => 'rw',
        isa => 'ArrayRef',
        default => sub {
            my $self = shift;
            return $self->_get_file_list();
        },
    );
    
    sub update_file_list {
        my $self = shift;
        $self->file_list($self->_get_file_list());
    }
    
    sub _get_file_list {
        my @files;
        find(sub { push @files, $File::Find::name }, $Bin);
        return \@files;
    }
    

    _get_file_list method returns arrayref of files found. It is used both in default and update_file_list method to populate the attribute.