| File-Fu documentation | Contained in the File-Fu distribution. |
File::Fu::File - a filename object
use File::Fu;
my $file = File::Fu->file("path/to/file");
$file %= '.extension';
$file->e and warn "$file exists";
$file->l and warn "$file is a link to ", $file->readlink;
my $file = File::Fu::File->new($path); my $file = File::Fu::File->new(@path);
my $file = File::Fu::File->new_direct(
dir => $dir_obj,
file => $name
);
Return the corresponding dir class for this file object.
my $dc = $class->dir_class;
Always false for a file.
Always true for a file.
Returns a new object representing only the file part of the name.
my $obj = $file->basename;
my $string = $file->stringify;
Append a string only to the filename part.
$file->append('.gz');
$file %= '.gz';
(Yeah... I tried to use .=, but overloading hates me.)
$file->map(sub {...});
$file &= sub {...};
Get an absolute name (without checking the filesystem.)
my $abs = $file->absolute;
Get an absolute name (resolved on the filesytem.)
my $abs = $file->absolutely;
Open the file with $mode ('<', 'r', '>', 'w', etc) -- see IO::File.
my $fh = $file->open($mode, $permissions);
Throws an error if anything goes wrong or if the resulting filehandle happens to be a directory.
Opens a read pipe. The file is appended to @command.
my $fh = $file->piped_open(@command);
Update the timestamp of a file (or create it.)
$file->touch;
my $link = $file->link($name);
my $link = $file->symlink($linkname);
Note that symlinks are relative to where they live.
my $dir = File::Fu->dir("foo");
my $file = $dir+'file';
# $file->symlink($dir+'link'); is a broken link
my $link = $file->basename->symlink($dir+'link');
$file->unlink;
my $to = $file->readlink;
Read the entire file into memory (or swap!)
my @lines = $file->read; my $file = $file->read;
If File::Slurp is available, options to read_file will be passed along. See read_file in File::Slurp.
Write the file's contents.
$file->write($content);
If File::Slurp is available, $content may be either a scalar, scalar ref, or array ref.
$file->write($content, %args);
$file->copy($dest);
Eric Wilhelm @ <ewilhelm at cpan dot org>
http://scratchcomputing.com/
If you found this module on CPAN, please report any bugs or feature requests through the web interface at http://rt.cpan.org. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
If you pulled this development version from my /svn/, please contact me directly.
Copyright (C) 2008 Eric L. Wilhelm, All Rights Reserved.
Absolutely, positively NO WARRANTY, neither express or implied, is offered with this software. You use this software at your own risk. In case of loss, no person or entity owes you anything whatsoever. You have been warned.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| File-Fu documentation | Contained in the File-Fu distribution. |
package File::Fu::File; $VERSION = v0.0.7; use warnings; use strict; use Carp; use IO::File ();
use base 'File::Fu::Base'; use Class::Accessor::Classy; lv 'file'; ro 'dir'; aka dir => 'dirname', 'parent'; no Class::Accessor::Classy; #use overload ();
sub new { my $package = shift; my $class = ref($package) || $package; my $self = {$class->_init(@_)}; bless($self, $class); return($self); } # end subroutine new definition ########################################################################
sub new_direct { my $package = shift; my $class = ref($package) || $package; my $self = {@_}; bless($self, $class); return($self); } # end subroutine new_direct definition ########################################################################
use constant dir_class => 'File::Fu::Dir'; use constant is_dir => 0; use constant is_file => 1; ########################################################################
sub _init { my $class = shift; my @dirs = @_ or croak("file must have a name"); my $file = pop(@dirs); if($file =~ m#/#) { croak("strange mix: ", join(',', @_, $file)) if(@dirs); my %p = $class->dir_class->_init($file); @dirs = @{$p{dirs}}; $file = pop(@dirs); } return(dir => $class->dir_class->new(@dirs), file => $file); } # end subroutine _init definition ########################################################################
sub basename { my $self = shift; $self->new($self->file); } # end subroutine basename definition ########################################################################
sub stringify { my $self = shift; my $dir = $self->dir; #warn "stringify(..., $_[1], $_[2])"; #Carp::carp("stringify ", overload::StrVal($self), " ($self->{file})"); $dir = $dir->is_cwd ? '' : $dir->stringify; return($dir . $self->file); } # end subroutine stringify definition ########################################################################
sub append { my $self = shift; my ($tail) = @_; $self->file .= $tail; $self; } # end subroutine append definition ########################################################################
sub map :method { my $self = shift; my ($sub) = shift; local $_ = $self->file; $sub->(); $self->file = $_; $self; } # end subroutine map definition ########################################################################
sub absolute { my ($self) = shift; return($self->dir->absolute->file($self->file)); } # end subroutine absolutely definition ########################################################################
sub absolutely { my $self = shift; return($self->dir->absolutely->file($self->file)); } # end subroutine absolutely definition ########################################################################
# TODO should probably have our own filehandle so we can close in the # destructor and croak there too? sub open :method { my $self = shift; my $fh = IO::File->new($self, @_) or croak("cannot open '$self' $!"); -d $fh and croak("$self is a directory"); return($fh); } # end subroutine open definition ########################################################################
sub piped_open { my $self = shift; my (@command) = @_; # TODO some way to decide where self goes in @command push(@command, $self); # TODO closing STDIN and such before the fork? # TODO here is where we need our own filehandle object again my $pid = open(my $fh, '-|', @command) or croak("cannot exec '@command' $!"); return($fh); } # end subroutine piped_open definition ########################################################################
sub touch { my $self = shift; if(-e $self) { $self->utime(time); } else { $self->open('>'); } return($self); } # end subroutine touch definition ########################################################################
sub link :method { my $self = shift; my ($name) = @_; link($self, $name) or croak("link '$self' to '$name' failed $!"); return($self->new($name)); } # end subroutine link definition ########################################################################
sub symlink :method { my $self = shift; my ($name) = @_; symlink($self, $name) or croak("symlink '$self' to '$name' failed $!"); return($self->new($name)); } # end subroutine symlink definition ######################################################################## # TODO # my $link = $file->dwimlink(absolute|relative|samedir => $linkname);
sub unlink :method { my $self = shift; unlink("$self") or croak("unlink '$self' failed $!"); } # end subroutine unlink definition ########################################################################
sub readlink :method { my $self = shift; my $name = readlink($self); defined($name) or croak("cannot readlink '$self' $!"); return($self->new($name)); } # end subroutine readlink definition ######################################################################## ######################################################################## { # a closure for this variable my $has_slurp;
sub read :method { my $self = shift; my @args = @_; $has_slurp ||= eval {require File::Slurp; 1} || -1; if($has_slurp > 0) { local $Carp::CarpLevel = 1; return(File::Slurp::read_file("$self", @args, err_mode => 'croak')); } else { croak("must have File::Slurp for fancy reads") if(@args); my $fh = $self->open; local $/ = wantarray ? $/ : undef; return(<$fh>); } } # end subroutine read definition ########################################################################
sub write { my $self = shift; my ($content, @args) = @_; $has_slurp ||= eval {require File::Slurp; 1} || -1; if($has_slurp > 0) { local $Carp::CarpLevel = 1; return(File::Slurp::write_file("$self", {@args, err_mode => 'croak'}, $content )); } else { croak("must have File::Slurp for fancy writes") if(@args or ref($content)); my $fh = $self->open('>'); print $fh $content; close($fh) or croak("write '$self' failed: $!"); } } # end subroutine write definition ######################################################################## } # File::Slurp closure ########################################################################
sub copy { my $self = shift; my ($dest) = shift; my (%opts) = @_; # decide if this is file-to-dir or file-to-file if(-d $dest) { $dest = $self->dir_class->new($dest)->file($self->basename); } else { $dest = $self->new($dest) unless(ref($dest)); } if($dest->e) { croak("'$dest' and '$self' are the same file") if($self->is_same($dest)); } # TODO here's another good reason to have our own filehandle object: # This fh-copy should be in there. my $ifh = $self->open; my $ofh = $dest->open('>'); binmode($_) for($ifh, $ofh); while(1) { my $buf; defined(my $r = sysread($ifh, $buf, 1024)) or croak("sysread failed $!"); $r or last; # why did File::Copy::copy do it like this? for(my $t = my $w = 0; $w < $r; $w += $t) { $t = syswrite($ofh, $buf, $r - $w, $w) or croak("syswrite failed $!"); } } close($ofh) or croak("write '$dest' failed: $!"); # TODO some form of rollback? # TODO handle opts #if($opts{preserve}) { # # TODO chmod/chown and such # $dest->utime($self->stat->mtime); #} } # end subroutine copy definition ########################################################################
require File::Fu; # vi:ts=2:sw=2:et:sta 1;