I've building a script that recursively builds the names of a directory's subdirectories/files and the names of the files in those subdirectories as objects:
package Dir;
use Moose;
use Modern::Perl;
use File;
use strict;
use warnings;
has 'path' => (is => 'ro', isa => 'Str', required => 1);
has 'name' => (is => 'ro', isa => 'Str', lazy => 1, default => sub { my $self = shift; my ($name) = $self->path =~ /\/([^\/]*)$/; return $name; } );
has 'subdirs' => (is => 'rw', isa => 'ArrayRef[Dir]' );
has 'files' => (is => 'rw', isa => 'ArrayRef[File]' );
has 'num_dirs' => (is => 'ro', isa => 'Int', lazy => 1, default => sub { my $self = shift; scalar @{$self->subdirs}; } );
sub BUILD {
my $self = shift;
my $path = $self->path;
# run some tests
logf('Path to the directory does not exist.') if (!-e $path);
logf('The path should point to a directory, not a file.') if (!-d $path);
# populate subdirs attribute with Dir objects
opendir my $dh, $path or die "Can't opendir '$path': $!";
# Get files and dirs and separate them out into categories
my @dirs_and_files = grep { ! m{^\.$|^\.\.$} } readdir $dh;
closedir $dh or die "Can't closedir '$path': $!";
my @subdir_names = grep { -d "$path/$_" } grep { !m{^\.} } @dirs_and_files;
my @file_names = grep { -f "$path/$_" } grep { !m{^\.} } @dirs_and_files;
# Create objects
my @dir_objects = map { Dir->new ( path => $path . '/' . $_ ) } @subdir_names;
my @file_objects = map { File->new ( path => $path . '/' . $_ ) } @file_names;
# Populate this with file and directory objects
$self->subdirs ( \@dir_objects );
$self->files ( \@file_objects );
}
1;
Notice the code has a files
attribute which holds an array of File
objects. A File
has the following attributes:
has 'path' => (is => 'ro', isa => 'Str', required => 1);
has 'name' => (is => 'ro', isa => 'Str', lazy => 1, default => sub { my $self = shift; my ($name) = $self->path =~ /\/([^\/]*)$/; return $name; } );
The problem is that the name
attribute never gets set when a File
object is created. I'm not sure why.
EDIT 1: Solution (sort of)
So, I slapped this into the File
object to see if it triggered the creation of the attribute:
sub BUILD {
my $self = shift;
}
This did not solve the problem. However, this did:
sub BUILD {
my $self = shift;
$self->name;
}
The question I have, though, is why did I need to do this?