Imported Upstream version 0.1011 upstream/0.1011
authorTizenOpenSource <tizenopensrc@samsung.com>
Wed, 14 Feb 2024 02:06:27 +0000 (11:06 +0900)
committerTizenOpenSource <tizenopensrc@samsung.com>
Wed, 14 Feb 2024 02:06:27 +0000 (11:06 +0900)
31 files changed:
CONTRIBUTING.mkdn [new file with mode: 0644]
Changes [new file with mode: 0644]
LICENSE [new file with mode: 0644]
MANIFEST [new file with mode: 0644]
META.json [new file with mode: 0644]
META.yml [new file with mode: 0644]
Makefile.PL [new file with mode: 0644]
README [new file with mode: 0644]
cpanfile [new file with mode: 0644]
dist.ini [new file with mode: 0644]
examples/chdir-example.pl [new file with mode: 0644]
lib/File/chdir.pm [new file with mode: 0644]
perlcritic.rc [new file with mode: 0644]
t/00-report-prereqs.dd [new file with mode: 0644]
t/00-report-prereqs.t [new file with mode: 0644]
t/array.t [new file with mode: 0644]
t/chdir.t [new file with mode: 0644]
t/delete-array.t [new file with mode: 0644]
t/lib/dummy.txt [new file with mode: 0644]
t/nested.t [new file with mode: 0644]
t/newline.t [new file with mode: 0644]
t/var.t [new file with mode: 0644]
xt/author/00-compile.t [new file with mode: 0644]
xt/author/critic.t [new file with mode: 0644]
xt/author/pod-coverage.t [new file with mode: 0644]
xt/author/pod-spell.t [new file with mode: 0644]
xt/author/pod-syntax.t [new file with mode: 0644]
xt/author/portability.t [new file with mode: 0644]
xt/author/test-version.t [new file with mode: 0644]
xt/release/distmeta.t [new file with mode: 0644]
xt/release/minimum-version.t [new file with mode: 0644]

diff --git a/CONTRIBUTING.mkdn b/CONTRIBUTING.mkdn
new file mode 100644 (file)
index 0000000..761c9db
--- /dev/null
@@ -0,0 +1,87 @@
+## 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, as is much of the documentation.  Some generated files are
+kept in the repository as a convenience (e.g. Makefile.PL or cpanfile).
+
+Generally, **you do not need Dist::Zilla to contribute patches**.  You do need
+Dist::Zilla to create a tarball.  See below for guidance.
+
+### Getting dependencies
+
+If you have App::cpanminus 1.6 or later installed, you can use `cpanm` to
+satisfy dependencies like this:
+
+    $ cpanm --installdeps .
+
+Otherwise, look for either a `Makefile.PL` or `cpanfile` file for
+a list of dependencies to satisfy.
+
+### 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.  Some is
+generated boilerplate; other documentation is built from pseudo-POD
+directives in the source like C<=method> or C<=func>.
+
+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 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
+
+You can learn more about Dist::Zilla at http://dzil.org/
+
diff --git a/Changes b/Changes
new file mode 100644 (file)
index 0000000..8b31e82
--- /dev/null
+++ b/Changes
@@ -0,0 +1,121 @@
+Changes for File-chdir
+
+0.1011    2016-10-07 10:23:15-04:00 America/New_York
+
+    [Documentation]
+
+    - Fixed POD typos
+
+0.1010    2015-02-05 10:04:27-05:00 America/New_York
+
+    [Changed]
+
+    - Updated distribution metadata and repo layout
+
+    - Changed bugtracker to github
+
+0.1009    2014-09-23 12:24:11-04:00 America/New_York
+
+    [Changed]
+
+    - Updated distribution metadata
+
+0.1008    2012-12-02 22:32:37 America/New_York
+
+    - Fixed broken use of abs_path on Cygwin [Joel Berger]
+
+0.1007    2012-09-17 20:29:43 America/New_York
+
+    - Fixed broken Pod link; reordered CAVEATS section
+
+0.1006    2011-11-02 18:11:13 America/New_York
+
+    - Handle directories with newlines [rt.cpan.org #72114]
+
+0.1005    2011-11-02 14:21:27 America/New_York
+
+    - Fixed rt.cpan.org #53064 [Michael Schwern]
+
+    - Removes bundled Test::More
+
+    - Converted distribution builder to Dist::Zilla
+
+0.1004 Wed Jun  9 14:14:54 EDT 2010
+
+    - Build.Pl and Makefile.PL will bail out on Perl 5.13.1, which
+      accidentally broke File::chdir
+
+0.1003 Tue Apr 27 21:21:32 EDT 2010
+
+    - testfix: remove -T flag in tests
+
+0.1002 Mon Feb 11 19:47:46 EST 2008
+
+    - testfix: 0.1001 accidentally left many array tests commented out
+
+0.1001 Sat Feb  9 13:07:05 EST 2008
+
+    - testfix: work around odd Test::Builder errors on perl 5.6.2 dying in
+      the middle of a "push"
+
+0.10 Fri Feb  8 08:42:53 EST 2008
+    - File::Spec 3.2501 broke File::chdir on Win32; updated prerequisite to
+      latest File::Spec (3.27) and rewrote internals of File::chdir
+    - Split array deletion tests to separate file to skip on Perl < 5.006
+    - Added Build.PL and other files (e.g. INSTALL, LICENSE) to the tarball
+    - Minor documentation changes/additions
+
+0.0901
+    - removed unnecessary prototypes on internal functions (perl critic)
+    - cosmetic changes to distribution package (README, extra tests in xt)
+
+0.09 Mon Jul 30 09:50:28 EDT 2007
+    - Updated Makefile.PL to warn about API change in 0.08
+    - Added $! diagnostic to error messages
+
+0.08 Thu Jun 21 20:56:50 EDT 2007
+    * Croaks if the chdir fails when changing $CWD or @CWD
+    * Deleting from end of @CWD acts like a pop
+    - Revised and expanded @CWD tests
+    - Revised delete error message for deleting from middle of @CWD
+    - Added DIAGNOSTICS section to documentation
+
+0.07 Mon Jun 18 18:38:00 EDT 2007
+    - Fixed testfile bug that prepended "/" in tests on Cygwin
+
+0.06_01 Mon Apr  9 05:17:02 EDT 2007
+    - Development release by David Golden
+    * Fixed bug that prepended "/" to $CWD for Win32
+    * $CWD changed to use native path separators
+    * Tests fixed on Win32 by always using native separators as well
+    * Upped File::Spec and Cwd dependencies to require many recent bug-fixes
+    - Added note about comparing $CWD to File::Spec generated names
+    - Other minor documentation patches from Schwern
+
+0.06  Thu Aug 14 17:02:32 PDT 2003
+    * Now working under taint mode (thanks Mark Guckeyson)
+    - Small nit in the SYNOPSIS
+    * Removed dependency on File::Spec 0.8 and File::Spec::Functions
+    - Added a LICENSE
+    - Added NOTES about %CWD.
+
+0.05  Mon Nov 26 15:44:20 EST 2001
+    * Added @CWD
+    - $CWD's value now guaranteed to be correct even if some other code
+      calls chdir().
+
+0.04  Mon Nov 26 13:36:24 EST 2001  *UNRELEASED*
+    * The magic chdir() is *gone*
+    * Now works back to 5.004
+
+0.03  Mon Sep  3 20:10:15 EDT 2001
+    * chdir() is being deprecated and will be removed next version!
+    - Gave credit to Abigail and Bryan
+
+0.02  Mon Sep  3 19:51:02 EDT 2001
+    * Added $CWD
+    - chdir() with no args works
+
+0.01  Fri Aug 31 21:15:25 EDT 2001
+    * HA!  It works!
+
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..68fb9aa
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,379 @@
+This software is copyright (c) 2016 by Michael G. Schwern and David Golden.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+Terms of the Perl programming language system itself
+
+a) the GNU General Public License as published by the Free
+   Software Foundation; either version 1, or (at your option) any
+   later version, or
+b) the "Artistic License"
+
+--- The GNU General Public License, Version 1, February 1989 ---
+
+This software is Copyright (c) 2016 by Michael G. Schwern and David Golden.
+
+This is free software, licensed under:
+
+  The GNU General Public License, Version 1, February 1989
+
+                    GNU GENERAL PUBLIC LICENSE
+                     Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The license agreements of most software companies try to keep users
+at the mercy of those companies.  By contrast, our General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of a such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must tell them their rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any program or other work which
+contains a notice placed by the copyright holder saying it may be
+distributed under the terms of this General Public License.  The
+"Program", below, refers to any such program or work, and a "work based
+on the Program" means either the Program or any work containing the
+Program or a portion of it, either verbatim or with modifications.  Each
+licensee is addressed as "you".
+
+  1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program.  You may charge a fee for the physical act of
+transferring a copy.
+
+  2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+    a) cause the modified files to carry prominent notices stating that
+    you changed the files and the date of any change; and
+
+    b) cause the whole of any work that you distribute or publish, that
+    in whole or in part contains the Program or any part thereof, either
+    with or without modifications, to be licensed at no charge to all
+    third parties under the terms of this General Public License (except
+    that you may choose to grant warranty protection to some or all
+    third parties, at your option).
+
+    c) If the modified program normally reads commands interactively when
+    run, you must cause it, when started running for such interactive use
+    in the simplest and most usual way, to print or display an
+    announcement including an appropriate copyright notice and a notice
+    that there is no warranty (or else, saying that you provide a
+    warranty) and that users may redistribute the program under these
+    conditions, and telling the user how to view a copy of this General
+    Public License.
+
+    d) You may charge a fee for the physical act of transferring a
+    copy, and you may at your option offer warranty protection in
+    exchange for a fee.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+
+  3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+    a) accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    b) accompany it with a written offer, valid for at least three
+    years, to give any third party free (except for a nominal charge
+    for the cost of distribution) a complete machine-readable copy of the
+    corresponding source code, to be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    c) accompany it with the information you received as to where the
+    corresponding source code may be obtained.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it.  For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+  4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License.  However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+  5. By copying, distributing or modifying the Program (or any work based
+on the Program) you indicate your acceptance of this license to do so,
+and all its terms and conditions.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these
+terms and conditions.  You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein.
+
+  7. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of the license which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+  8. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+        Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+  To do so, attach the following notices to the program.  It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 1, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19xx name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License.  Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  program `Gnomovision' (a program to direct compilers to make passes
+  at assemblers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
+--- The Artistic License 1.0 ---
+
+This software is Copyright (c) 2016 by Michael G. Schwern and David Golden.
+
+This is free software, licensed under:
+
+  The Artistic License 1.0
+
+The Artistic License
+
+Preamble
+
+The intent of this document is to state the conditions under which a Package
+may be copied, such that the Copyright Holder maintains some semblance of
+artistic control over the development of the package, while giving the users of
+the package the right to use and distribute the Package in a more-or-less
+customary fashion, plus the right to make reasonable modifications.
+
+Definitions:
+
+  - "Package" refers to the collection of files distributed by the Copyright
+    Holder, and derivatives of that collection of files created through
+    textual modification. 
+  - "Standard Version" refers to such a Package if it has not been modified,
+    or has been modified in accordance with the wishes of the Copyright
+    Holder. 
+  - "Copyright Holder" is whoever is named in the copyright or copyrights for
+    the package. 
+  - "You" is you, if you're thinking about copying or distributing this Package.
+  - "Reasonable copying fee" is whatever you can justify on the basis of media
+    cost, duplication charges, time of people involved, and so on. (You will
+    not be required to justify it to the Copyright Holder, but only to the
+    computing community at large as a market that must bear the fee.) 
+  - "Freely Available" means that no fee is charged for the item itself, though
+    there may be fees involved in handling the item. It also means that
+    recipients of the item may redistribute it under the same conditions they
+    received it. 
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications derived
+from the Public Domain or from the Copyright Holder. A Package modified in such
+a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided that
+you insert a prominent notice in each changed file stating how and when you
+changed that file, and provided that you do at least ONE of the following:
+
+  a) place your modifications in the Public Domain or otherwise make them
+     Freely Available, such as by posting said modifications to Usenet or an
+     equivalent medium, or placing the modifications on a major archive site
+     such as ftp.uu.net, or by allowing the Copyright Holder to include your
+     modifications in the Standard Version of the Package.
+
+  b) use the modified Package only within your corporation or organization.
+
+  c) rename any non-standard executables so the names do not conflict with
+     standard executables, which must also be provided, and provide a separate
+     manual page for each non-standard executable that clearly documents how it
+     differs from the Standard Version.
+
+  d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or executable
+form, provided that you do at least ONE of the following:
+
+  a) distribute a Standard Version of the executables and library files,
+     together with instructions (in the manual page or equivalent) on where to
+     get the Standard Version.
+
+  b) accompany the distribution with the machine-readable source of the Package
+     with your modifications.
+
+  c) accompany any non-standard executables with their corresponding Standard
+     Version executables, giving the non-standard executables non-standard
+     names, and clearly documenting the differences in manual pages (or
+     equivalent), together with instructions on where to get the Standard
+     Version.
+
+  d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package.  You may charge any fee you choose for support of this Package. You
+may not charge a fee for this Package itself. However, you may distribute this
+Package in aggregate with other (possibly commercial) programs as part of a
+larger (possibly commercial) software distribution provided that you do not
+advertise this Package as a product of your own.
+
+6. The scripts and library files supplied as input to or produced as output
+from the programs of this Package do not automatically fall under the copyright
+of this Package, but belong to whomever generated them, and may be sold
+commercially, and may be aggregated with this Package.
+
+7. C or perl subroutines supplied by you and linked into this Package shall not
+be considered part of this Package.
+
+8. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+The End
+
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..db72938
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,32 @@
+# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.008.
+CONTRIBUTING.mkdn
+Changes
+LICENSE
+MANIFEST
+META.json
+META.yml
+Makefile.PL
+README
+cpanfile
+dist.ini
+examples/chdir-example.pl
+lib/File/chdir.pm
+perlcritic.rc
+t/00-report-prereqs.dd
+t/00-report-prereqs.t
+t/array.t
+t/chdir.t
+t/delete-array.t
+t/lib/dummy.txt
+t/nested.t
+t/newline.t
+t/var.t
+xt/author/00-compile.t
+xt/author/critic.t
+xt/author/pod-coverage.t
+xt/author/pod-spell.t
+xt/author/pod-syntax.t
+xt/author/portability.t
+xt/author/test-version.t
+xt/release/distmeta.t
+xt/release/minimum-version.t
diff --git a/META.json b/META.json
new file mode 100644 (file)
index 0000000..077b894
--- /dev/null
+++ b/META.json
@@ -0,0 +1,118 @@
+{
+   "abstract" : "a more sensible way to change directories",
+   "author" : [
+      "David Golden <dagolden@cpan.org>",
+      "Michael G. Schwern <schwern@pobox.com>"
+   ],
+   "dynamic_config" : 0,
+   "generated_by" : "Dist::Zilla version 6.008, CPAN::Meta::Converter version 2.150010",
+   "license" : [
+      "perl_5"
+   ],
+   "meta-spec" : {
+      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
+      "version" : 2
+   },
+   "name" : "File-chdir",
+   "no_index" : {
+      "directory" : [
+         "corpus",
+         "examples",
+         "t",
+         "xt"
+      ],
+      "package" : [
+         "DB"
+      ]
+   },
+   "prereqs" : {
+      "configure" : {
+         "requires" : {
+            "ExtUtils::MakeMaker" : "6.17",
+            "perl" : "5.006"
+         }
+      },
+      "develop" : {
+         "requires" : {
+            "Dist::Zilla" : "5",
+            "Dist::Zilla::PluginBundle::DAGOLDEN" : "0.072",
+            "English" : "0",
+            "File::Spec" : "0",
+            "File::Temp" : "0",
+            "IO::Handle" : "0",
+            "IPC::Open3" : "0",
+            "Pod::Coverage::TrustPod" : "0",
+            "Pod::Wordlist" : "0",
+            "Software::License::Perl_5" : "0",
+            "Test::CPAN::Meta" : "0",
+            "Test::More" : "0",
+            "Test::Pod" : "1.41",
+            "Test::Pod::Coverage" : "1.08",
+            "Test::Portability::Files" : "0",
+            "Test::Spelling" : "0.12",
+            "Test::Version" : "1",
+            "blib" : "1.01",
+            "perl" : "5.006",
+            "warnings" : "0"
+         }
+      },
+      "runtime" : {
+         "requires" : {
+            "Carp" : "0",
+            "Cwd" : "3.16",
+            "Exporter" : "0",
+            "File::Spec::Functions" : "3.27",
+            "perl" : "5.006",
+            "strict" : "0",
+            "vars" : "0"
+         }
+      },
+      "test" : {
+         "recommends" : {
+            "CPAN::Meta" : "2.120900"
+         },
+         "requires" : {
+            "ExtUtils::MakeMaker" : "0",
+            "File::Spec" : "0",
+            "Test::More" : "0",
+            "perl" : "5.006",
+            "warnings" : "0"
+         }
+      }
+   },
+   "provides" : {
+      "File::chdir" : {
+         "file" : "lib/File/chdir.pm",
+         "version" : "0.1011"
+      },
+      "File::chdir::ARRAY" : {
+         "file" : "lib/File/chdir.pm",
+         "version" : "0.1011"
+      },
+      "File::chdir::SCALAR" : {
+         "file" : "lib/File/chdir.pm",
+         "version" : "0.1011"
+      }
+   },
+   "release_status" : "stable",
+   "resources" : {
+      "bugtracker" : {
+         "web" : "https://github.com/dagolden/File-chdir/issues"
+      },
+      "homepage" : "https://github.com/dagolden/File-chdir",
+      "repository" : {
+         "type" : "git",
+         "url" : "https://github.com/dagolden/File-chdir.git",
+         "web" : "https://github.com/dagolden/File-chdir"
+      }
+   },
+   "version" : "0.1011",
+   "x_authority" : "cpan:DAGOLDEN",
+   "x_contributors" : [
+      "David Golden <xdg@xdg.me>",
+      "Joel Berger <joel.a.berger@gmail.com>",
+      "Philippe Bruhat (BooK) <book@cpan.org>"
+   ],
+   "x_serialization_backend" : "Cpanel::JSON::XS version 3.0213"
+}
+
diff --git a/META.yml b/META.yml
new file mode 100644 (file)
index 0000000..6166773
--- /dev/null
+++ b/META.yml
@@ -0,0 +1,58 @@
+---
+abstract: 'a more sensible way to change directories'
+author:
+  - 'David Golden <dagolden@cpan.org>'
+  - 'Michael G. Schwern <schwern@pobox.com>'
+build_requires:
+  ExtUtils::MakeMaker: '0'
+  File::Spec: '0'
+  Test::More: '0'
+  perl: '5.006'
+  warnings: '0'
+configure_requires:
+  ExtUtils::MakeMaker: '6.17'
+  perl: '5.006'
+dynamic_config: 0
+generated_by: 'Dist::Zilla version 6.008, CPAN::Meta::Converter version 2.150010'
+license: perl
+meta-spec:
+  url: http://module-build.sourceforge.net/META-spec-v1.4.html
+  version: '1.4'
+name: File-chdir
+no_index:
+  directory:
+    - corpus
+    - examples
+    - t
+    - xt
+  package:
+    - DB
+provides:
+  File::chdir:
+    file: lib/File/chdir.pm
+    version: '0.1011'
+  File::chdir::ARRAY:
+    file: lib/File/chdir.pm
+    version: '0.1011'
+  File::chdir::SCALAR:
+    file: lib/File/chdir.pm
+    version: '0.1011'
+requires:
+  Carp: '0'
+  Cwd: '3.16'
+  Exporter: '0'
+  File::Spec::Functions: '3.27'
+  perl: '5.006'
+  strict: '0'
+  vars: '0'
+resources:
+  bugtracker: https://github.com/dagolden/File-chdir/issues
+  homepage: https://github.com/dagolden/File-chdir
+  repository: https://github.com/dagolden/File-chdir.git
+version: '0.1011'
+x_authority: cpan:DAGOLDEN
+x_contributors:
+  - 'David Golden <xdg@xdg.me>'
+  - 'Joel Berger <joel.a.berger@gmail.com>'
+  - 'Philippe Bruhat (BooK) <book@cpan.org>'
+x_serialization_backend: 'YAML::Tiny version 1.69'
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644 (file)
index 0000000..ac9d522
--- /dev/null
@@ -0,0 +1,63 @@
+# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.008.
+use strict;
+use warnings;
+
+use 5.006;
+
+use ExtUtils::MakeMaker 6.17;
+
+my %WriteMakefileArgs = (
+  "ABSTRACT" => "a more sensible way to change directories",
+  "AUTHOR" => "David Golden <dagolden\@cpan.org>, Michael G. Schwern <schwern\@pobox.com>",
+  "CONFIGURE_REQUIRES" => {
+    "ExtUtils::MakeMaker" => "6.17"
+  },
+  "DISTNAME" => "File-chdir",
+  "LICENSE" => "perl",
+  "MIN_PERL_VERSION" => "5.006",
+  "NAME" => "File::chdir",
+  "PREREQ_PM" => {
+    "Carp" => 0,
+    "Cwd" => "3.16",
+    "Exporter" => 0,
+    "File::Spec::Functions" => "3.27",
+    "strict" => 0,
+    "vars" => 0
+  },
+  "TEST_REQUIRES" => {
+    "ExtUtils::MakeMaker" => 0,
+    "File::Spec" => 0,
+    "Test::More" => 0,
+    "warnings" => 0
+  },
+  "VERSION" => "0.1011",
+  "test" => {
+    "TESTS" => "t/*.t"
+  }
+);
+
+
+my %FallbackPrereqs = (
+  "Carp" => 0,
+  "Cwd" => "3.16",
+  "Exporter" => 0,
+  "ExtUtils::MakeMaker" => 0,
+  "File::Spec" => 0,
+  "File::Spec::Functions" => "3.27",
+  "Test::More" => 0,
+  "strict" => 0,
+  "vars" => 0,
+  "warnings" => 0
+);
+
+
+unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) {
+  delete $WriteMakefileArgs{TEST_REQUIRES};
+  delete $WriteMakefileArgs{BUILD_REQUIRES};
+  $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs;
+}
+
+delete $WriteMakefileArgs{CONFIGURE_REQUIRES}
+  unless eval { ExtUtils::MakeMaker->VERSION(6.52) };
+
+WriteMakefile(%WriteMakefileArgs);
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..ad422c8
--- /dev/null
+++ b/README
@@ -0,0 +1,231 @@
+NAME
+    File::chdir - a more sensible way to change directories
+
+VERSION
+    version 0.1011
+
+SYNOPSIS
+      use File::chdir;
+
+      $CWD = "/foo/bar";     # now in /foo/bar
+      {
+          local $CWD = "/moo/baz";  # now in /moo/baz
+          ...
+      }
+
+      # still in /foo/bar!
+
+DESCRIPTION
+    Perl's "chdir()" has the unfortunate problem of being very, very, very
+    global. If any part of your program calls "chdir()" or if any library
+    you use calls "chdir()", it changes the current working directory for
+    the *whole* program.
+
+    This sucks.
+
+    File::chdir gives you an alternative, $CWD and @CWD. These two variables
+    combine all the power of "chdir()", File::Spec and Cwd.
+
+$CWD
+    Use the $CWD variable instead of "chdir()" and Cwd.
+
+        use File::chdir;
+        $CWD = $dir;  # just like chdir($dir)!
+        print $CWD;   # prints the current working directory
+
+    It can be localized, and it does the right thing.
+
+        $CWD = "/foo";      # it's /foo out here.
+        {
+            local $CWD = "/bar";  # /bar in here
+        }
+        # still /foo out here!
+
+    $CWD always returns the absolute path in the native form for the
+    operating system.
+
+    $CWD and normal "chdir()" work together just fine.
+
+@CWD
+    @CWD represents the current working directory as an array, each
+    directory in the path is an element of the array. This can often make
+    the directory easier to manipulate, and you don't have to fumble with
+    "File::Spec->splitpath" and "File::Spec->catdir" to make portable code.
+
+      # Similar to chdir("/usr/local/src/perl")
+      @CWD = qw(usr local src perl);
+
+    pop, push, shift, unshift and splice all work. pop and push are probably
+    the most useful.
+
+      pop @CWD;                 # same as chdir(File::Spec->updir)
+      push @CWD, 'some_dir'     # same as chdir('some_dir')
+
+    @CWD and $CWD both work fine together.
+
+    *NOTE* Due to a perl bug you can't localize @CWD. See "CAVEATS" for a
+    work around.
+
+EXAMPLES
+    (We omit the "use File::chdir" from these examples for terseness)
+
+    Here's $CWD instead of "chdir()":
+
+        $CWD = 'foo';           # chdir('foo')
+
+    and now instead of Cwd.
+
+        print $CWD;             # use Cwd;  print Cwd::abs_path
+
+    you can even do zsh style "cd foo bar"
+
+        $CWD = '/usr/local/foo';
+        $CWD =~ s/usr/var/;
+
+    if you want to localize that, make sure you get the parens right
+
+        {
+            (local $CWD) =~ s/usr/var/;
+            ...
+        }
+
+    It's most useful for writing polite subroutines which don't leave the
+    program in some strange directory:
+
+        sub foo {
+            local $CWD = 'some/other/dir';
+            ...do your work...
+        }
+
+    which is much simpler than the equivalent:
+
+        sub foo {
+            use Cwd;
+            my $orig_dir = Cwd::getcwd;
+            chdir('some/other/dir');
+
+            ...do your work...
+
+            chdir($orig_dir);
+        }
+
+    @CWD comes in handy when you want to start moving up and down the
+    directory hierarchy in a cross-platform manner without having to use
+    File::Spec.
+
+        pop @CWD;                   # chdir(File::Spec->updir);
+        push @CWD, 'some', 'dir'    # chdir(File::Spec->catdir(qw(some dir)));
+
+    You can easily change your parent directory:
+
+        # chdir from /some/dir/bar/moo to /some/dir/foo/moo
+        $CWD[-2] = 'foo';
+
+CAVEATS
+  "local @CWD" does not work.
+    "local @CWD" will not localize @CWD. This is a bug in Perl, you can't
+    localize tied arrays. As a work around localizing $CWD will effectively
+    localize @CWD.
+
+        {
+            local $CWD;
+            pop @CWD;
+            ...
+        }
+
+  Assigning to @CWD calls "chdir()" for each element
+        @CWD = qw/a b c d/;
+
+    Internally, Perl clears @CWD and assigns each element in turn. Thus,
+    this code above will do this:
+
+        chdir 'a';
+        chdir 'a/b';
+        chdir 'a/b/c';
+        chdir 'a/b/c/d';
+
+    Generally, avoid assigning to @CWD and just use push and pop instead.
+
+  Volumes not handled
+    There is currently no way to change the current volume via File::chdir.
+
+NOTES
+    $CWD returns the current directory using native path separators, i.e.
+    "\" on Win32. This ensures that $CWD will compare correctly with
+    directories created using File::Spec. For example:
+
+        my $working_dir = File::Spec->catdir( $CWD, "foo" );
+        $CWD = $working_dir;
+        doing_stuff_might_chdir();
+        is( $CWD, $working_dir, "back to original working_dir?" );
+
+    Deleting the last item of @CWD will act like a pop. Deleting from the
+    middle will throw an exception.
+
+        delete @CWD[-1]; # OK
+        delete @CWD[-2]; # Dies
+
+    What should %CWD do? Something with volumes?
+
+        # chdir to C:\Program Files\Sierra\Half Life ?
+        $CWD{C} = '\\Program Files\\Sierra\\Half Life';
+
+DIAGNOSTICS
+    If an error is encountered when changing $CWD or @CWD, one of the
+    following exceptions will be thrown:
+
+    * ~Can't delete except at the end of @CWD~ * ~Failed to change directory
+    to '$dir'~
+
+HISTORY
+    Michael wanted "local chdir" to work. p5p didn't. But it wasn't over!
+    Was it over when the Germans bombed Pearl Harbor? Hell, no!
+
+    Abigail and/or Bryan Warnock suggested the $CWD thing (Michael forgets
+    which). They were right.
+
+    The "chdir()" override was eliminated in 0.04.
+
+    David became co-maintainer with 0.06_01 to fix some chronic Win32 path
+    bugs.
+
+    As of 0.08, if changing $CWD or @CWD fails to change the directory, an
+    error will be thrown.
+
+SEE ALSO
+    File::pushd, File::Spec, Cwd, "chdir" in perlfunc, "Animal House"
+    <http://www.imdb.com/title/tt0077975/quotes>
+
+SUPPORT
+  Bugs / Feature Requests
+    Please report any bugs or feature requests through the issue tracker at
+    <https://github.com/dagolden/File-chdir/issues>. You will be notified
+    automatically of any progress on your issue.
+
+  Source Code
+    This is open source software. The code repository is available for
+    public review and contribution under the terms of the license.
+
+    <https://github.com/dagolden/File-chdir>
+
+      git clone https://github.com/dagolden/File-chdir.git
+
+AUTHORS
+    *   David Golden <dagolden@cpan.org>
+
+    *   Michael G. Schwern <schwern@pobox.com>
+
+CONTRIBUTORS
+    *   David Golden <xdg@xdg.me>
+
+    *   Joel Berger <joel.a.berger@gmail.com>
+
+    *   Philippe Bruhat (BooK) <book@cpan.org>
+
+COPYRIGHT AND LICENSE
+    This software is copyright (c) 2016 by Michael G. Schwern and David
+    Golden.
+
+    This is free software; you can redistribute it and/or modify it under
+    the same terms as the Perl 5 programming language system itself.
+
diff --git a/cpanfile b/cpanfile
new file mode 100644 (file)
index 0000000..7edaee0
--- /dev/null
+++ b/cpanfile
@@ -0,0 +1,47 @@
+requires "Carp" => "0";
+requires "Cwd" => "3.16";
+requires "Exporter" => "0";
+requires "File::Spec::Functions" => "3.27";
+requires "perl" => "5.006";
+requires "strict" => "0";
+requires "vars" => "0";
+
+on 'test' => sub {
+  requires "ExtUtils::MakeMaker" => "0";
+  requires "File::Spec" => "0";
+  requires "Test::More" => "0";
+  requires "perl" => "5.006";
+  requires "warnings" => "0";
+};
+
+on 'test' => sub {
+  recommends "CPAN::Meta" => "2.120900";
+};
+
+on 'configure' => sub {
+  requires "ExtUtils::MakeMaker" => "6.17";
+  requires "perl" => "5.006";
+};
+
+on 'develop' => sub {
+  requires "Dist::Zilla" => "5";
+  requires "Dist::Zilla::PluginBundle::DAGOLDEN" => "0.072";
+  requires "English" => "0";
+  requires "File::Spec" => "0";
+  requires "File::Temp" => "0";
+  requires "IO::Handle" => "0";
+  requires "IPC::Open3" => "0";
+  requires "Pod::Coverage::TrustPod" => "0";
+  requires "Pod::Wordlist" => "0";
+  requires "Software::License::Perl_5" => "0";
+  requires "Test::CPAN::Meta" => "0";
+  requires "Test::More" => "0";
+  requires "Test::Pod" => "1.41";
+  requires "Test::Pod::Coverage" => "1.08";
+  requires "Test::Portability::Files" => "0";
+  requires "Test::Spelling" => "0.12";
+  requires "Test::Version" => "1";
+  requires "blib" => "1.01";
+  requires "perl" => "5.006";
+  requires "warnings" => "0";
+};
diff --git a/dist.ini b/dist.ini
new file mode 100644 (file)
index 0000000..3b5aad3
--- /dev/null
+++ b/dist.ini
@@ -0,0 +1,9 @@
+name = File-chdir
+author = David Golden <dagolden@cpan.org>
+author = Michael G. Schwern <schwern@pobox.com>
+license = Perl_5
+copyright_holder = Michael G. Schwern and David Golden
+
+[@DAGOLDEN]
+:version = 0.072
+stopwords = Warnock
diff --git a/examples/chdir-example.pl b/examples/chdir-example.pl
new file mode 100644 (file)
index 0000000..d9eed03
--- /dev/null
@@ -0,0 +1,21 @@
+use strict;
+use warnings;
+use File::chdir;
+
+mkdir "foo";
+
+$CWD = "foo"; # now in foo/
+
+mkdir "bar";
+
+{
+    local $CWD = "bar";  # now in foo/bar/
+}
+
+# back to foo
+rmdir "bar";
+
+pop @CWD; # now in original directory
+
+rmdir "foo";
+
diff --git a/lib/File/chdir.pm b/lib/File/chdir.pm
new file mode 100644 (file)
index 0000000..c51f68b
--- /dev/null
@@ -0,0 +1,474 @@
+package File::chdir;
+use 5.004;
+use strict;
+use vars qw($VERSION @ISA @EXPORT $CWD @CWD);
+# ABSTRACT: a more sensible way to change directories
+
+our $VERSION = '0.1011';
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(*CWD);
+
+use Carp;
+use Cwd 3.16;
+use File::Spec::Functions 3.27 qw/canonpath splitpath catpath splitdir catdir/;
+
+tie $CWD, 'File::chdir::SCALAR' or die "Can't tie \$CWD";
+tie @CWD, 'File::chdir::ARRAY'  or die "Can't tie \@CWD";
+
+sub _abs_path {
+    # Otherwise we'll never work under taint mode.
+    my($cwd) = Cwd::getcwd =~ /(.*)/s;
+    # Run through File::Spec, since everything else uses it
+    return canonpath($cwd);
+}
+
+# splitpath but also split directory
+sub _split_cwd {
+    my ($vol, $dir) = splitpath(_abs_path, 1);
+    my @dirs = splitdir( $dir );
+    shift @dirs; # get rid of leading empty "root" directory
+    return ($vol, @dirs);
+}
+
+# catpath, but take list of directories
+# restore the empty root dir and provide an empty file to avoid warnings
+sub _catpath {
+    my ($vol, @dirs) = @_;
+    return catpath($vol, catdir(q{}, @dirs), q{});
+}
+
+sub _chdir {
+    # Untaint target directory
+    my ($new_dir) = $_[0] =~ /(.*)/s;
+
+    local $Carp::CarpLevel = $Carp::CarpLevel + 1;
+    if ( ! CORE::chdir($new_dir) ) {
+        croak "Failed to change directory to '$new_dir': $!";
+    };
+    return 1;
+}
+
+{
+    package File::chdir::SCALAR;
+    use Carp;
+
+    BEGIN {
+        *_abs_path = \&File::chdir::_abs_path;
+        *_chdir = \&File::chdir::_chdir;
+        *_split_cwd = \&File::chdir::_split_cwd;
+        *_catpath = \&File::chdir::_catpath;
+    }
+
+    sub TIESCALAR {
+        bless [], $_[0];
+    }
+
+    # To be safe, in case someone chdir'd out from under us, we always
+    # check the Cwd explicitly.
+    sub FETCH {
+        return _abs_path;
+    }
+
+    sub STORE {
+        return unless defined $_[1];
+        _chdir($_[1]);
+    }
+}
+
+
+{
+    package File::chdir::ARRAY;
+    use Carp;
+
+    BEGIN {
+        *_abs_path = \&File::chdir::_abs_path;
+        *_chdir = \&File::chdir::_chdir;
+        *_split_cwd = \&File::chdir::_split_cwd;
+        *_catpath = \&File::chdir::_catpath;
+    }
+
+    sub TIEARRAY {
+        bless {}, $_[0];
+    }
+
+    sub FETCH {
+        my($self, $idx) = @_;
+        my ($vol, @cwd) = _split_cwd;
+        return $cwd[$idx];
+    }
+
+    sub STORE {
+        my($self, $idx, $val) = @_;
+
+        my ($vol, @cwd) = _split_cwd;
+        if( $self->{Cleared} ) {
+            @cwd = ();
+            $self->{Cleared} = 0;
+        }
+
+        $cwd[$idx] = $val;
+        my $dir = _catpath($vol,@cwd);
+
+        _chdir($dir);
+        return $cwd[$idx];
+    }
+
+    sub FETCHSIZE {
+        my ($vol, @cwd) = _split_cwd;
+        return scalar @cwd;
+    }
+    sub STORESIZE {}
+
+    sub PUSH {
+        my($self) = shift;
+
+        my $dir = _catpath(_split_cwd, @_);
+        _chdir($dir);
+        return $self->FETCHSIZE;
+    }
+
+    sub POP {
+        my($self) = shift;
+
+        my ($vol, @cwd) = _split_cwd;
+        my $popped = pop @cwd;
+        my $dir = _catpath($vol,@cwd);
+        _chdir($dir);
+        return $popped;
+    }
+
+    sub SHIFT {
+        my($self) = shift;
+
+        my ($vol, @cwd) = _split_cwd;
+        my $shifted = shift @cwd;
+        my $dir = _catpath($vol,@cwd);
+        _chdir($dir);
+        return $shifted;
+    }
+
+    sub UNSHIFT {
+        my($self) = shift;
+
+        my ($vol, @cwd) = _split_cwd;
+        my $dir = _catpath($vol, @_, @cwd);
+        _chdir($dir);
+        return $self->FETCHSIZE;
+    }
+
+    sub CLEAR  {
+        my($self) = shift;
+        $self->{Cleared} = 1;
+    }
+
+    sub SPLICE {
+        my $self = shift;
+        my $offset = shift || 0;
+        my $len = shift || $self->FETCHSIZE - $offset;
+        my @new_dirs = @_;
+
+        my ($vol, @cwd) = _split_cwd;
+        my @orig_dirs = splice @cwd, $offset, $len, @new_dirs;
+        my $dir = _catpath($vol, @cwd);
+        _chdir($dir);
+        return @orig_dirs;
+    }
+
+    sub EXTEND { }
+    sub EXISTS {
+        my($self, $idx) = @_;
+        return $self->FETCHSIZE >= $idx ? 1 : 0;
+    }
+
+    sub DELETE {
+        my($self, $idx) = @_;
+        croak "Can't delete except at the end of \@CWD"
+            if $idx < $self->FETCHSIZE - 1;
+        local $Carp::CarpLevel = $Carp::CarpLevel + 1;
+        $self->POP;
+    }
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+File::chdir - a more sensible way to change directories
+
+=head1 VERSION
+
+version 0.1011
+
+=head1 SYNOPSIS
+
+  use File::chdir;
+
+  $CWD = "/foo/bar";     # now in /foo/bar
+  {
+      local $CWD = "/moo/baz";  # now in /moo/baz
+      ...
+  }
+
+  # still in /foo/bar!
+
+=head1 DESCRIPTION
+
+Perl's C<chdir()> has the unfortunate problem of being very, very, very
+global.  If any part of your program calls C<chdir()> or if any library
+you use calls C<chdir()>, it changes the current working directory for
+the *whole* program.
+
+This sucks.
+
+File::chdir gives you an alternative, C<$CWD> and C<@CWD>.  These two
+variables combine all the power of C<chdir()>, L<File::Spec> and L<Cwd>.
+
+=head1 $CWD
+
+Use the C<$CWD> variable instead of C<chdir()> and Cwd.
+
+    use File::chdir;
+    $CWD = $dir;  # just like chdir($dir)!
+    print $CWD;   # prints the current working directory
+
+It can be localized, and it does the right thing.
+
+    $CWD = "/foo";      # it's /foo out here.
+    {
+        local $CWD = "/bar";  # /bar in here
+    }
+    # still /foo out here!
+
+C<$CWD> always returns the absolute path in the native form for the
+operating system.
+
+C<$CWD> and normal C<chdir()> work together just fine.
+
+=head1 @CWD
+
+C<@CWD> represents the current working directory as an array, each
+directory in the path is an element of the array.  This can often make
+the directory easier to manipulate, and you don't have to fumble with
+C<< File::Spec->splitpath >> and C<< File::Spec->catdir >> to make portable code.
+
+  # Similar to chdir("/usr/local/src/perl")
+  @CWD = qw(usr local src perl);
+
+pop, push, shift, unshift and splice all work.  pop and push are
+probably the most useful.
+
+  pop @CWD;                 # same as chdir(File::Spec->updir)
+  push @CWD, 'some_dir'     # same as chdir('some_dir')
+
+C<@CWD> and C<$CWD> both work fine together.
+
+*NOTE* Due to a perl bug you can't localize C<@CWD>.  See L</CAVEATS> for a work around.
+
+=head1 EXAMPLES
+
+(We omit the C<use File::chdir> from these examples for terseness)
+
+Here's C<$CWD> instead of C<chdir()>:
+
+    $CWD = 'foo';           # chdir('foo')
+
+and now instead of Cwd.
+
+    print $CWD;             # use Cwd;  print Cwd::abs_path
+
+you can even do zsh style C<cd foo bar>
+
+    $CWD = '/usr/local/foo';
+    $CWD =~ s/usr/var/;
+
+if you want to localize that, make sure you get the parens right
+
+    {
+        (local $CWD) =~ s/usr/var/;
+        ...
+    }
+
+It's most useful for writing polite subroutines which don't leave the
+program in some strange directory:
+
+    sub foo {
+        local $CWD = 'some/other/dir';
+        ...do your work...
+    }
+
+which is much simpler than the equivalent:
+
+    sub foo {
+        use Cwd;
+        my $orig_dir = Cwd::getcwd;
+        chdir('some/other/dir');
+
+        ...do your work...
+
+        chdir($orig_dir);
+    }
+
+C<@CWD> comes in handy when you want to start moving up and down the
+directory hierarchy in a cross-platform manner without having to use
+File::Spec.
+
+    pop @CWD;                   # chdir(File::Spec->updir);
+    push @CWD, 'some', 'dir'    # chdir(File::Spec->catdir(qw(some dir)));
+
+You can easily change your parent directory:
+
+    # chdir from /some/dir/bar/moo to /some/dir/foo/moo
+    $CWD[-2] = 'foo';
+
+=head1 CAVEATS
+
+=head2 C<local @CWD> does not work.
+
+C<local @CWD> will not localize C<@CWD>.  This is a bug in Perl, you
+can't localize tied arrays.  As a work around localizing $CWD will
+effectively localize @CWD.
+
+    {
+        local $CWD;
+        pop @CWD;
+        ...
+    }
+
+=head2 Assigning to C<@CWD> calls C<chdir()> for each element
+
+    @CWD = qw/a b c d/;
+
+Internally, Perl clears C<@CWD> and assigns each element in turn.  Thus, this
+code above will do this:
+
+    chdir 'a';
+    chdir 'a/b';
+    chdir 'a/b/c';
+    chdir 'a/b/c/d';
+
+Generally, avoid assigning to C<@CWD> and just use push and pop instead.
+
+=head2 Volumes not handled
+
+There is currently no way to change the current volume via File::chdir.
+
+=head1 NOTES
+
+C<$CWD> returns the current directory using native path separators, i.e. C<\>
+on Win32.  This ensures that C<$CWD> will compare correctly with directories
+created using File::Spec.  For example:
+
+    my $working_dir = File::Spec->catdir( $CWD, "foo" );
+    $CWD = $working_dir;
+    doing_stuff_might_chdir();
+    is( $CWD, $working_dir, "back to original working_dir?" );
+
+Deleting the last item of C<@CWD> will act like a pop.  Deleting from the
+middle will throw an exception.
+
+    delete @CWD[-1]; # OK
+    delete @CWD[-2]; # Dies
+
+What should %CWD do?  Something with volumes?
+
+    # chdir to C:\Program Files\Sierra\Half Life ?
+    $CWD{C} = '\\Program Files\\Sierra\\Half Life';
+
+=head1 DIAGNOSTICS
+
+If an error is encountered when changing C<$CWD> or C<@CWD>, one of
+the following exceptions will be thrown:
+
+* ~Can't delete except at the end of @CWD~
+* ~Failed to change directory to '$dir'~
+
+=head1 HISTORY
+
+Michael wanted C<local chdir> to work.  p5p didn't.  But it wasn't over!
+Was it over when the Germans bombed Pearl Harbor?  Hell, no!
+
+Abigail and/or Bryan Warnock suggested the C<$CWD> thing (Michael forgets
+which).  They were right.
+
+The C<chdir()> override was eliminated in 0.04.
+
+David became co-maintainer with 0.06_01 to fix some chronic
+Win32 path bugs.
+
+As of 0.08, if changing C<$CWD> or C<@CWD> fails to change the directory, an
+error will be thrown.
+
+=head1 SEE ALSO
+
+L<File::pushd>, L<File::Spec>, L<Cwd>, L<perlfunc/chdir>,
+"Animal House" L<http://www.imdb.com/title/tt0077975/quotes>
+
+=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
+
+=head1 SUPPORT
+
+=head2 Bugs / Feature Requests
+
+Please report any bugs or feature requests through the issue tracker
+at L<https://github.com/dagolden/File-chdir/issues>.
+You will be notified automatically of any progress on your issue.
+
+=head2 Source Code
+
+This is open source software.  The code repository is available for
+public review and contribution under the terms of the license.
+
+L<https://github.com/dagolden/File-chdir>
+
+  git clone https://github.com/dagolden/File-chdir.git
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+David Golden <dagolden@cpan.org>
+
+=item *
+
+Michael G. Schwern <schwern@pobox.com>
+
+=back
+
+=head1 CONTRIBUTORS
+
+=for stopwords David Golden Joel Berger Philippe Bruhat (BooK)
+
+=over 4
+
+=item *
+
+David Golden <xdg@xdg.me>
+
+=item *
+
+Joel Berger <joel.a.berger@gmail.com>
+
+=item *
+
+Philippe Bruhat (BooK) <book@cpan.org>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2016 by Michael G. Schwern and David Golden.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/perlcritic.rc b/perlcritic.rc
new file mode 100644 (file)
index 0000000..bcbbb45
--- /dev/null
@@ -0,0 +1,26 @@
+severity = 5
+verbose = 8
+
+[Variables::ProhibitPunctuationVars]
+allow = $@ $!
+
+[TestingAndDebugging::ProhibitNoStrict]
+allow = refs
+
+[Variables::ProhibitEvilVariables]
+variables = $DB::single
+
+# Turn these off
+[-BuiltinFunctions::ProhibitStringyEval]
+[-ControlStructures::ProhibitPostfixControls]
+[-ControlStructures::ProhibitUnlessBlocks]
+[-Documentation::RequirePodSections]
+[-InputOutput::ProhibitInteractiveTest]
+[-References::ProhibitDoubleSigils]
+[-RegularExpressions::RequireExtendedFormatting]
+[-InputOutput::ProhibitTwoArgOpen]
+[-Modules::ProhibitEvilModules]
+
+# Turn this on
+[Lax::ProhibitStringyEval::ExceptForRequire]
+
diff --git a/t/00-report-prereqs.dd b/t/00-report-prereqs.dd
new file mode 100644 (file)
index 0000000..c53e7ff
--- /dev/null
@@ -0,0 +1,57 @@
+do { my $x = {
+       'configure' => {
+                        'requires' => {
+                                        'ExtUtils::MakeMaker' => '6.17',
+                                        'perl' => '5.006'
+                                      }
+                      },
+       'develop' => {
+                      'requires' => {
+                                      'Dist::Zilla' => '5',
+                                      'Dist::Zilla::PluginBundle::DAGOLDEN' => '0.072',
+                                      'English' => '0',
+                                      'File::Spec' => '0',
+                                      'File::Temp' => '0',
+                                      'IO::Handle' => '0',
+                                      'IPC::Open3' => '0',
+                                      'Pod::Coverage::TrustPod' => '0',
+                                      'Pod::Wordlist' => '0',
+                                      'Software::License::Perl_5' => '0',
+                                      'Test::CPAN::Meta' => '0',
+                                      'Test::More' => '0',
+                                      'Test::Pod' => '1.41',
+                                      'Test::Pod::Coverage' => '1.08',
+                                      'Test::Portability::Files' => '0',
+                                      'Test::Spelling' => '0.12',
+                                      'Test::Version' => '1',
+                                      'blib' => '1.01',
+                                      'perl' => '5.006',
+                                      'warnings' => '0'
+                                    }
+                    },
+       'runtime' => {
+                      'requires' => {
+                                      'Carp' => '0',
+                                      'Cwd' => '3.16',
+                                      'Exporter' => '0',
+                                      'File::Spec::Functions' => '3.27',
+                                      'perl' => '5.006',
+                                      'strict' => '0',
+                                      'vars' => '0'
+                                    }
+                    },
+       'test' => {
+                   'recommends' => {
+                                     'CPAN::Meta' => '2.120900'
+                                   },
+                   'requires' => {
+                                   'ExtUtils::MakeMaker' => '0',
+                                   'File::Spec' => '0',
+                                   'Test::More' => '0',
+                                   'perl' => '5.006',
+                                   'warnings' => '0'
+                                 }
+                 }
+     };
+  $x;
+ }
\ No newline at end of file
diff --git a/t/00-report-prereqs.t b/t/00-report-prereqs.t
new file mode 100644 (file)
index 0000000..e338372
--- /dev/null
@@ -0,0 +1,183 @@
+#!perl
+
+use strict;
+use warnings;
+
+# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.025
+
+use Test::More tests => 1;
+
+use ExtUtils::MakeMaker;
+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_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 _max {
+    my $max = shift;
+    $max = ( $_ > $max ) ? $_ : $max for @_;
+    return $max;
+}
+
+sub _merge_prereqs {
+    my ($collector, $prereqs) = @_;
+
+    # 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 = qw(
+
+);
+
+my @exclude = qw(
+
+);
+
+# Add static prereqs to the included modules list
+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
+    && (my $meta = eval { CPAN::Meta->load_file($source) } )
+) {
+    $full_prereqs = _merge_prereqs($full_prereqs, $meta->prereqs);
+}
+else {
+    $source = 'static metadata';
+}
+
+my @full_reports;
+my @dep_errors;
+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)";
+                }
+            }
+        }
+
+        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 );
+
+            if ($type eq 'modules') {
+                splice @reports, 1, 0, ["-" x $ml, "", "-" x $hl];
+                push @full_reports, map { sprintf("    %*s %*s\n", -$ml, $_->[0], $hl, $_->[2]) } @reports;
+            }
+            else {
+                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 ( @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"
+    );
+}
+
+pass;
+
+# vim: ts=4 sts=4 sw=4 et:
diff --git a/t/array.t b/t/array.t
new file mode 100644 (file)
index 0000000..386c77e
--- /dev/null
+++ b/t/array.t
@@ -0,0 +1,184 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Test::More tests => 55;
+use File::Spec::Functions qw/canonpath splitdir catdir splitpath catpath/;
+use Cwd qw/getcwd/;
+
+BEGIN { use_ok('File::chdir') }
+
+#--------------------------------------------------------------------------#
+# Fixtures and utility subs
+#--------------------------------------------------------------------------#-
+
+# _catdir has OS-specific path separators so do the same for getcwd
+sub _getcwd { canonpath( getcwd ) }
+
+# reassemble
+sub _catpath {
+    my ($vol, @dirs) = @_;
+    return catpath( $vol, catdir(q{}, @dirs), q{} );
+}
+
+# get $vol here and use it later
+my ($vol,$cwd) = splitpath(canonpath(getcwd),1);
+
+# get directory list the way a user would use it -- without empty leading dir
+# as returned by splitdir;
+my @cwd = grep { length } splitdir($cwd);
+
+# Utility sub for checking cases
+sub _check_cwd {
+    # report failures at the calling line
+    local $Test::Builder::Level = $Test::Builder::Level + 1;
+    my $label = pop @_;
+    my @expect = @_;
+    is( _getcwd, _catpath($vol,@expect),       "$label works" );
+    ok( eq_array(\@CWD, [@expect]),      '... and value of @CWD is correct' );
+    is( $CWD, _catpath($vol,@expect),        '... and value of $CWD is correct' );
+}
+
+#--------------------------------------------------------------------------#-
+# Tying test
+#--------------------------------------------------------------------------#-
+
+ok( tied @CWD,      '@CWD is fit to be tied' );
+
+#--------------------------------------------------------------------------#
+# Assignment tests
+#--------------------------------------------------------------------------#
+
+# Non-local
+@CWD = (@cwd, 't');
+_check_cwd( @cwd, 't', 'Ordinary assignment');
+
+# Reset
+@CWD = @cwd;
+
+# Localized 
+{
+    # localizing tied arrays doesn't work, perl bug. :(
+    # this is a work around.
+    local $CWD;
+
+    @CWD = (@cwd, 't');
+    _check_cwd( @cwd, 't', 'Localized assignment' );
+}
+
+# Check that localizing $CWD/@CWD reverts properly
+_check_cwd( @cwd, 'Reset of localized assignment' );
+
+#--------------------------------------------------------------------------#
+# Push tests
+#--------------------------------------------------------------------------#
+
+# Non-local
+push @CWD, 't';
+_check_cwd( @cwd, 't', 'Ordinary push');
+
+# Reset
+@CWD = @cwd;
+
+# Localized 
+{
+    # localizing tied arrays doesn't work, perl bug. :(
+    # this is a work around.
+    local $CWD;
+
+    push @CWD, 't';
+    _check_cwd( @cwd, 't', 'Localized push' );
+}
+
+# Check that localizing $CWD/@CWD reverts properly
+_check_cwd( @cwd, 'Reset of localized push' );
+
+#--------------------------------------------------------------------------#
+# Pop tests
+#--------------------------------------------------------------------------#
+
+# Non-local
+my $popped_dir = pop @CWD;
+_check_cwd( @cwd[0 .. $#cwd-1], 'Ordinary pop');
+is( $popped_dir, $cwd[-1],          '... and pop returned popped dir' ); 
+
+# Reset
+@CWD = @cwd;
+
+# Localized 
+{
+    # localizing tied arrays doesn't work, perl bug. :(
+    # this is a work around.
+    local $CWD;
+
+    my $popped_dir = pop @CWD;
+    _check_cwd( @cwd[0 .. $#cwd-1], 'Localized pop');
+}
+
+# Check that localizing $CWD/@CWD reverts properly
+_check_cwd( @cwd, 'Reset of localized pop' );
+
+
+#--------------------------------------------------------------------------#
+# Splice tests
+#--------------------------------------------------------------------------#
+
+# Non-local
+my @spliced_dirs;
+
+# splice multiple dirs from end
+push @CWD, 't', 'lib';
+@spliced_dirs = splice @CWD, -2;
+_check_cwd( @cwd, 'Ordinary splice (from end)');
+is( @spliced_dirs, 2, '... and returns right number of dirs' );
+ok( eq_array(\@spliced_dirs, [qw/t lib/]), "... and they're correct" );
+
+# splice a single dir from the middle
+push @CWD, 't', 'lib';
+@spliced_dirs = splice @CWD, -2, 1;
+_check_cwd( @cwd, 'lib', 'Ordinary splice (from middle)');
+is( @spliced_dirs, 1, '... and returns right number of dirs' );
+ok( eq_array(\@spliced_dirs, ['t']), "... and it's correct" );
+
+# Reset
+@CWD = @cwd;
+
+# Localized 
+{
+    # localizing tied arrays doesn't work, perl bug. :(
+    # this is a work around.
+    local $CWD;
+
+    # splice multiple dirs from end
+    push @CWD, 't', 'lib';
+    @spliced_dirs = splice @CWD, -2;
+    _check_cwd( @cwd, 'Localized splice (from end)');
+    is( @spliced_dirs, 2, '... and returns right number of dirs' );
+    ok( eq_array(\@spliced_dirs, [qw/t lib/]), "... and they're correct" );
+
+    # splice a single dir from the middle
+    push @CWD, 't', 'lib';
+    @spliced_dirs = splice @CWD, -2, 1;
+    _check_cwd( @cwd, 'lib', 'Localized splice (from middle)');
+    is( @spliced_dirs, 1, '... and returns right number of dirs' );
+    ok( eq_array(\@spliced_dirs, ['t']), "... and it's correct" );
+}
+
+# Check that localizing $CWD/@CWD reverts properly
+_check_cwd( @cwd, 'Reset of localized splice' );
+
+#--------------------------------------------------------------------------#
+# Exceptions
+#--------------------------------------------------------------------------#
+
+
+# Change to invalid directory
+my $target = "doesnt_exist";
+eval { $CWD[@CWD] = $target };
+my $err = $@;
+ok( $err, 'Failure to chdir throws an error' );
+#_check_cwd( @cwd, 'Still in original directory' );
+
+my $missing_dir = quotemeta(File::Spec->catfile($CWD,$target));
+like( $err,  "/Failed to change directory to '$missing_dir'/", 
+        '... and the error message is correct');
+
diff --git a/t/chdir.t b/t/chdir.t
new file mode 100644 (file)
index 0000000..fbdd9e8
--- /dev/null
+++ b/t/chdir.t
@@ -0,0 +1,45 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Test::More tests => 6;
+use File::Spec::Functions qw/canonpath catdir/;
+use Cwd qw/getcwd/;
+
+BEGIN { use_ok('File::chdir') }
+
+# _catdir has OS-specific path separators so do the same for getcwd
+sub _getcwd { canonpath( getcwd ) }
+
+my($cwd) = _getcwd =~ /(.*)/;  # detaint otherwise nothing's gonna work
+
+# First, let's try normal chdir()
+{
+    chdir('t');
+    ::is( _getcwd, catdir($cwd,'t'), 'void chdir still works' );
+
+    chdir($cwd);    # reset
+
+    if( chdir('t') ) {
+        1;
+    }
+    else {
+        ::fail('chdir() failed completely in boolean context!');
+    }
+    ::is( _getcwd, catdir($cwd,'t'),  '  even in boolean context' );
+}
+
+::is( _getcwd, catdir($cwd,'t'), '  unneffected by blocks' );
+
+
+# Ok, reset ourself for the real test.
+chdir($cwd) or die $!;
+
+{
+    local $ENV{HOME} = 't';
+    chdir;
+    ::is( _getcwd, catdir($cwd, 't'), 'chdir() with no args' );
+    ::is( $CWD, catdir($cwd, 't'), '  $CWD follows' );
+}
+
+# Final chdir() back to the original or we confuse the debugger.
+chdir($cwd);
diff --git a/t/delete-array.t b/t/delete-array.t
new file mode 100644 (file)
index 0000000..2ebee00
--- /dev/null
@@ -0,0 +1,104 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use Test::More;
+
+BEGIN {
+    if ( $] < 5.006 ) {
+        plan skip_all => 'delete(@array) not available before Perl 5.6';
+    }
+    else {
+        plan tests => 15;
+    }
+}
+
+use File::Spec::Functions qw/canonpath splitdir catdir splitpath catpath/;
+use Cwd qw/getcwd/;
+
+BEGIN { use_ok('File::chdir') }
+
+#--------------------------------------------------------------------------#
+# Fixtures and utility subs
+#--------------------------------------------------------------------------#-
+
+# _catdir has OS-specific path separators so do the same for getcwd
+sub _getcwd { canonpath( getcwd ) }
+
+# reassemble
+sub _catpath {
+    my ($vol, @dirs) = @_;
+    return catpath( $vol, catdir(q{}, @dirs), q{} );
+}
+
+# get $vol here and use it later
+my ($vol,$cwd) = splitpath(canonpath(getcwd),1);
+
+# get directory list the way a user would use it -- without empty leading dir
+# as returned by splitdir;
+my @cwd = grep { length } splitdir($cwd);
+
+# Utility sub for checking cases
+sub _check_cwd {
+    # report failures at the calling line
+    local $Test::Builder::Level = $Test::Builder::Level + 1;
+    my $label = pop @_;
+    my @expect = @_;
+    is( _getcwd, _catpath($vol,@expect),       "$label works" );
+    ok( eq_array(\@CWD, [@expect]),      '... and value of @CWD is correct' );
+    is( $CWD, _catpath($vol,@expect),        '... and value of $CWD is correct' );
+}
+
+#--------------------------------------------------------------------------#-
+# Tying test
+#--------------------------------------------------------------------------#-
+
+ok( tied @CWD,      '@CWD is fit to be tied' );
+
+#--------------------------------------------------------------------------#
+# Delete tests - only from the end of the array (like popping)
+#--------------------------------------------------------------------------#
+
+SKIP: {
+    if ( $] < 5.006 ) {
+        skip 'delete(@array) not available before Perl 5.6', 13;
+    }
+
+    # Non-local
+    eval { delete $CWD[$#CWD] };
+    is( $@, '', "Ordinary delete from end of \@CWD lives" );
+    _check_cwd( @cwd[0 .. $#cwd-1], 'Ordinary delete from end of @CWD');
+
+    # Reset
+    @CWD = @cwd;
+
+    # Localized 
+    {
+        # localizing tied arrays doesn't work, perl bug. :(
+        # this is a work around.
+        local $CWD;
+
+        eval { delete $CWD[$#CWD] };
+        is( $@, '', "Ordinary delete from end of \@CWD lives" );
+        _check_cwd( @cwd[0 .. $#cwd-1], 'Ordinary delete from end of @CWD');
+
+    }
+    
+    # Exception: DELETE (middle of array)
+    {
+        local $CWD;
+        push @CWD, 't', 'lib';
+        eval { delete $CWD[-2] };
+        my $err = $@;
+        ok( $err, 'Deleting $CWD[-2] throws an error' );
+        like( $err,  "/Can't delete except at the end of \@CWD/", 
+            '... and the error message is correct');
+    }
+
+
+}
+
+# Check that localizing $CWD/@CWD reverts properly
+_check_cwd( @cwd, 'Reset of localized pop' );
+
+
diff --git a/t/lib/dummy.txt b/t/lib/dummy.txt
new file mode 100644 (file)
index 0000000..b0128ec
--- /dev/null
@@ -0,0 +1 @@
+Ensures git tracks 't/lib' as tests use that directory.
diff --git a/t/nested.t b/t/nested.t
new file mode 100644 (file)
index 0000000..38233dc
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env perl -w
+
+# Test that File::chdir works when multiple packages have nested, localized $CWD.
+
+use strict;
+use warnings;
+
+use Test::More;
+
+use File::chdir;
+
+my $original_cwd = $CWD.'';
+
+{
+    package Inner;
+    use File::chdir;
+
+    sub foo {
+        local $CWD = File::Spec->catdir($original_cwd, "lib");
+    }
+}
+
+
+{
+    package Outer;
+    use File::chdir;
+
+    sub bar {
+        local $CWD = File::Spec->catdir($original_cwd, "t");
+        Inner::foo();
+    }
+}
+
+
+Outer::bar();
+is $CWD, $original_cwd;
+
+
+done_testing;
diff --git a/t/newline.t b/t/newline.t
new file mode 100644 (file)
index 0000000..7455538
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/env perl -w
+
+use strict;
+use warnings;
+
+use Test::More;
+
+use File::chdir;
+use Cwd qw(getcwd);
+
+my $Orig_Cwd = $CWD;
+
+my $Test_Dir = "t/testdir$$\ntest";
+my $Can_mkdir_With_Newline = mkdir $Test_Dir;
+
+plan skip_all => "Can't make a directory with a newline in it" unless $Can_mkdir_With_Newline;
+
+{
+    local $CWD = $Test_Dir;
+    is $CWD, getcwd;
+}
+
+is $CWD, $Orig_Cwd;
+is getcwd, $Orig_Cwd;
+
+END {
+    chdir $Orig_Cwd;  # just in case
+    rmdir $Test_Dir;
+}
+
+done_testing;
diff --git a/t/var.t b/t/var.t
new file mode 100644 (file)
index 0000000..0e5d102
--- /dev/null
+++ b/t/var.t
@@ -0,0 +1,56 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Test::More tests => 13;
+use File::Spec::Functions qw/canonpath catdir/;
+use Cwd qw/getcwd/;
+
+BEGIN { use_ok('File::chdir') }
+
+# _catdir has OS-specific path separators so do the same for getcwd
+sub _getcwd { canonpath( getcwd ) }
+
+my $cwd = _getcwd;
+
+ok( tied $CWD,      '$CWD is fit to be tied' );
+
+# First, let's try unlocalized $CWD.
+{
+    $CWD = 't';
+    ::is( _getcwd, catdir($cwd,'t'), 'unlocalized $CWD works' );
+    ::is( $CWD,   catdir($cwd,'t'), '  $CWD set' );
+}
+
+::is( _getcwd, catdir($cwd,'t'), 'unlocalized $CWD unneffected by blocks' );
+::is( $CWD,   catdir($cwd,'t'), '  and still set' );
+
+
+# Ok, reset ourself for the real test.
+$CWD = $cwd;
+
+{
+    my $old_dir = $CWD;
+    local $CWD = "t";
+    ::is( $old_dir, $cwd,           '$CWD fetch works' );
+    ::is( _getcwd, catdir($cwd,'t'), 'localized $CWD works' );
+}
+
+::is( _getcwd, $cwd,                 '  and resets automatically!' );
+::is( $CWD,   $cwd,                 '  $CWD reset, too' );
+
+
+chdir('t');
+is( $CWD,   catdir($cwd,'t'),       'chdir() and $CWD work together' );
+
+#--------------------------------------------------------------------------#
+# Exceptions
+#--------------------------------------------------------------------------#
+my $target = "doesnt_exist";
+eval { $CWD = $target };
+my $err = $@;
+ok( $err, 'failure to chdir throws an error' );
+like( $err,  "/Failed to change directory to '\Q$target\E'/", 
+        '... and the error message is correct');
+
+
+
diff --git a/xt/author/00-compile.t b/xt/author/00-compile.t
new file mode 100644 (file)
index 0000000..f705e60
--- /dev/null
@@ -0,0 +1,57 @@
+use 5.006;
+use strict;
+use warnings;
+
+# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.054
+
+use Test::More;
+
+plan tests => 2;
+
+my @module_files = (
+    'File/chdir.pm'
+);
+
+
+
+# fake home for cpan-testers
+use File::Temp;
+local $ENV{HOME} = File::Temp::tempdir( CLEANUP => 1 );
+
+
+my $inc_switch = -d 'blib' ? '-Mblib' : '-Ilib';
+
+use File::Spec;
+use IPC::Open3;
+use IO::Handle;
+
+open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!";
+
+my @warnings;
+for my $lib (@module_files)
+{
+    # see L<perlfaq8/How can I capture STDERR from an external command?>
+    my $stderr = IO::Handle->new;
+
+    my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, '-e', "require q[$lib]");
+    binmode $stderr, ':crlf' if $^O eq 'MSWin32';
+    my @_warnings = <$stderr>;
+    waitpid($pid, 0);
+    is($?, 0, "$lib loaded ok");
+
+    shift @_warnings if @_warnings and $_warnings[0] =~ /^Using .*\bblib/
+        and not eval { require blib; blib->VERSION('1.01') };
+
+    if (@_warnings)
+    {
+        warn @_warnings;
+        push @warnings, @_warnings;
+    }
+}
+
+
+
+is(scalar(@warnings), 0, 'no warnings found')
+    or diag 'got warnings: ', ( Test::More->can('explain') ? Test::More::explain(\@warnings) : join("\n", '', @warnings) );
+
+
diff --git a/xt/author/critic.t b/xt/author/critic.t
new file mode 100644 (file)
index 0000000..d5b4c96
--- /dev/null
@@ -0,0 +1,12 @@
+#!perl
+
+use strict;
+use warnings;
+
+use Test::More;
+use English qw(-no_match_vars);
+
+eval "use Test::Perl::Critic";
+plan skip_all => 'Test::Perl::Critic required to criticise code' if $@;
+Test::Perl::Critic->import( -profile => "perlcritic.rc" ) if -e "perlcritic.rc";
+all_critic_ok();
diff --git a/xt/author/pod-coverage.t b/xt/author/pod-coverage.t
new file mode 100644 (file)
index 0000000..66b3b64
--- /dev/null
@@ -0,0 +1,7 @@
+#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::PodCoverageTests.
+
+use Test::Pod::Coverage 1.08;
+use Pod::Coverage::TrustPod;
+
+all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' });
diff --git a/xt/author/pod-spell.t b/xt/author/pod-spell.t
new file mode 100644 (file)
index 0000000..b3957d8
--- /dev/null
@@ -0,0 +1,31 @@
+use strict;
+use warnings;
+use Test::More;
+
+# generated by Dist::Zilla::Plugin::Test::PodSpelling 2.007003
+use Test::Spelling 0.12;
+use Pod::Wordlist;
+
+
+add_stopwords(<DATA>);
+all_pod_files_spelling_ok( qw( bin lib ) );
+__DATA__
+Berger
+BooK
+Bruhat
+David
+File
+Golden
+Joel
+Michael
+Philippe
+Schwern
+Warnock
+and
+book
+chdir
+dagolden
+joel
+lib
+schwern
+xdg
diff --git a/xt/author/pod-syntax.t b/xt/author/pod-syntax.t
new file mode 100644 (file)
index 0000000..e563e5d
--- /dev/null
@@ -0,0 +1,7 @@
+#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests.
+use strict; use warnings;
+use Test::More;
+use Test::Pod 1.41;
+
+all_pod_files_ok();
diff --git a/xt/author/portability.t b/xt/author/portability.t
new file mode 100644 (file)
index 0000000..f6ac836
--- /dev/null
@@ -0,0 +1,10 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+eval 'use Test::Portability::Files';
+plan skip_all => 'Test::Portability::Files required for testing portability'
+    if $@;
+options(test_one_dot => 0);
+run_tests();
diff --git a/xt/author/test-version.t b/xt/author/test-version.t
new file mode 100644 (file)
index 0000000..247ba9a
--- /dev/null
@@ -0,0 +1,23 @@
+use strict;
+use warnings;
+use Test::More;
+
+# generated by Dist::Zilla::Plugin::Test::Version 1.09
+use Test::Version;
+
+my @imports = qw( version_all_ok );
+
+my $params = {
+    is_strict      => 0,
+    has_version    => 1,
+    multiple       => 0,
+
+};
+
+push @imports, $params
+    if version->parse( $Test::Version::VERSION ) >= version->parse('1.002');
+
+Test::Version->import(@imports);
+
+version_all_ok;
+done_testing;
diff --git a/xt/release/distmeta.t b/xt/release/distmeta.t
new file mode 100644 (file)
index 0000000..c2280dc
--- /dev/null
@@ -0,0 +1,6 @@
+#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::MetaTests.
+
+use Test::CPAN::Meta;
+
+meta_yaml_ok();
diff --git a/xt/release/minimum-version.t b/xt/release/minimum-version.t
new file mode 100644 (file)
index 0000000..708ba15
--- /dev/null
@@ -0,0 +1,8 @@
+#!perl
+
+use Test::More;
+
+eval "use Test::MinimumVersion";
+plan skip_all => "Test::MinimumVersion required for testing minimum versions"
+  if $@;
+all_minimum_version_ok( qq{5.010} );