@@ -1,100 +0,0 @@
-## HOW TO CONTRIBUTE
-
-Thank you for considering contributing to this distribution. This file
-contains instructions that will help you work with the source code.
-
-The distribution is managed with Dist::Zilla. This means than many of the
-usual files you might expect are not in the repository, but are generated at
-release time (e.g. Makefile.PL).
-
-Generally, **you do not need Dist::Zilla to contribute patches**. You do need
-Dist::Zilla to create a tarball and/or install from the repository. See below
-for guidance.
-
-### Getting dependencies
-
-See the included `cpanfile` file for a list of dependencies. If you have
-App::cpanminus 1.6 or later installed, you can use `cpanm` to satisfy
-dependencies like this:
-
- $ cpanm --installdeps .
-
-Otherwise, you can install Module::CPANfile 1.0002 or later and then satisfy
-dependencies with the regular `cpan` client and `cpanfile-dump`:
-
- $ cpan `cpanfile-dump`
-
-### Running tests
-
-You can run tests directly using the `prove` tool:
-
- $ prove -l
- $ prove -lv t/some_test_file.t
-
-For most of my distributions, `prove` is entirely sufficient for you to test any
-patches you have. I use `prove` for 99% of my testing during development.
-
-### Code style and tidying
-
-Please try to match any existing coding style. If there is a `.perltidyrc`
-file, please install Perl::Tidy and use perltidy before submitting patches.
-
-If there is a `tidyall.ini` file, you can also install Code::TidyAll and run
-`tidyall` on a file or `tidyall -a` to tidy all files.
-
-### Patching documentation
-
-Much of the documentation Pod is generated at release time. Depending on the
-distribution, some of my documentation may be written in a Pod dialect called
-WikiDoc. (See Pod::WikiDoc on CPAN.)
-
-If you would like to submit a documentation edit, please limit yourself to the
-documentation you see.
-
-If you see typos or documentation issues in the generated docs, please
-email or open a bug ticket instead of patching.
-
-### Installing from the repository
-
-If you want to install directly from the repository, you need to have
-Dist::Zilla installed (see below). If this is a burden to you, I welcome
-patches against a CPAN tarball instead of the repository.
-
-### Installing and using Dist::Zilla
-
-Dist::Zilla is a very powerful authoring tool, optimized for maintaining a
-large number of distributions with a high degree of automation, but it has a
-large dependency chain, a bit of a learning curve and requires a number of
-author-specific plugins.
-
-To install it from CPAN, I recommend one of the following approaches for
-the quickest installation:
-
- # using CPAN.pm, but bypassing non-functional pod tests
- $ cpan TAP::Harness::Restricted
- $ PERL_MM_USE_DEFAULT=1 HARNESS_CLASS=TAP::Harness::Restricted cpan Dist::Zilla
-
- # using cpanm, bypassing *all* tests
- $ cpanm -n Dist::Zilla
-
-In either case, it's probably going to take about 10 minutes. Go for a walk,
-go get a cup of your favorite beverage, take a bathroom break, or whatever.
-When you get back, Dist::Zilla should be ready for you.
-
-Then you need to install any plugins specific to this distribution:
-
- $ cpan `dzil authordeps`
- $ dzil authordeps | cpanm
-
-Once installed, here are some dzil commands you might try:
-
- $ dzil build
- $ dzil test
- $ dzil xtest
-
-To install from the repository, use:
-
- $ dzil install
-
-You can learn more about Dist::Zilla at http://dzil.org/
-
@@ -0,0 +1,100 @@
+## HOW TO CONTRIBUTE
+
+Thank you for considering contributing to this distribution. This file
+contains instructions that will help you work with the source code.
+
+The distribution is managed with Dist::Zilla. This means than many of the
+usual files you might expect are not in the repository, but are generated at
+release time (e.g. Makefile.PL).
+
+Generally, **you do not need Dist::Zilla to contribute patches**. You do need
+Dist::Zilla to create a tarball and/or install from the repository. See below
+for guidance.
+
+### Getting dependencies
+
+See the included `cpanfile` file for a list of dependencies. If you have
+App::cpanminus 1.6 or later installed, you can use `cpanm` to satisfy
+dependencies like this:
+
+ $ cpanm --installdeps .
+
+Otherwise, you can install Module::CPANfile 1.0002 or later and then satisfy
+dependencies with the regular `cpan` client and `cpanfile-dump`:
+
+ $ cpan `cpanfile-dump`
+
+### Running tests
+
+You can run tests directly using the `prove` tool:
+
+ $ prove -l
+ $ prove -lv t/some_test_file.t
+
+For most of my distributions, `prove` is entirely sufficient for you to test any
+patches you have. I use `prove` for 99% of my testing during development.
+
+### Code style and tidying
+
+Please try to match any existing coding style. If there is a `.perltidyrc`
+file, please install Perl::Tidy and use perltidy before submitting patches.
+
+If there is a `tidyall.ini` file, you can also install Code::TidyAll and run
+`tidyall` on a file or `tidyall -a` to tidy all files.
+
+### Patching documentation
+
+Much of the documentation Pod is generated at release time. Depending on the
+distribution, some of my documentation may be written in a Pod dialect called
+WikiDoc. (See Pod::WikiDoc on CPAN.)
+
+If you would like to submit a documentation edit, please limit yourself to the
+documentation you see.
+
+If you see typos or documentation issues in the generated docs, please
+email or open a bug ticket instead of patching.
+
+### Installing from the repository
+
+If you want to install directly from the repository, you need to have
+Dist::Zilla installed (see below). If this is a burden to you, I welcome
+patches against a CPAN tarball instead of the repository.
+
+### Installing and using Dist::Zilla
+
+Dist::Zilla is a very powerful authoring tool, optimized for maintaining a
+large number of distributions with a high degree of automation, but it has a
+large dependency chain, a bit of a learning curve and requires a number of
+author-specific plugins.
+
+To install it from CPAN, I recommend one of the following approaches for
+the quickest installation:
+
+ # using CPAN.pm, but bypassing non-functional pod tests
+ $ cpan TAP::Harness::Restricted
+ $ PERL_MM_USE_DEFAULT=1 HARNESS_CLASS=TAP::Harness::Restricted cpan Dist::Zilla
+
+ # using cpanm, bypassing *all* tests
+ $ cpanm -n Dist::Zilla
+
+In either case, it's probably going to take about 10 minutes. Go for a walk,
+go get a cup of your favorite beverage, take a bathroom break, or whatever.
+When you get back, Dist::Zilla should be ready for you.
+
+Then you need to install any plugins specific to this distribution:
+
+ $ cpan `dzil authordeps`
+ $ dzil authordeps | cpanm
+
+Once installed, here are some dzil commands you might try:
+
+ $ dzil build
+ $ dzil test
+ $ dzil xtest
+
+To install from the repository, use:
+
+ $ dzil install
+
+You can learn more about Dist::Zilla at http://dzil.org/
+
@@ -1,5 +1,27 @@
Revision history for Path-Tiny
+0.056 2014-08-07 15:08:41-04:00 America/New_York
+
+ [*** DEPRECATIONS ***]
+
+ - The 'dirname' method is deprecated due to exposing File::Spec
+ inconsistencies
+
+ [ADDED]
+
+ - The 'digest' method now takes a 'chunk_size' option to avoid
+ slurping files entirely into memory.
+
+ [FIXED]
+
+ - Fixed problem throwing errors from 'remove'
+
+0.055 2014-06-30 10:29:28-04:00 America/New_York
+
+ [FIXED]
+
+ - tempfile/tempdir won't warn if used as functions without arguments
+
0.054 2014-05-04 13:56:11-04:00 America/New_York
[ADDED]
@@ -1,5 +1,5 @@
-# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.015.
-CONTRIBUTING
+# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.020.
+CONTRIBUTING.mkdn
Changes
LICENSE
MANIFEST
@@ -11,6 +11,7 @@ cpanfile
dist.ini
lib/Path/Tiny.pm
perlcritic.rc
+t/00-report-prereqs.dd
t/00-report-prereqs.t
t/README
t/basename.t
@@ -4,7 +4,7 @@
"David Golden <dagolden@cpan.org>"
],
"dynamic_config" : 0,
- "generated_by" : "Dist::Zilla version 5.015, CPAN::Meta::Converter version 2.141170",
+ "generated_by" : "Dist::Zilla version 5.020, CPAN::Meta::Converter version 2.142060",
"license" : [
"apache_2_0"
],
@@ -33,7 +33,7 @@
},
"develop" : {
"requires" : {
- "Dist::Zilla" : "5.015",
+ "Dist::Zilla" : "5",
"Dist::Zilla::Plugin::MinimumPerl" : "0",
"Dist::Zilla::Plugin::OnlyCorePrereqs" : "0",
"Dist::Zilla::Plugin::Prereqs" : "0",
@@ -47,7 +47,8 @@
"Test::CPAN::Meta" : "0",
"Test::More" : "0",
"Test::Pod" : "1.41",
- "Test::Pod::Coverage" : "1.08"
+ "Test::Pod::Coverage" : "1.08",
+ "Test::Spelling" : "0.12"
}
},
"runtime" : {
@@ -76,32 +77,30 @@
},
"test" : {
"recommends" : {
- "CPAN::Meta" : "0",
- "CPAN::Meta::Requirements" : "2.120900",
+ "CPAN::Meta" : "2.120900",
"Test::FailWarnings" : "0"
},
"requires" : {
"ExtUtils::MakeMaker" : "0",
"File::Basename" : "0",
+ "File::Spec" : "3.40",
"File::Spec::Functions" : "0",
"File::Spec::Unix" : "0",
"File::Temp" : "0.19",
- "List::Util" : "0",
"Test::More" : "0.96",
"lib" : "0",
- "open" : "0",
- "version" : "0"
+ "open" : "0"
}
}
},
"provides" : {
"Path::Tiny" : {
"file" : "lib/Path/Tiny.pm",
- "version" : "0.054"
+ "version" : "0.056"
},
"Path::Tiny::Error" : {
"file" : "lib/Path/Tiny.pm",
- "version" : "0.054"
+ "version" : "0.056"
}
},
"release_status" : "stable",
@@ -116,11 +115,12 @@
"web" : "https://github.com/dagolden/Path-Tiny"
}
},
- "version" : "0.054",
+ "version" : "0.056",
"x_authority" : "cpan:DAGOLDEN",
"x_contributors" : [
"Chris Williams <bingos@cpan.org>",
"David Steinbrunner <dsteinbrunner@pobox.com>",
+ "Doug Bell <madcityzen@gmail.com>",
"Gabor Szabo <szabgab@cpan.org>",
"Gabriel Andrade <gabiruh@gmail.com>",
"George Hartzell <hartzell@cpan.org>",
@@ -129,6 +129,7 @@
"Karen Etheridge <ether@cpan.org>",
"Martin Kjeldsen <mk@bluepipe.dk>",
"Michael G. Schwern <mschwern@cpan.org>",
+ "Smylers <Smylers@stripey.com>",
"Toby Inkster <tobyink@cpan.org>",
"김도형 - Keedi Kim <keedi@cpan.org>"
]
@@ -5,18 +5,17 @@ author:
build_requires:
ExtUtils::MakeMaker: '0'
File::Basename: '0'
+ File::Spec: '3.40'
File::Spec::Functions: '0'
File::Spec::Unix: '0'
File::Temp: '0.19'
- List::Util: '0'
Test::More: '0.96'
lib: '0'
open: '0'
- version: '0'
configure_requires:
ExtUtils::MakeMaker: '6.17'
dynamic_config: 0
-generated_by: 'Dist::Zilla version 5.015, CPAN::Meta::Converter version 2.141170'
+generated_by: 'Dist::Zilla version 5.020, CPAN::Meta::Converter version 2.142060'
license: apache
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -34,10 +33,10 @@ no_index:
provides:
Path::Tiny:
file: lib/Path/Tiny.pm
- version: '0.054'
+ version: '0.056'
Path::Tiny::Error:
file: lib/Path/Tiny.pm
- version: '0.054'
+ version: '0.056'
recommends:
Unicode::UTF8: '0.58'
requires:
@@ -62,11 +61,12 @@ resources:
bugtracker: https://github.com/dagolden/Path-Tiny/issues
homepage: https://github.com/dagolden/Path-Tiny
repository: https://github.com/dagolden/Path-Tiny.git
-version: '0.054'
+version: '0.056'
x_authority: cpan:DAGOLDEN
x_contributors:
- 'Chris Williams <bingos@cpan.org>'
- 'David Steinbrunner <dsteinbrunner@pobox.com>'
+ - 'Doug Bell <madcityzen@gmail.com>'
- 'Gabor Szabo <szabgab@cpan.org>'
- 'Gabriel Andrade <gabiruh@gmail.com>'
- 'George Hartzell <hartzell@cpan.org>'
@@ -75,5 +75,6 @@ x_contributors:
- 'Karen Etheridge <ether@cpan.org>'
- 'Martin Kjeldsen <mk@bluepipe.dk>'
- 'Michael G. Schwern <mschwern@cpan.org>'
+ - 'Smylers <Smylers@stripey.com>'
- 'Toby Inkster <tobyink@cpan.org>'
- '김도형 - Keedi Kim <keedi@cpan.org>'
@@ -1,5 +1,5 @@
-# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.015.
+# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.020.
use strict;
use warnings;
@@ -12,7 +12,6 @@ use ExtUtils::MakeMaker 6.17;
my %WriteMakefileArgs = (
"ABSTRACT" => "File path utility",
"AUTHOR" => "David Golden <dagolden\@cpan.org>",
- "BUILD_REQUIRES" => {},
"CONFIGURE_REQUIRES" => {
"ExtUtils::MakeMaker" => "6.17"
},
@@ -41,16 +40,15 @@ my %WriteMakefileArgs = (
"TEST_REQUIRES" => {
"ExtUtils::MakeMaker" => 0,
"File::Basename" => 0,
+ "File::Spec" => "3.40",
"File::Spec::Functions" => 0,
"File::Spec::Unix" => 0,
"File::Temp" => "0.19",
- "List::Util" => 0,
"Test::More" => "0.96",
"lib" => 0,
- "open" => 0,
- "version" => 0
+ "open" => 0
},
- "VERSION" => "0.054",
+ "VERSION" => "0.056",
"test" => {
"TESTS" => "t/*.t"
}
@@ -73,7 +71,6 @@ my %FallbackPrereqs = (
"File::Spec::Unix" => 0,
"File::Temp" => "0.19",
"File::stat" => 0,
- "List::Util" => 0,
"Test::More" => "0.96",
"constant" => 0,
"if" => 0,
@@ -81,7 +78,6 @@ my %FallbackPrereqs = (
"open" => 0,
"overload" => 0,
"strict" => 0,
- "version" => 0,
"warnings" => 0
);
@@ -2,7 +2,7 @@ NAME
Path::Tiny - File path utility
VERSION
- version 0.054
+ version 0.056
SYNOPSIS
use Path::Tiny;
@@ -263,18 +263,28 @@ METHODS
digest
$obj = path("/tmp/foo.txt")->digest; # SHA-256
$obj = path("/tmp/foo.txt")->digest("MD5"); # user-selected
+ $obj = path("/tmp/foo.txt")->digest( { chunk_size => 1e6 }, "MD5" );
- Returns a hexadecimal digest for a file. Any arguments are passed to the
- constructor for Digest to select an algorithm. If no arguments are
- given, the default is SHA-256.
+ Returns a hexadecimal digest for a file. An optional hash reference of
+ options may be given. The only option is "chunk_size". If "chunk_size"
+ is given, that many bytes will be read at a time. If not provided, the
+ entire file will be slurped into memory to compute the digest.
- dirname
+ Any subsequent arguments are passed to the constructor for Digest to
+ select an algorithm. If no arguments are given, the default is SHA-256.
+
+ dirname (deprecated)
$name = path("/tmp/foo.txt")->dirname; # "/tmp/"
- Returns the directory name portion of the path. This is roughly
- equivalent to what File::Spec would give from "splitpath" and thus
- usually has the trailing slash. If that's not desired, stringify
- directories or call "parent" on files.
+ Returns the directory portion you would get from calling
+ "File::Spec->splitpath( $path->stringify )" or "." for a path without a
+ parent directory portion. Because File::Spec is inconsistent, the result
+ might or might not have a trailing slash. Because of this, this method
+ is deprecated.
+
+ A better, more consistently approach is likely
+ "$path->parent->stringify", which will not have a trailing slash except
+ for a root directory.
exists, is_file, is_dir
if ( path("/tmp")->exists ) { ... } # -e
@@ -465,8 +475,9 @@ METHODS
Note: as of 0.012, remove only works on files.
- This is just like "unlink", except if the path does not exist, it
- returns false rather than throwing an exception.
+ This is just like "unlink", except for its error handling: if the path
+ does not exist, it returns false; if deleting the file fails, it throws
+ an exception.
remove_tree
# directory
@@ -708,6 +719,8 @@ CONTRIBUTORS
* David Steinbrunner <dsteinbrunner@pobox.com>
+ * Doug Bell <madcityzen@gmail.com>
+
* Gabor Szabo <szabgab@cpan.org>
* Gabriel Andrade <gabiruh@gmail.com>
@@ -724,6 +737,8 @@ CONTRIBUTORS
* Michael G. Schwern <mschwern@cpan.org>
+ * Smylers <Smylers@stripey.com>
+
* Toby Inkster <tobyink@cpan.org>
* 김도형 - Keedi Kim <keedi@cpan.org>
@@ -20,19 +20,17 @@ recommends "Unicode::UTF8" => "0.58";
on 'test' => sub {
requires "ExtUtils::MakeMaker" => "0";
requires "File::Basename" => "0";
+ requires "File::Spec" => "3.40";
requires "File::Spec::Functions" => "0";
requires "File::Spec::Unix" => "0";
requires "File::Temp" => "0.19";
- requires "List::Util" => "0";
requires "Test::More" => "0.96";
requires "lib" => "0";
requires "open" => "0";
- requires "version" => "0";
};
on 'test' => sub {
- recommends "CPAN::Meta" => "0";
- recommends "CPAN::Meta::Requirements" => "2.120900";
+ recommends "CPAN::Meta" => "2.120900";
recommends "Test::FailWarnings" => "0";
};
@@ -41,7 +39,7 @@ on 'configure' => sub {
};
on 'develop' => sub {
- requires "Dist::Zilla" => "5.015";
+ requires "Dist::Zilla" => "5";
requires "Dist::Zilla::Plugin::MinimumPerl" => "0";
requires "Dist::Zilla::Plugin::OnlyCorePrereqs" => "0";
requires "Dist::Zilla::Plugin::Prereqs" => "0";
@@ -56,4 +54,5 @@ on 'develop' => sub {
requires "Test::More" => "0";
requires "Test::Pod" => "1.41";
requires "Test::Pod::Coverage" => "1.08";
+ requires "Test::Spelling" => "0.12";
};
@@ -4,7 +4,7 @@ use warnings;
package Path::Tiny;
# ABSTRACT: File path utility
-our $VERSION = '0.054'; # VERSION
+our $VERSION = '0.056'; # VERSION
# Dependencies
use Config;
@@ -203,7 +203,7 @@ sub path {
return $path;
}
- # stringify initial path
+ # stringify objects
$path = "$path";
# expand relative volume paths on windows; put trailing slash on UNC root
@@ -212,18 +212,17 @@ sub path {
$path .= "/" if $path =~ m{^$UNC_VOL$};
}
- # concatenate more arguments (stringifies any objects, too)
+ # concatenations stringifies objects, too
if (@_) {
$path .= ( _is_root($path) ? "" : "/" ) . join( "/", @_ );
}
- # canonicalize paths
- my $cpath = $path = File::Spec->canonpath($path); # ugh, but probably worth it
- $path =~ tr[\\][/] if IS_WIN32(); # unix convention enforced
- $path .= "/" if IS_WIN32() && $path =~ m{^$UNC_VOL$}; # canonpath strips it
+ # canonicalize, but with unix slashes and put back trailing volume slash
+ my $cpath = $path = File::Spec->canonpath($path);
+ $path =~ tr[\\][/] if IS_WIN32();
+ $path .= "/" if IS_WIN32() && $path =~ m{^$UNC_VOL$};
- # hack to make splitpath give us a basename; root paths must always have
- # a trailing slash, but other paths must not
+ # root paths must always have a trailing slash, but other paths must not
if ( _is_root($path) ) {
$path =~ s{/?$}{/};
}
@@ -237,7 +236,6 @@ sub path {
$path =~ s{^(~[^/]*)}{$homedir};
}
- # and we're finally done
bless [ $path, $cpath ], __PACKAGE__;
}
@@ -318,7 +316,7 @@ sub rootdir { path( File::Spec->rootdir ) }
#pod =cut
sub tempfile {
- shift if $_[0] eq 'Path::Tiny'; # called as method
+ shift if @_ && $_[0] eq 'Path::Tiny'; # called as method
my ( $maybe_template, $args ) = _parse_file_temp_args(@_);
# File::Temp->new demands TEMPLATE
$args->{TEMPLATE} = $maybe_template->[0] if @$maybe_template;
@@ -327,19 +325,19 @@ sub tempfile {
my $temp = File::Temp->new( TMPDIR => 1, %$args );
close $temp;
my $self = path($temp)->absolute;
- $self->[TEMP] = $temp; # keep object alive while we are
+ $self->[TEMP] = $temp; # keep object alive while we are
return $self;
}
sub tempdir {
- shift if $_[0] eq 'Path::Tiny'; # called as method
+ shift if @_ && $_[0] eq 'Path::Tiny'; # called as method
my ( $maybe_template, $args ) = _parse_file_temp_args(@_);
# File::Temp->newdir demands leading template
require File::Temp;
my $temp = File::Temp->newdir( @$maybe_template, TMPDIR => 1, %$args );
my $self = path($temp)->absolute;
- $self->[TEMP] = $temp; # keep object alive while we are
+ $self->[TEMP] = $temp; # keep object alive while we are
return $self;
}
@@ -606,28 +604,48 @@ sub copy {
#pod
#pod $obj = path("/tmp/foo.txt")->digest; # SHA-256
#pod $obj = path("/tmp/foo.txt")->digest("MD5"); # user-selected
+#pod $obj = path("/tmp/foo.txt")->digest( { chunk_size => 1e6 }, "MD5" );
#pod
-#pod Returns a hexadecimal digest for a file. Any arguments are passed to the
-#pod constructor for L<Digest> to select an algorithm. If no arguments are given,
-#pod the default is SHA-256.
+#pod Returns a hexadecimal digest for a file. An optional hash reference of options may
+#pod be given. The only option is C<chunk_size>. If C<chunk_size> is given, that many
+#pod bytes will be read at a time. If not provided, the entire file will be slurped
+#pod into memory to compute the digest.
+#pod
+#pod Any subsequent arguments are passed to the constructor for L<Digest> to select
+#pod an algorithm. If no arguments are given, the default is SHA-256.
#pod
#pod =cut
sub digest {
- my ( $self, $alg, @args ) = @_;
- $alg = 'SHA-256' unless defined $alg;
+ my ( $self, @opts ) = @_;
+ my $args = ( @opts && ref $opts[0] eq 'HASH' ) ? shift @opts : {};
+ $args = _get_args( $args, qw/chunk_size/ );
+ unshift @opts, 'SHA-256' unless @opts;
require Digest;
- return Digest->new( $alg, @args )->add( $self->slurp_raw )->hexdigest;
+ my $digest = Digest->new(@opts);
+ if ( $args->{chunk_size} ) {
+ my $fh = $self->filehandle( { locked => 1 }, "<", ":unix" );
+ my $buf;
+ $digest->add($buf) while read $fh, $buf, $args->{chunk_size};
+ }
+ else {
+ $digest->add( $self->slurp_raw );
+ }
+ return $digest->hexdigest;
}
-#pod =method dirname
+#pod =method dirname (deprecated)
#pod
#pod $name = path("/tmp/foo.txt")->dirname; # "/tmp/"
#pod
-#pod Returns the directory name portion of the path. This is roughly
-#pod equivalent to what L<File::Spec> would give from C<splitpath> and thus
-#pod usually has the trailing slash. If that's not desired, stringify directories
-#pod or call C<parent> on files.
+#pod Returns the directory portion you would get from calling
+#pod C<< File::Spec->splitpath( $path->stringify ) >> or C<"."> for a path without a
+#pod parent directory portion. Because L<File::Spec> is inconsistent, the result
+#pod might or might not have a trailing slash. Because of this, this method is
+#pod B<deprecated>.
+#pod
+#pod A better, more consistently approach is likely C<< $path->parent->stringify >>,
+#pod which will not have a trailing slash except for a root directory.
#pod
#pod =cut
@@ -1151,8 +1169,9 @@ sub relative { path( File::Spec->abs2rel( $_[0]->[PATH], $_[1] ) ) }
#pod
#pod B<Note: as of 0.012, remove only works on files>.
#pod
-#pod This is just like C<unlink>, except if the path does not exist, it returns
-#pod false rather than throwing an exception.
+#pod This is just like C<unlink>, except for its error handling: if the path does
+#pod not exist, it returns false; if deleting the file fails, it throws an
+#pod exception.
#pod
#pod =cut
@@ -1161,7 +1180,7 @@ sub remove {
return 0 if !-e $self->[PATH] && !-l $self->[PATH];
- return unlink $self->[PATH] || $self->_throw('unlink');
+ return unlink( $self->[PATH] ) || $self->_throw('unlink');
}
#pod =method remove_tree
@@ -1490,7 +1509,7 @@ Path::Tiny - File path utility
=head1 VERSION
-version 0.054
+version 0.056
=head1 SYNOPSIS
@@ -1765,19 +1784,28 @@ Copies a file using L<File::Copy>'s C<copy> function.
$obj = path("/tmp/foo.txt")->digest; # SHA-256
$obj = path("/tmp/foo.txt")->digest("MD5"); # user-selected
+ $obj = path("/tmp/foo.txt")->digest( { chunk_size => 1e6 }, "MD5" );
-Returns a hexadecimal digest for a file. Any arguments are passed to the
-constructor for L<Digest> to select an algorithm. If no arguments are given,
-the default is SHA-256.
+Returns a hexadecimal digest for a file. An optional hash reference of options may
+be given. The only option is C<chunk_size>. If C<chunk_size> is given, that many
+bytes will be read at a time. If not provided, the entire file will be slurped
+into memory to compute the digest.
-=head2 dirname
+Any subsequent arguments are passed to the constructor for L<Digest> to select
+an algorithm. If no arguments are given, the default is SHA-256.
+
+=head2 dirname (deprecated)
$name = path("/tmp/foo.txt")->dirname; # "/tmp/"
-Returns the directory name portion of the path. This is roughly
-equivalent to what L<File::Spec> would give from C<splitpath> and thus
-usually has the trailing slash. If that's not desired, stringify directories
-or call C<parent> on files.
+Returns the directory portion you would get from calling
+C<< File::Spec->splitpath( $path->stringify ) >> or C<"."> for a path without a
+parent directory portion. Because L<File::Spec> is inconsistent, the result
+might or might not have a trailing slash. Because of this, this method is
+B<deprecated>.
+
+A better, more consistently approach is likely C<< $path->parent->stringify >>,
+which will not have a trailing slash except for a root directory.
=head2 exists, is_file, is_dir
@@ -1982,8 +2010,9 @@ C<< File::Spec->abs2rel() >>.
B<Note: as of 0.012, remove only works on files>.
-This is just like C<unlink>, except if the path does not exist, it returns
-false rather than throwing an exception.
+This is just like C<unlink>, except for its error handling: if the path does
+not exist, it returns false; if deleting the file fails, it throws an
+exception.
=head2 remove_tree
@@ -2276,6 +2305,8 @@ David Golden <dagolden@cpan.org>
=head1 CONTRIBUTORS
+=for stopwords Chris Williams David Steinbrunner Doug Bell Gabor Szabo Gabriel Andrade George Hartzell Geraud Continsouzas Goro Fuji Karen Etheridge Martin Kjeldsen Michael G. Schwern Smylers Toby Inkster 김도형 - Keedi Kim
+
=over 4
=item *
@@ -2288,6 +2319,10 @@ David Steinbrunner <dsteinbrunner@pobox.com>
=item *
+Doug Bell <madcityzen@gmail.com>
+
+=item *
+
Gabor Szabo <szabgab@cpan.org>
=item *
@@ -2320,6 +2355,10 @@ Michael G. Schwern <mschwern@cpan.org>
=item *
+Smylers <Smylers@stripey.com>
+
+=item *
+
Toby Inkster <tobyink@cpan.org>
=item *
@@ -7,6 +7,9 @@ allow = $@ $!
[TestingAndDebugging::ProhibitNoStrict]
allow = refs
+[Variables::ProhibitEvilVariables]
+variables = $DB::single
+
# Turn these off
[-BuiltinFunctions::ProhibitStringyEval]
[-ControlStructures::ProhibitPostfixControls]
@@ -0,0 +1,70 @@
+do { my $x = {
+ 'configure' => {
+ 'requires' => {
+ 'ExtUtils::MakeMaker' => '6.17'
+ }
+ },
+ 'develop' => {
+ 'requires' => {
+ 'Dist::Zilla' => '5',
+ 'Dist::Zilla::Plugin::MinimumPerl' => '0',
+ 'Dist::Zilla::Plugin::OnlyCorePrereqs' => '0',
+ 'Dist::Zilla::Plugin::Prereqs' => '0',
+ 'Dist::Zilla::Plugin::RemovePrereqs' => '0',
+ 'Dist::Zilla::PluginBundle::DAGOLDEN' => '0.060',
+ 'File::Spec' => '0',
+ 'File::Temp' => '0',
+ 'IO::Handle' => '0',
+ 'IPC::Open3' => '0',
+ 'Pod::Coverage::TrustPod' => '0',
+ 'Test::CPAN::Meta' => '0',
+ 'Test::More' => '0',
+ 'Test::Pod' => '1.41',
+ 'Test::Pod::Coverage' => '1.08',
+ 'Test::Spelling' => '0.12'
+ }
+ },
+ 'runtime' => {
+ 'recommends' => {
+ 'Unicode::UTF8' => '0.58'
+ },
+ 'requires' => {
+ 'Carp' => '0',
+ 'Cwd' => '0',
+ 'Digest' => '1.03',
+ 'Digest::SHA' => '5.45',
+ 'Exporter' => '5.57',
+ 'Fcntl' => '0',
+ 'File::Copy' => '0',
+ 'File::Path' => '2.07',
+ 'File::Spec' => '3.40',
+ 'File::Temp' => '0.19',
+ 'File::stat' => '0',
+ 'constant' => '0',
+ 'if' => '0',
+ 'overload' => '0',
+ 'perl' => '5.008001',
+ 'strict' => '0',
+ 'warnings' => '0'
+ }
+ },
+ 'test' => {
+ 'recommends' => {
+ 'CPAN::Meta' => '2.120900',
+ 'Test::FailWarnings' => '0'
+ },
+ 'requires' => {
+ 'ExtUtils::MakeMaker' => '0',
+ 'File::Basename' => '0',
+ 'File::Spec' => '3.40',
+ 'File::Spec::Functions' => '0',
+ 'File::Spec::Unix' => '0',
+ 'File::Temp' => '0.19',
+ 'Test::More' => '0.96',
+ 'lib' => '0',
+ 'open' => '0'
+ }
+ }
+ };
+ $x;
+ }
\ No newline at end of file
@@ -3,201 +3,173 @@
use strict;
use warnings;
-# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.013
+# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.018
use Test::More tests => 1;
use ExtUtils::MakeMaker;
-use File::Spec::Functions;
-use List::Util qw/max/;
-use version;
+use File::Spec;
+
+# from $version::LAX
+my $lax_version_re =
+ qr/(?: undef | (?: (?:[0-9]+) (?: \. | (?:\.[0-9]+) (?:_[0-9]+)? )?
+ |
+ (?:\.[0-9]+) (?:_[0-9]+)?
+ ) | (?:
+ v (?:[0-9]+) (?: (?:\.[0-9]+)+ (?:_[0-9]+)? )?
+ |
+ (?:[0-9]+)? (?:\.[0-9]+){2,} (?:_[0-9]+)?
+ )
+ )/x;
# hide optional CPAN::Meta modules from prereq scanner
# and check if they are available
my $cpan_meta = "CPAN::Meta";
-my $cpan_meta_req = "CPAN::Meta::Requirements";
-my $HAS_CPAN_META = eval "require $cpan_meta"; ## no critic
-my $HAS_CPAN_META_REQ = eval "require $cpan_meta_req; $cpan_meta_req->VERSION('2.120900')";
+my $cpan_meta_pre = "CPAN::Meta::Prereqs";
+my $HAS_CPAN_META = eval "require $cpan_meta; $cpan_meta->VERSION('2.120900')" && eval "require $cpan_meta_pre"; ## no critic
# Verify requirements?
my $DO_VERIFY_PREREQS = 1;
-sub _merge_requires {
+sub _max {
+ my $max = shift;
+ $max = ( $_ > $max ) ? $_ : $max for @_;
+ return $max;
+}
+
+sub _merge_prereqs {
my ($collector, $prereqs) = @_;
- for my $phase ( qw/configure build test runtime develop/ ) {
- next unless exists $prereqs->{$phase};
- if ( my $req = $prereqs->{$phase}{'requires'} ) {
- my $cmr = CPAN::Meta::Requirements->from_string_hash( $req );
- $collector->add_requirements( $cmr );
+
+ # CPAN::Meta::Prereqs object
+ if (ref $collector eq $cpan_meta_pre) {
+ return $collector->with_merged_prereqs(
+ CPAN::Meta::Prereqs->new( $prereqs )
+ );
+ }
+
+ # Raw hashrefs
+ for my $phase ( keys %$prereqs ) {
+ for my $type ( keys %{ $prereqs->{$phase} } ) {
+ for my $module ( keys %{ $prereqs->{$phase}{$type} } ) {
+ $collector->{$phase}{$type}{$module} = $prereqs->{$phase}{$type}{$module};
+ }
}
}
+
+ return $collector;
}
-my %include = map {; $_ => 1 } qw(
+my @include = qw(
);
-my %exclude = map {; $_ => 1 } qw(
+my @exclude = qw(
);
# Add static prereqs to the included modules list
-my $static_prereqs = do { my $x = {
- 'configure' => {
- 'requires' => {
- 'ExtUtils::MakeMaker' => '6.17'
- }
- },
- 'develop' => {
- 'requires' => {
- 'Dist::Zilla' => '5.015',
- 'Dist::Zilla::Plugin::MinimumPerl' => '0',
- 'Dist::Zilla::Plugin::OnlyCorePrereqs' => '0',
- 'Dist::Zilla::Plugin::Prereqs' => '0',
- 'Dist::Zilla::Plugin::RemovePrereqs' => '0',
- 'Dist::Zilla::PluginBundle::DAGOLDEN' => '0.060',
- 'File::Spec' => '0',
- 'File::Temp' => '0',
- 'IO::Handle' => '0',
- 'IPC::Open3' => '0',
- 'Pod::Coverage::TrustPod' => '0',
- 'Test::CPAN::Meta' => '0',
- 'Test::More' => '0',
- 'Test::Pod' => '1.41',
- 'Test::Pod::Coverage' => '1.08'
- }
- },
- 'runtime' => {
- 'recommends' => {
- 'Unicode::UTF8' => '0.58'
- },
- 'requires' => {
- 'Carp' => '0',
- 'Cwd' => '0',
- 'Digest' => '1.03',
- 'Digest::SHA' => '5.45',
- 'Exporter' => '5.57',
- 'Fcntl' => '0',
- 'File::Copy' => '0',
- 'File::Path' => '2.07',
- 'File::Spec' => '3.40',
- 'File::Temp' => '0.19',
- 'File::stat' => '0',
- 'constant' => '0',
- 'if' => '0',
- 'overload' => '0',
- 'perl' => '5.008001',
- 'strict' => '0',
- 'warnings' => '0'
- }
- },
- 'test' => {
- 'recommends' => {
- 'CPAN::Meta' => '0',
- 'CPAN::Meta::Requirements' => '2.120900',
- 'Test::FailWarnings' => '0'
- },
- 'requires' => {
- 'ExtUtils::MakeMaker' => '0',
- 'File::Basename' => '0',
- 'File::Spec::Functions' => '0',
- 'File::Spec::Unix' => '0',
- 'File::Temp' => '0.19',
- 'List::Util' => '0',
- 'Test::More' => '0.96',
- 'lib' => '0',
- 'open' => '0',
- 'version' => '0'
- }
- }
- };
- $x;
- };
-
-delete $static_prereqs->{develop} if not $ENV{AUTHOR_TESTING};
-$include{$_} = 1 for map { keys %$_ } map { values %$_ } values %$static_prereqs;
-
-# Merge requirements for major phases (if we can)
-my $all_requires;
-if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META_REQ ) {
- $all_requires = $cpan_meta_req->new;
- _merge_requires($all_requires, $static_prereqs);
+my $static_prereqs = do 't/00-report-prereqs.dd';
+
+### XXX: Assume these are Runtime Requires
+my $static_prereqs_requires = $static_prereqs->{runtime}{requires};
+for my $mod (@include) {
+ $static_prereqs_requires->{$mod} = 0 unless exists $static_prereqs_requires->{$mod};
}
+# Merge all prereqs (either with ::Prereqs or a hashref)
+my $full_prereqs = _merge_prereqs(
+ ( $HAS_CPAN_META ? $cpan_meta_pre->new : {} ),
+ $static_prereqs
+);
# Add dynamic prereqs to the included modules list (if we can)
my ($source) = grep { -f } 'MYMETA.json', 'MYMETA.yml';
if ( $source && $HAS_CPAN_META ) {
- if ( my $meta = eval { CPAN::Meta->load_file($source) } ) {
- my $dynamic_prereqs = $meta->prereqs;
- delete $dynamic_prereqs->{develop} if not $ENV{AUTHOR_TESTING};
- $include{$_} = 1 for map { keys %$_ } map { values %$_ } values %$dynamic_prereqs;
-
- if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META_REQ ) {
- _merge_requires($all_requires, $dynamic_prereqs);
+ if ( my $meta = eval { CPAN::Meta->load_file($source) } ) {
+ $full_prereqs = _merge_prereqs($full_prereqs, $meta->prereqs);
}
- }
}
else {
- $source = 'static metadata';
+ $source = 'static metadata';
}
-my @modules = sort grep { ! $exclude{$_} } keys %include;
-my @reports = [qw/Version Module/];
+my @full_reports;
my @dep_errors;
-my $req_hash = defined($all_requires) ? $all_requires->as_string_hash : {};
-
-for my $mod ( @modules ) {
- next if $mod eq 'perl';
- my $file = $mod;
- $file =~ s{::}{/}g;
- $file .= ".pm";
- my ($prefix) = grep { -e catfile($_, $file) } @INC;
- if ( $prefix ) {
- my $ver = MM->parse_version( catfile($prefix, $file) );
- $ver = "undef" unless defined $ver; # Newer MM should do this anyway
- push @reports, [$ver, $mod];
-
- if ( $DO_VERIFY_PREREQS && $all_requires ) {
- my $req = $req_hash->{$mod};
- if ( defined $req && length $req ) {
- if ( ! defined eval { version->parse($ver) } ) {
- push @dep_errors, "$mod version '$ver' cannot be parsed (version '$req' required)";
- }
- elsif ( ! $all_requires->accepts_module( $mod => $ver ) ) {
- push @dep_errors, "$mod version '$ver' is not in required range '$req'";
+my $req_hash = $HAS_CPAN_META ? $full_prereqs->as_string_hash : $full_prereqs;
+
+for my $phase ( qw(configure build test runtime develop) ) {
+ next unless $req_hash->{$phase};
+ next if ($phase eq 'develop' and not $ENV{AUTHOR_TESTING});
+
+ for my $type ( qw(requires recommends suggests conflicts) ) {
+ next unless $req_hash->{$phase}{$type};
+
+ my $title = ucfirst($phase).' '.ucfirst($type);
+ my @reports = [qw/Module Want Have/];
+
+ for my $mod ( sort keys %{ $req_hash->{$phase}{$type} } ) {
+ next if $mod eq 'perl';
+ next if grep { $_ eq $mod } @exclude;
+
+ my $file = $mod;
+ $file =~ s{::}{/}g;
+ $file .= ".pm";
+ my ($prefix) = grep { -e File::Spec->catfile($_, $file) } @INC;
+
+ my $want = $req_hash->{$phase}{$type}{$mod};
+ $want = "undef" unless defined $want;
+ $want = "any" if !$want && $want == 0;
+
+ my $req_string = $want eq 'any' ? 'any version required' : "version '$want' required";
+
+ if ($prefix) {
+ my $have = MM->parse_version( File::Spec->catfile($prefix, $file) );
+ $have = "undef" unless defined $have;
+ push @reports, [$mod, $want, $have];
+
+ if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META && $type eq 'requires' ) {
+ if ( $have !~ /\A$lax_version_re\z/ ) {
+ push @dep_errors, "$mod version '$have' cannot be parsed ($req_string)";
+ }
+ elsif ( ! $full_prereqs->requirements_for( $phase, $type )->accepts_module( $mod => $have ) ) {
+ push @dep_errors, "$mod version '$have' is not in required range '$want'";
+ }
+ }
+ }
+ else {
+ push @reports, [$mod, $want, "missing"];
+
+ if ( $DO_VERIFY_PREREQS && $type eq 'requires' ) {
+ push @dep_errors, "$mod is not installed ($req_string)";
+ }
+ }
}
- }
- }
- }
- else {
- push @reports, ["missing", $mod];
+ if ( @reports ) {
+ push @full_reports, "=== $title ===\n\n";
+
+ my $ml = _max( map { length $_->[0] } @reports );
+ my $wl = _max( map { length $_->[1] } @reports );
+ my $hl = _max( map { length $_->[2] } @reports );
+ splice @reports, 1, 0, ["-" x $ml, "-" x $wl, "-" x $hl];
- if ( $DO_VERIFY_PREREQS && $all_requires ) {
- my $req = $req_hash->{$mod};
- if ( defined $req && length $req ) {
- push @dep_errors, "$mod is not installed (version '$req' required)";
- }
+ push @full_reports, map { sprintf(" %*s %*s %*s\n", -$ml, $_->[0], $wl, $_->[1], $hl, $_->[2]) } @reports;
+ push @full_reports, "\n";
+ }
}
- }
}
-if ( @reports ) {
- my $vl = max map { length $_->[0] } @reports;
- my $ml = max map { length $_->[1] } @reports;
- splice @reports, 1, 0, ["-" x $vl, "-" x $ml];
- diag "\nVersions for all modules listed in $source (including optional ones):\n",
- map {sprintf(" %*s %*s\n",$vl,$_->[0],-$ml,$_->[1])} @reports;
+if ( @full_reports ) {
+ diag "\nVersions for all modules listed in $source (including optional ones):\n\n", @full_reports;
}
if ( @dep_errors ) {
- diag join("\n",
- "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n",
- "The following REQUIRED prerequisites were not satisfied:\n",
- @dep_errors,
- "\n"
- );
+ diag join("\n",
+ "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n",
+ "The following REQUIRED prerequisites were not satisfied:\n",
+ @dep_errors,
+ "\n"
+ );
}
pass;
@@ -23,7 +23,9 @@ is(
my $sha = Digest->new('SHA-256');
$sha->add($chunk);
-is( $file->digest, $sha->hexdigest, 'digest SHA-256', );
+my $sha_hex = $sha->hexdigest;
+is( $file->digest, $sha_hex, 'digest SHA-256' );
+is( $file->digest( { chunk_size => 10 } ), $sha_hex, 'digest SHA-256 (chunked)' );
is(
$file->digest('MD5'),
@@ -33,7 +35,9 @@ is(
my $md5 = Digest->new('MD5');
$md5->add($chunk);
-is( $file->digest('MD5'), $md5->hexdigest, 'digest MD5', );
+my $md5_hex = $md5->hexdigest;
+is( $file->digest('MD5'), $md5_hex, 'digest MD5', );
+is( $file->digest( { chunk_size => 10 }, 'MD5' ), $md5_hex, 'digest MD5 (chunked)' );
done_testing;
#
@@ -176,6 +176,18 @@ my $tmpdir = Path::Tiny->tempdir;
ok( $file->remove, "removing file" );
ok !-e $file, "file is gone";
ok !$file->remove, "removing file again returns false";
+
+ my $subdir = $tmpdir->child('subdir');
+ ok $subdir->mkpath;
+ ok exception { $subdir->remove }, "calling 'remove' on a directory throws";
+ ok rmdir $subdir;
+
+ my $orig = Path::Tiny->cwd;
+ ok chdir $tmpdir;
+ my $zero_file = path '0';
+ ok $zero_file->openw;
+ ok $zero_file->remove, "removing file called '0'";
+ ok chdir $orig;
}
{
@@ -2,7 +2,7 @@ use 5.006;
use strict;
use warnings;
-# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.040
+# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.045
use Test::More tests => 1 + ($ENV{AUTHOR_TESTING} ? 1 : 0);
@@ -2,7 +2,7 @@ use strict;
use warnings;
use Test::More;
-# generated by Dist::Zilla::Plugin::Test::PodSpelling 2.006007
+# generated by Dist::Zilla::Plugin::Test::PodSpelling 2.006008
use Test::Spelling 0.12;
use Pod::Wordlist;
@@ -41,6 +41,9 @@ Williams
bingos
Steinbrunner
dsteinbrunner
+Doug
+Bell
+madcityzen
Gabor
Szabo
szabgab
@@ -65,6 +68,7 @@ mk
Michael
Schwern
mschwern
+Smylers
Toby
Inkster
tobyink