The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
CONTRIBUTING 1000
CONTRIBUTING.mkdn 0100
Changes 043
MANIFEST 23
META.json 1213
META.yml 67
Makefile.PL 84
README 19118
cpanfile 65
dist.ini 11
lib/Path/Tiny.pm 56273
perlcritic.rc 03
t/00-report-prereqs.dd 070
t/00-report-prereqs.t 151122
t/basic.t 04
t/digest.t 26
t/filesystem.t 012
xt/author/00-compile.t 22
xt/author/pod-spell.t 15
19 files changed (This is a version diff) 366791
@@ -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,48 @@
 Revision history for Path-Tiny
 
+0.058     2014-09-23 11:00:24-04:00 America/New_York
+
+    [ADDED]
+
+    - Added a 'sibling' method as a more efficient form of
+      calling $path->parent->child(...).
+
+    [DOCUMENTED]
+
+    - Every method annotated with the version number of the
+      last API change.
+
+0.057     2014-09-19 11:23:05-04:00 America/New_York
+
+    [FIXED]
+
+    - On AIX, reads that default to locking would fail without
+      write permissions, because locking needs write permissions.
+      The fix is only to lock reads if write permissions exist;
+      otherwise locking is skipped.
+
+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.140640",
    "license" : [
       "apache_2_0"
    ],
@@ -33,12 +33,12 @@
       },
       "develop" : {
          "requires" : {
-            "Dist::Zilla" : "5.015",
+            "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",
+            "Dist::Zilla::PluginBundle::DAGOLDEN" : "0.068",
             "File::Spec" : "0",
             "File::Temp" : "0",
             "IO::Handle" : "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.058"
       },
       "Path::Tiny::Error" : {
          "file" : "lib/Path/Tiny.pm",
-         "version" : "0.054"
+         "version" : "0.058"
       }
    },
    "release_status" : "stable",
@@ -116,11 +115,12 @@
          "web" : "https://github.com/dagolden/Path-Tiny"
       }
    },
-   "version" : "0.054",
+   "version" : "0.058",
    "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.140640'
 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.058'
   Path::Tiny::Error:
     file: lib/Path/Tiny.pm
-    version: '0.054'
+    version: '0.058'
 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.058'
 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.058",
   "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.058
 
 SYNOPSIS
       use Path::Tiny;
@@ -104,12 +104,16 @@ CONSTRUCTORS
     This optimizes copies without proliferating references unexpectedly if a
     copy is made by code outside your control.
 
+    Current API available since 0.017.
+
   new
         $path = Path::Tiny->new("foo/bar");
 
     This is just like "path", but with method call overhead. (Why would you
     do that?)
 
+    Current API available since 0.001.
+
   cwd
         $path = Path::Tiny->cwd; # path( Cwd::getcwd )
         $path = cwd; # optional export
@@ -120,6 +124,8 @@ CONSTRUCTORS
     "cwd" may be exported on request and used as a function instead of as a
     method.
 
+    Current API available since 0.018.
+
   rootdir
         $path = Path::Tiny->rootdir; # /
         $path = rootdir;             # optional export
@@ -130,6 +136,8 @@ CONSTRUCTORS
     "rootdir" may be exported on request and used as a function instead of
     as a method.
 
+    Current API available since 0.018.
+
   tempfile, tempdir
         $temp = Path::Tiny->tempfile( @options );
         $temp = Path::Tiny->tempdir( @options );
@@ -160,6 +168,8 @@ CONSTRUCTORS
     Both "tempfile" and "tempdir" may be exported on request and used as
     functions instead of as methods.
 
+    Current API available since 0.018.
+
 METHODS
   absolute
         $abs = path("foo/bar")->absolute;
@@ -178,6 +188,8 @@ METHODS
     On Windows, an absolute path without a volume component will have it
     added based on the current drive.
 
+    Current API available since 0.001.
+
   append, append_raw, append_utf8
         path("foo.txt")->append(@data);
         path("foo.txt")->append(\@data);
@@ -197,6 +209,8 @@ METHODS
     ":unix:encoding(UTF-8)". If Unicode::UTF8 0.58+ is installed, a raw
     append will be done instead on the data encoded with "Unicode::UTF8".
 
+    Current API available since 0.004.
+
   basename
         $name = path("foo/bar.txt")->basename;        # bar.txt
         $name = path("foo.txt")->basename('.txt');    # foo
@@ -209,6 +223,8 @@ METHODS
     match at the end of the file portion or last directory portion will be
     removed before the result is returned.
 
+    Current API available since 0.054.
+
   canonpath
         $canonical = path("foo/bar")->canonpath; # foo\bar on Windows
 
@@ -216,6 +232,8 @@ METHODS
     platform. In particular, this means directory separators will be "\" on
     Windows.
 
+    Current API available since 0.001.
+
   child
         $file = path("/tmp")->child("foo.txt"); # "/tmp/foo.txt"
         $file = path("/tmp")->child(@parts);
@@ -224,6 +242,8 @@ METHODS
     "catfile" or "catdir" from File::Spec, but without caring about file or
     directories.
 
+    Current API available since 0.001.
+
   children
         @paths = path("/tmp")->children;
         @paths = path("/tmp")->children( qr/\.txt$/ );
@@ -238,6 +258,8 @@ METHODS
         @paths = path("/tmp")->children( qr/^foo/ );
         # matches children like the glob foo*
 
+    Current API available since 0.028.
+
   chmod
         path("foo.txt")->chmod(0777);
         path("foo.txt")->chmod("0755");
@@ -255,26 +277,44 @@ METHODS
     allowed and permissions "stugoX" are not supported. (See File::chmod for
     more complex needs.)
 
+    Current API available since 0.053.
+
   copy
         path("/tmp/foo.txt")->copy("/tmp/bar.txt");
 
     Copies a file using File::Copy's "copy" function.
 
+    Current API available since 0.001.
+
   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. 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.
 
-    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.
+    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
+    Current API available since 0.056.
+
+  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.
+
+    Deprecated in 0.056.
 
   exists, is_file, is_dir
         if ( path("/tmp")->exists ) { ... }     # -e
@@ -290,6 +330,8 @@ METHODS
 
     Use "-f" instead if you really mean to check for a plain file.
 
+    Current API available since 0.053.
+
   filehandle
         $fh = path("/tmp/foo.txt")->filehandle($mode, $binmode);
         $fh = path("/tmp/foo.txt")->filehandle({ locked => 1 }, $mode, $binmode);
@@ -306,12 +348,16 @@ METHODS
 
     See "openr", "openw", "openrw", and "opena" for sugar.
 
+    Current API available since 0.039.
+
   is_absolute, is_relative
         if ( path("/tmp")->is_absolute ) { ... }
         if ( path("/tmp")->is_relative ) { ... }
 
     Booleans for whether the path appears absolute or relative.
 
+    Current API available since 0.001.
+
   is_rootdir
         while ( ! $path->is_rootdir ) {
             $path = $path->parent;
@@ -326,6 +372,8 @@ METHODS
         path("C:/")->is_rootdir;             # true
         path("//server/share/")->is_rootdir; #true
 
+    Current API available since 0.038.
+
   iterator
         $iter = path("/tmp")->iterator( \%options );
 
@@ -356,6 +404,8 @@ METHODS
     For a more powerful, recursive iterator with built-in loop avoidance,
     see Path::Iterator::Rule.
 
+    Current API available since 0.016.
+
   lines, lines_raw, lines_utf8
         @contents = path("/tmp/foo.txt")->lines;
         @contents = path("/tmp/foo.txt")->lines(\%options);
@@ -385,6 +435,8 @@ METHODS
     ":encoding(UTF-8)", though a bit memory intensive. If memory use is a
     concern, consider "openr_utf8" and iterating directly on the handle.
 
+    Current API available since 0.048.
+
   mkpath
         path("foo/bar/baz")->mkpath;
         path("foo/bar/baz")->mkpath( \%options );
@@ -394,11 +446,15 @@ METHODS
     thrown. Returns the list of directories created or an empty list if the
     directories already exist, just like "make_path".
 
+    Current API available since 0.001.
+
   move
         path("foo.txt")->move("bar.txt");
 
     Just like "rename".
 
+    Current API available since 0.001.
+
   openr, openw, openrw, opena
         $fh = path("foo.txt")->openr($binmode);  # read
         $fh = path("foo.txt")->openr_raw;
@@ -430,6 +486,8 @@ METHODS
 
     See "filehandle" for more on locking.
 
+    Current API available since 0.011.
+
   parent
         $parent = path("foo/bar/baz")->parent; # foo/bar
         $parent = path("foo/wibble.txt")->parent; # foo
@@ -441,6 +499,8 @@ METHODS
     the number of parent directories upwards to return. "parent" by itself
     is equivalent to parent(1).
 
+    Current API available since 0.014.
+
   realpath
         $real = path("/baz/foo/../bar")->realpath;
         $real = path("foo/../bar")->realpath;
@@ -454,19 +514,24 @@ METHODS
 
         $real = path("doesnt_exist/foo")->realpath; # dies
 
+    Current API available since 0.001.
+
   relative
         $rel = path("/tmp/foo/bar")->relative("/tmp"); # foo/bar
 
     Returns a "Path::Tiny" object with a relative path name. Given the
     trickiness of this, it's a thin wrapper around "File::Spec->abs2rel()".
 
+    Current API available since 0.001.
+
   remove
         path("foo.txt")->remove;
 
-    Note: as of 0.012, remove only works on files.
+    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.
 
-    This is just like "unlink", except if the path does not exist, it
-    returns false rather than throwing an exception.
+    Current API available since 0.012.
 
   remove_tree
         # directory
@@ -484,6 +549,19 @@ METHODS
 
         rmdir path("foo/bar/baz/");
 
+    Current API available since 0.013.
+
+  sibling
+        $foo = path("/tmp/foo.txt");
+        $sib = $foo->sibling("bar.txt");        # /tmp/bar.txt
+        $sib = $foo->sibling("baz", "bam.txt"); # /tmp/baz/bam.txt
+
+    Returns a new "Path::Tiny" object relative to the parent of the
+    original. This is slightly more efficient than
+    "$path->parent->child(...)".
+
+    Current API available since 0.058.
+
   slurp, slurp_raw, slurp_utf8
         $data = path("foo.txt")->slurp;
         $data = path("foo.txt")->slurp( {binmode => ":raw"} );
@@ -503,6 +581,8 @@ METHODS
     This is just as strict and is roughly an order of magnitude faster than
     using ":encoding(UTF-8)".
 
+    Current API available since 0.004.
+
   spew, spew_raw, spew_utf8
         path("foo.txt")->spew(@data);
         path("foo.txt")->spew(\@data);
@@ -523,12 +603,16 @@ METHODS
     If Unicode::UTF8 0.58+ is installed, a raw spew will be done instead on
     the data encoded with "Unicode::UTF8".
 
+    Current API available since 0.011.
+
   stat, lstat
         $stat = path("foo.txt")->stat;
         $stat = path("/some/symlink")->lstat;
 
     Like calling "stat" or "lstat" from File::stat.
 
+    Current API available since 0.001.
+
   stringify
         $path = path("foo.txt");
         say $path->stringify; # same as "$path"
@@ -537,6 +621,8 @@ METHODS
     method returns the path standardized with Unix-style "/" directory
     separators.
 
+    Current API available since 0.001.
+
   subsumes
         path("foo/bar")->subsumes("foo/bar/baz"); # true
         path("/foo/bar")->subsumes("/foo/baz");   # false
@@ -555,6 +641,8 @@ METHODS
         my $p2 = path("foo/bar/../baz")->realpath;
         if ( $p1->subsumes($p2) ) { ... }
 
+    Current API available since 0.048.
+
   touch
         path("foo.txt")->touch;
         path("foo.txt")->touch($epoch_secs);
@@ -567,6 +655,8 @@ METHODS
 
         path("foo.txt")->touch->spew( $content );
 
+    Current API available since 0.015.
+
   touchpath
         path("bar/baz/foo.txt")->touchpath;
 
@@ -574,6 +664,8 @@ METHODS
     doesn't exist, before touching the file. Returns the path object like
     "touch" does.
 
+    Current API available since 0.022.
+
   volume
         $vol = path("/tmp/foo.txt")->volume;   # ""
         $vol = path("C:/tmp/foo.txt")->volume; # "C:"
@@ -583,6 +675,8 @@ METHODS
     empty string on Unix-like operating systems or the drive letter for an
     absolute path on "MSWin32".
 
+    Current API available since 0.001.
+
 EXCEPTION HANDLING
     Simple usage errors will generally croak. Failures of underlying Perl
     unctions will be thrown as exceptions in the class "Path::Tiny::Error".
@@ -620,7 +714,8 @@ CAVEATS
    AIX and locking
     AIX requires a write handle for locking. Therefore, calls that normally
     open a read handle and take a shared lock instead will open a read-write
-    handle and take an exclusive lock.
+    handle and take an exclusive lock. If the user does not have write
+    permission, no lock will be used.
 
   utf8 vs UTF-8
     All the *_utf8 methods use ":encoding(UTF-8)" -- either as
@@ -706,8 +801,18 @@ AUTHOR
 CONTRIBUTORS
     *   Chris Williams <bingos@cpan.org>
 
+    *   Michael G. Schwern <mschwern@cpan.org>
+
+    *   Smylers <Smylers@stripey.com>
+
+    *   Toby Inkster <tobyink@cpan.org>
+
+    *   김도형 - Keedi Kim <keedi@cpan.org>
+
     *   David Steinbrunner <dsteinbrunner@pobox.com>
 
+    *   Doug Bell <madcityzen@gmail.com>
+
     *   Gabor Szabo <szabgab@cpan.org>
 
     *   Gabriel Andrade <gabiruh@gmail.com>
@@ -722,12 +827,6 @@ CONTRIBUTORS
 
     *   Martin Kjeldsen <mk@bluepipe.dk>
 
-    *   Michael G. Schwern <mschwern@cpan.org>
-
-    *   Toby Inkster <tobyink@cpan.org>
-
-    *   김도형 - Keedi Kim <keedi@cpan.org>
-
 COPYRIGHT AND LICENSE
     This software is Copyright (c) 2013 by David Golden.
 
@@ -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,12 +39,12 @@ 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";
   requires "Dist::Zilla::Plugin::RemovePrereqs" => "0";
-  requires "Dist::Zilla::PluginBundle::DAGOLDEN" => "0.060";
+  requires "Dist::Zilla::PluginBundle::DAGOLDEN" => "0.068";
   requires "File::Spec" => "0";
   requires "File::Temp" => "0";
   requires "IO::Handle" => "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";
 };
@@ -5,7 +5,7 @@ copyright_holder = David Golden
 copyright_year   = 2013
 
 [@DAGOLDEN]
-:version = 0.060
+:version = 0.068
 -remove = MinimumPerlFast
 stopwords = AIX
 stopwords = BENCHMARKING
@@ -4,7 +4,7 @@ use warnings;
 
 package Path::Tiny;
 # ABSTRACT: File path utility
-our $VERSION = '0.054'; # VERSION
+our $VERSION = '0.058'; # VERSION
 
 # Dependencies
 use Config;
@@ -191,6 +191,8 @@ sub _get_args {
 #pod This optimizes copies without proliferating references unexpectedly if a copy is
 #pod made by code outside your control.
 #pod
+#pod Current API available since 0.017.
+#pod
 #pod =cut
 
 sub path {
@@ -203,7 +205,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 +214,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 +238,6 @@ sub path {
         $path =~ s{^(~[^/]*)}{$homedir};
     }
 
-    # and we're finally done
     bless [ $path, $cpath ], __PACKAGE__;
 }
 
@@ -248,6 +248,8 @@ sub path {
 #pod This is just like C<path>, but with method call overhead.  (Why would you
 #pod do that?)
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 sub new { shift; path(@_) }
@@ -263,6 +265,8 @@ sub new { shift; path(@_) }
 #pod C<cwd> may be exported on request and used as a function instead of as a
 #pod method.
 #pod
+#pod Current API available since 0.018.
+#pod
 #pod =cut
 
 sub cwd {
@@ -281,6 +285,8 @@ sub cwd {
 #pod C<rootdir> may be exported on request and used as a function instead of as a
 #pod method.
 #pod
+#pod Current API available since 0.018.
+#pod
 #pod =cut
 
 sub rootdir { path( File::Spec->rootdir ) }
@@ -315,10 +321,12 @@ sub rootdir { path( File::Spec->rootdir ) }
 #pod Both C<tempfile> and C<tempdir> may be exported on request and used as
 #pod functions instead of as methods.
 #pod
+#pod Current API available since 0.018.
+#pod
 #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 +335,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;
 }
 
@@ -386,6 +394,8 @@ sub _splitpath {
 #pod On Windows, an absolute path without a volume component will have it added
 #pod based on the current drive.
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 sub absolute {
@@ -431,6 +441,8 @@ sub absolute {
 #pod C<:unix:encoding(UTF-8)>.  If L<Unicode::UTF8> 0.58+ is installed, a raw
 #pod append will be done instead on the data encoded with C<Unicode::UTF8>.
 #pod
+#pod Current API available since 0.004.
+#pod
 #pod =cut
 
 sub append {
@@ -470,6 +482,8 @@ sub append_utf8 {
 #pod the end of the file portion or last directory portion will be removed before
 #pod the result is returned.
 #pod
+#pod Current API available since 0.054.
+#pod
 #pod =cut
 
 sub basename {
@@ -491,6 +505,8 @@ sub basename {
 #pod the platform.  In particular, this means directory separators
 #pod will be C<\> on Windows.
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 sub canonpath { $_[0]->[CANON] }
@@ -504,6 +520,8 @@ sub canonpath { $_[0]->[CANON] }
 #pod like C<catfile> or C<catdir> from File::Spec, but without caring about
 #pod file or directories.
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 sub child {
@@ -526,6 +544,8 @@ sub child {
 #pod     @paths = path("/tmp")->children( qr/^foo/ );
 #pod     # matches children like the glob foo*
 #pod
+#pod Current API available since 0.028.
+#pod
 #pod =cut
 
 sub children {
@@ -565,6 +585,8 @@ sub children {
 #pod are required for each clause, multiple ops are not allowed and permissions
 #pod C<stugoX> are not supported.  (See L<File::chmod> for more complex needs.)
 #pod
+#pod Current API available since 0.053.
+#pod
 #pod =cut
 
 sub chmod {
@@ -592,6 +614,8 @@ sub chmod {
 #pod
 #pod Copies a file using L<File::Copy>'s C<copy> function.
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 # XXX do recursively for directories?
@@ -606,28 +630,52 @@ 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.  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 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 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 Current API available since 0.056.
 #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 Deprecated in 0.056.
 #pod
 #pod =cut
 
@@ -652,6 +700,7 @@ sub dirname {
 #pod
 #pod Use C<-f> instead if you really mean to check for a plain file.
 #pod
+#pod Current API available since 0.053.
 #pod
 #pod =cut
 
@@ -678,6 +727,8 @@ sub is_dir { -d $_[0]->[PATH] }
 #pod
 #pod See C<openr>, C<openw>, C<openrw>, and C<opena> for sugar.
 #pod
+#pod Current API available since 0.039.
+#pod
 #pod =cut
 
 # Note: must put binmode on open line, not subsequent binmode() call, so things
@@ -728,9 +779,14 @@ sub filehandle {
             $trunc = 1;
         }
         elsif ( $^O eq 'aix' && $opentype eq "<" ) {
-            # AIX can only lock write handles, so upgrade to RW and LOCK_EX
-            $opentype = "+<";
-            $lock     = Fcntl::LOCK_EX();
+            # AIX can only lock write handles, so upgrade to RW and LOCK_EX if
+            # the file is writable; otherwise give up on locking.  N.B.
+            # checking -w before open to determine the open mode is an
+            # unavoidable race condition
+            if ( -w $self->[PATH] ) {
+                $opentype = "+<";
+                $lock     = Fcntl::LOCK_EX();
+            }
         }
         else {
             $lock = $opentype eq "<" ? Fcntl::LOCK_SH() : Fcntl::LOCK_EX();
@@ -755,6 +811,8 @@ sub filehandle {
 #pod
 #pod Booleans for whether the path appears absolute or relative.
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 sub is_absolute { substr( $_[0]->dirname, 0, 1 ) eq '/' }
@@ -776,6 +834,8 @@ sub is_relative { substr( $_[0]->dirname, 0, 1 ) ne '/' }
 #pod     path("C:/")->is_rootdir;             # true
 #pod     path("//server/share/")->is_rootdir; #true
 #pod
+#pod Current API available since 0.038.
+#pod
 #pod =cut
 
 sub is_rootdir {
@@ -815,6 +875,8 @@ sub is_rootdir {
 #pod For a more powerful, recursive iterator with built-in loop avoidance, see
 #pod L<Path::Iterator::Rule>.
 #pod
+#pod Current API available since 0.016.
+#pod
 #pod =cut
 
 sub iterator {
@@ -892,6 +954,8 @@ sub iterator {
 #pod intensive.  If memory use is a concern, consider C<openr_utf8> and
 #pod iterating directly on the handle.
 #pod
+#pod Current API available since 0.048.
+#pod
 #pod =cut
 
 sub lines {
@@ -956,6 +1020,8 @@ sub lines_utf8 {
 #pod thrown.  Returns the list of directories created or an empty list if
 #pod the directories already exist, just like C<make_path>.
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 sub mkpath {
@@ -978,6 +1044,8 @@ sub mkpath {
 #pod
 #pod Just like C<rename>.
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 sub move {
@@ -1018,6 +1086,8 @@ sub move {
 #pod
 #pod See L</filehandle> for more on locking.
 #pod
+#pod Current API available since 0.011.
+#pod
 #pod =cut
 
 # map method names to corresponding open mode
@@ -1066,6 +1136,8 @@ while ( my ( $k, $v ) = each %opens ) {
 #pod of parent directories upwards to return.  C<parent> by itself is equivalent to
 #pod C<parent(1)>.
 #pod
+#pod Current API available since 0.014.
+#pod
 #pod =cut
 
 # XXX this is ugly and coverage is incomplete.  I think it's there for windows
@@ -1119,6 +1191,8 @@ sub _non_empty {
 #pod
 #pod     $real = path("doesnt_exist/foo")->realpath; # dies
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 sub realpath {
@@ -1140,6 +1214,8 @@ sub realpath {
 #pod Given the trickiness of this, it's a thin wrapper around
 #pod C<< File::Spec->abs2rel() >>.
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 # Easy to get wrong, so wash it through File::Spec (sigh)
@@ -1149,10 +1225,11 @@ sub relative { path( File::Spec->abs2rel( $_[0]->[PATH], $_[1] ) ) }
 #pod
 #pod     path("foo.txt")->remove;
 #pod
-#pod B<Note: as of 0.012, remove only works on files>.
+#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 This is just like C<unlink>, except if the path does not exist, it returns
-#pod false rather than throwing an exception.
+#pod Current API available since 0.012.
 #pod
 #pod =cut
 
@@ -1161,7 +1238,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
@@ -1181,6 +1258,8 @@ sub remove {
 #pod
 #pod     rmdir path("foo/bar/baz/");
 #pod
+#pod Current API available since 0.013.
+#pod
 #pod =cut
 
 sub remove_tree {
@@ -1200,6 +1279,24 @@ sub remove_tree {
     return $count;
 }
 
+#pod =method sibling
+#pod
+#pod     $foo = path("/tmp/foo.txt");
+#pod     $sib = $foo->sibling("bar.txt");        # /tmp/bar.txt
+#pod     $sib = $foo->sibling("baz", "bam.txt"); # /tmp/baz/bam.txt
+#pod
+#pod Returns a new C<Path::Tiny> object relative to the parent of the original.
+#pod This is slightly more efficient than C<< $path->parent->child(...) >>.
+#pod
+#pod Current API available since 0.058.
+#pod
+#pod =cut
+
+sub sibling {
+    my $self = shift;
+    return path( $self->parent->[PATH], @_ );
+}
+
 #pod =method slurp, slurp_raw, slurp_utf8
 #pod
 #pod     $data = path("foo.txt")->slurp;
@@ -1220,6 +1317,8 @@ sub remove_tree {
 #pod This is just as strict and is roughly an order of magnitude faster than
 #pod using C<:encoding(UTF-8)>.
 #pod
+#pod Current API available since 0.004.
+#pod
 #pod =cut
 
 sub slurp {
@@ -1273,6 +1372,8 @@ sub slurp_utf8 {
 #pod If L<Unicode::UTF8> 0.58+ is installed, a raw spew will be done instead on
 #pod the data encoded with C<Unicode::UTF8>.
 #pod
+#pod Current API available since 0.011.
+#pod
 #pod =cut
 
 # XXX add "unsafe" option to disable flocking and atomic?  Check benchmarks on append() first.
@@ -1315,6 +1416,8 @@ sub spew_utf8 {
 #pod
 #pod Like calling C<stat> or C<lstat> from L<File::stat>.
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 # XXX break out individual stat() components as subs?
@@ -1338,6 +1441,8 @@ sub lstat {
 #pod Returns a string representation of the path.  Unlike C<canonpath>, this method
 #pod returns the path standardized with Unix-style C</> directory separators.
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 sub stringify { $_[0]->[PATH] }
@@ -1361,6 +1466,8 @@ sub stringify { $_[0]->[PATH] }
 #pod     my $p2 = path("foo/bar/../baz")->realpath;
 #pod     if ( $p1->subsumes($p2) ) { ... }
 #pod
+#pod Current API available since 0.048.
+#pod
 #pod =cut
 
 sub subsumes {
@@ -1412,6 +1519,8 @@ sub subsumes {
 #pod
 #pod     path("foo.txt")->touch->spew( $content );
 #pod
+#pod Current API available since 0.015.
+#pod
 #pod =cut
 
 sub touch {
@@ -1433,6 +1542,8 @@ sub touch {
 #pod Combines C<mkpath> and C<touch>.  Creates the parent directory if it doesn't exist,
 #pod before touching the file.  Returns the path object like C<touch> does.
 #pod
+#pod Current API available since 0.022.
+#pod
 #pod =cut
 
 sub touchpath {
@@ -1452,6 +1563,8 @@ sub touchpath {
 #pod usually is the empty string on Unix-like operating systems or the
 #pod drive letter for an absolute path on C<MSWin32>.
 #pod
+#pod Current API available since 0.001.
+#pod
 #pod =cut
 
 sub volume {
@@ -1490,7 +1603,7 @@ Path::Tiny - File path utility
 
 =head1 VERSION
 
-version 0.054
+version 0.058
 
 =head1 SYNOPSIS
 
@@ -1596,6 +1709,8 @@ stringified copy is made.
 This optimizes copies without proliferating references unexpectedly if a copy is
 made by code outside your control.
 
+Current API available since 0.017.
+
 =head2 new
 
     $path = Path::Tiny->new("foo/bar");
@@ -1603,6 +1718,8 @@ made by code outside your control.
 This is just like C<path>, but with method call overhead.  (Why would you
 do that?)
 
+Current API available since 0.001.
+
 =head2 cwd
 
     $path = Path::Tiny->cwd; # path( Cwd::getcwd )
@@ -1614,6 +1731,8 @@ This is slightly faster than C<< path(".")->absolute >>.
 C<cwd> may be exported on request and used as a function instead of as a
 method.
 
+Current API available since 0.018.
+
 =head2 rootdir
 
     $path = Path::Tiny->rootdir; # /
@@ -1625,6 +1744,8 @@ picky for C<path("/")>.
 C<rootdir> may be exported on request and used as a function instead of as a
 method.
 
+Current API available since 0.018.
+
 =head2 tempfile, tempdir
 
     $temp = Path::Tiny->tempfile( @options );
@@ -1655,6 +1776,8 @@ C<< File::Temp->newdir >> instead.
 Both C<tempfile> and C<tempdir> may be exported on request and used as
 functions instead of as methods.
 
+Current API available since 0.018.
+
 =head1 METHODS
 
 =head2 absolute
@@ -1674,6 +1797,8 @@ resolved, you must call the more expensive C<realpath> method instead.
 On Windows, an absolute path without a volume component will have it added
 based on the current drive.
 
+Current API available since 0.001.
+
 =head2 append, append_raw, append_utf8
 
     path("foo.txt")->append(@data);
@@ -1693,6 +1818,8 @@ C<append_utf8> is like C<append> with a C<binmode> of
 C<:unix:encoding(UTF-8)>.  If L<Unicode::UTF8> 0.58+ is installed, a raw
 append will be done instead on the data encoded with C<Unicode::UTF8>.
 
+Current API available since 0.004.
+
 =head2 basename
 
     $name = path("foo/bar.txt")->basename;        # bar.txt
@@ -1706,6 +1833,8 @@ Given a list of suffixes as strings or regular expressions, any that match at
 the end of the file portion or last directory portion will be removed before
 the result is returned.
 
+Current API available since 0.054.
+
 =head2 canonpath
 
     $canonical = path("foo/bar")->canonpath; # foo\bar on Windows
@@ -1714,6 +1843,8 @@ Returns a string with the canonical format of the path name for
 the platform.  In particular, this means directory separators
 will be C<\> on Windows.
 
+Current API available since 0.001.
+
 =head2 child
 
     $file = path("/tmp")->child("foo.txt"); # "/tmp/foo.txt"
@@ -1723,6 +1854,8 @@ Returns a new C<Path::Tiny> object relative to the original.  Works
 like C<catfile> or C<catdir> from File::Spec, but without caring about
 file or directories.
 
+Current API available since 0.001.
+
 =head2 children
 
     @paths = path("/tmp")->children;
@@ -1738,6 +1871,8 @@ for matching:
     @paths = path("/tmp")->children( qr/^foo/ );
     # matches children like the glob foo*
 
+Current API available since 0.028.
+
 =head2 chmod
 
     path("foo.txt")->chmod(0777);
@@ -1755,29 +1890,46 @@ match C<< qr/\A([augo]+)([=+-])([rwx]+)\z/ >>, which defines "who", "op" and
 are required for each clause, multiple ops are not allowed and permissions
 C<stugoX> are not supported.  (See L<File::chmod> for more complex needs.)
 
+Current API available since 0.053.
+
 =head2 copy
 
     path("/tmp/foo.txt")->copy("/tmp/bar.txt");
 
 Copies a file using L<File::Copy>'s C<copy> function.
 
+Current API available since 0.001.
+
 =head2 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.  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.
 
-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.
+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
+Current API available since 0.056.
+
+=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.
+
+Deprecated in 0.056.
 
 =head2 exists, is_file, is_dir
 
@@ -1794,6 +1946,8 @@ read just like files.
 
 Use C<-f> instead if you really mean to check for a plain file.
 
+Current API available since 0.053.
+
 =head2 filehandle
 
     $fh = path("/tmp/foo.txt")->filehandle($mode, $binmode);
@@ -1811,6 +1965,8 @@ acquired.
 
 See C<openr>, C<openw>, C<openrw>, and C<opena> for sugar.
 
+Current API available since 0.039.
+
 =head2 is_absolute, is_relative
 
     if ( path("/tmp")->is_absolute ) { ... }
@@ -1818,6 +1974,8 @@ See C<openr>, C<openw>, C<openrw>, and C<opena> for sugar.
 
 Booleans for whether the path appears absolute or relative.
 
+Current API available since 0.001.
+
 =head2 is_rootdir
 
     while ( ! $path->is_rootdir ) {
@@ -1833,6 +1991,8 @@ This works even on C<MSWin32> with drives and UNC volumes:
     path("C:/")->is_rootdir;             # true
     path("//server/share/")->is_rootdir; #true
 
+Current API available since 0.038.
+
 =head2 iterator
 
     $iter = path("/tmp")->iterator( \%options );
@@ -1864,6 +2024,8 @@ The default is the same as:
 For a more powerful, recursive iterator with built-in loop avoidance, see
 L<Path::Iterator::Rule>.
 
+Current API available since 0.016.
+
 =head2 lines, lines_raw, lines_utf8
 
     @contents = path("/tmp/foo.txt")->lines;
@@ -1895,6 +2057,8 @@ actually faster than relying on C<:encoding(UTF-8)>, though a bit memory
 intensive.  If memory use is a concern, consider C<openr_utf8> and
 iterating directly on the handle.
 
+Current API available since 0.048.
+
 =head2 mkpath
 
     path("foo/bar/baz")->mkpath;
@@ -1905,12 +2069,16 @@ is passed through to C<make_path>.  Errors will be trapped and an exception
 thrown.  Returns the list of directories created or an empty list if
 the directories already exist, just like C<make_path>.
 
+Current API available since 0.001.
+
 =head2 move
 
     path("foo.txt")->move("bar.txt");
 
 Just like C<rename>.
 
+Current API available since 0.001.
+
 =head2 openr, openw, openrw, opena
 
     $fh = path("foo.txt")->openr($binmode);  # read
@@ -1942,6 +2110,8 @@ locked with C<LOCK_EX>; otherwise, they are locked for C<LOCK_SH>.
 
 See L</filehandle> for more on locking.
 
+Current API available since 0.011.
+
 =head2 parent
 
     $parent = path("foo/bar/baz")->parent; # foo/bar
@@ -1954,6 +2124,8 @@ original directory or file. An optional positive integer argument is the number
 of parent directories upwards to return.  C<parent> by itself is equivalent to
 C<parent(1)>.
 
+Current API available since 0.014.
+
 =head2 realpath
 
     $real = path("/baz/foo/../bar")->realpath;
@@ -1968,6 +2140,8 @@ an exception will be thrown:
 
     $real = path("doesnt_exist/foo")->realpath; # dies
 
+Current API available since 0.001.
+
 =head2 relative
 
     $rel = path("/tmp/foo/bar")->relative("/tmp"); # foo/bar
@@ -1976,14 +2150,17 @@ Returns a C<Path::Tiny> object with a relative path name.
 Given the trickiness of this, it's a thin wrapper around
 C<< File::Spec->abs2rel() >>.
 
+Current API available since 0.001.
+
 =head2 remove
 
     path("foo.txt")->remove;
 
-B<Note: as of 0.012, remove only works on files>.
+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.
 
-This is just like C<unlink>, except if the path does not exist, it returns
-false rather than throwing an exception.
+Current API available since 0.012.
 
 =head2 remove_tree
 
@@ -2002,6 +2179,19 @@ C<rmdir> function instead.
 
     rmdir path("foo/bar/baz/");
 
+Current API available since 0.013.
+
+=head2 sibling
+
+    $foo = path("/tmp/foo.txt");
+    $sib = $foo->sibling("bar.txt");        # /tmp/bar.txt
+    $sib = $foo->sibling("baz", "bam.txt"); # /tmp/baz/bam.txt
+
+Returns a new C<Path::Tiny> object relative to the parent of the original.
+This is slightly more efficient than C<< $path->parent->child(...) >>.
+
+Current API available since 0.058.
+
 =head2 slurp, slurp_raw, slurp_utf8
 
     $data = path("foo.txt")->slurp;
@@ -2022,6 +2212,8 @@ slurp will be done instead and the result decoded with C<Unicode::UTF8>.
 This is just as strict and is roughly an order of magnitude faster than
 using C<:encoding(UTF-8)>.
 
+Current API available since 0.004.
+
 =head2 spew, spew_raw, spew_utf8
 
     path("foo.txt")->spew(@data);
@@ -2042,6 +2234,8 @@ C<spew_utf8> is like C<spew> with a C<binmode> of C<:unix:encoding(UTF-8)>.
 If L<Unicode::UTF8> 0.58+ is installed, a raw spew will be done instead on
 the data encoded with C<Unicode::UTF8>.
 
+Current API available since 0.011.
+
 =head2 stat, lstat
 
     $stat = path("foo.txt")->stat;
@@ -2049,6 +2243,8 @@ the data encoded with C<Unicode::UTF8>.
 
 Like calling C<stat> or C<lstat> from L<File::stat>.
 
+Current API available since 0.001.
+
 =head2 stringify
 
     $path = path("foo.txt");
@@ -2057,6 +2253,8 @@ Like calling C<stat> or C<lstat> from L<File::stat>.
 Returns a string representation of the path.  Unlike C<canonpath>, this method
 returns the path standardized with Unix-style C</> directory separators.
 
+Current API available since 0.001.
+
 =head2 subsumes
 
     path("foo/bar")->subsumes("foo/bar/baz"); # true
@@ -2076,6 +2274,8 @@ the filesystem with C<realpath>:
     my $p2 = path("foo/bar/../baz")->realpath;
     if ( $p1->subsumes($p2) ) { ... }
 
+Current API available since 0.048.
+
 =head2 touch
 
     path("foo.txt")->touch;
@@ -2089,6 +2289,8 @@ Returns the path object so it can be easily chained with spew:
 
     path("foo.txt")->touch->spew( $content );
 
+Current API available since 0.015.
+
 =head2 touchpath
 
     path("bar/baz/foo.txt")->touchpath;
@@ -2096,6 +2298,8 @@ Returns the path object so it can be easily chained with spew:
 Combines C<mkpath> and C<touch>.  Creates the parent directory if it doesn't exist,
 before touching the file.  Returns the path object like C<touch> does.
 
+Current API available since 0.022.
+
 =head2 volume
 
     $vol = path("/tmp/foo.txt")->volume;   # ""
@@ -2106,6 +2310,8 @@ equivalent to what L<File::Spec> would give from C<splitpath> and thus
 usually is the empty string on Unix-like operating systems or the
 drive letter for an absolute path on C<MSWin32>.
 
+Current API available since 0.001.
+
 =for Pod::Coverage openr_utf8 opena_utf8 openw_utf8 openrw_utf8
 openr_raw opena_raw openw_raw openrw_raw
 IS_BSD IS_WIN32 FREEZE THAW TO_JSON
@@ -2163,7 +2369,8 @@ category:
 
 AIX requires a write handle for locking.  Therefore, calls that normally
 open a read handle and take a shared lock instead will open a read-write
-handle and take an exclusive lock.
+handle and take an exclusive lock.  If the user does not have write
+permission, no lock will be used.
 
 =head2 utf8 vs UTF-8
 
@@ -2276,6 +2483,8 @@ David Golden <dagolden@cpan.org>
 
 =head1 CONTRIBUTORS
 
+=for stopwords Chris Williams Michael G. Schwern Smylers Toby Inkster 김도형 - Keedi Kim David Steinbrunner Doug Bell Gabor Szabo Gabriel Andrade George Hartzell Geraud Continsouzas Goro Fuji Karen Etheridge Martin Kjeldsen
+
 =over 4
 
 =item *
@@ -2284,47 +2493,55 @@ Chris Williams <bingos@cpan.org>
 
 =item *
 
-David Steinbrunner <dsteinbrunner@pobox.com>
+Michael G. Schwern <mschwern@cpan.org>
 
 =item *
 
-Gabor Szabo <szabgab@cpan.org>
+Smylers <Smylers@stripey.com>
 
 =item *
 
-Gabriel Andrade <gabiruh@gmail.com>
+Toby Inkster <tobyink@cpan.org>
 
 =item *
 
-George Hartzell <hartzell@cpan.org>
+김도형 - Keedi Kim <keedi@cpan.org>
 
 =item *
 
-Geraud Continsouzas <geraud@scsi.nc>
+David Steinbrunner <dsteinbrunner@pobox.com>
 
 =item *
 
-Goro Fuji <gfuji@cpan.org>
+Doug Bell <madcityzen@gmail.com>
 
 =item *
 
-Karen Etheridge <ether@cpan.org>
+Gabor Szabo <szabgab@cpan.org>
 
 =item *
 
-Martin Kjeldsen <mk@bluepipe.dk>
+Gabriel Andrade <gabiruh@gmail.com>
 
 =item *
 
-Michael G. Schwern <mschwern@cpan.org>
+George Hartzell <hartzell@cpan.org>
 
 =item *
 
-Toby Inkster <tobyink@cpan.org>
+Geraud Continsouzas <geraud@scsi.nc>
 
 =item *
 
-김도형 - Keedi Kim <keedi@cpan.org>
+Goro Fuji <gfuji@cpan.org>
+
+=item *
+
+Karen Etheridge <ether@cpan.org>
+
+=item *
+
+Martin Kjeldsen <mk@bluepipe.dk>
 
 =back
 
@@ -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.068',
+                                      '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,172 @@
 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.019
 
 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';
 
+# 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;
+
+# Add static includes into a fake section
+for my $mod (@include) {
+    $req_hash->{other}{modules}{$mod} = 0;
+}
+
+for my $phase ( qw(configure build test runtime develop other) ) {
+    next unless $req_hash->{$phase};
+    next if ($phase eq 'develop' and not $ENV{AUTHOR_TESTING});
+
+    for my $type ( qw(requires recommends suggests conflicts modules) ) {
+        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";
 
-    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)";
-      }
+            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];
+
+            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;
@@ -51,6 +51,10 @@ is $cat,     '/tmp/foo';
 isa_ok $cat, 'Path::Tiny';
 is $cat->basename, 'foo';
 
+my $sib = $cat->sibling('bar');
+is $sib,     '/tmp/bar';
+isa_ok $sib, 'Path::Tiny';
+
 my $file = path('/foo//baz/./foo');
 is $file, '/foo/baz/foo';
 is $file->dirname, '/foo/baz/';
@@ -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.046
 
 use Test::More  tests => 1 + ($ENV{AUTHOR_TESTING} ? 1 : 0);
 
@@ -48,6 +48,6 @@ for my $lib (@module_files)
 
 
 
-is(scalar(@warnings), 0, 'no warnings found') if $ENV{AUTHOR_TESTING};
+is(scalar(@warnings), 0, 'no warnings found') or diag 'got warnings: ', explain \@warnings if $ENV{AUTHOR_TESTING};
 
 
@@ -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