Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Path-Class CPAN distribution.

Maintainer(s)' notes

I prefer that bugs & patches are filed on GitHub rather than on RT: https://github.com/kenahoo/Path-Class/issues. Thanks.

Report information
The Basics
Id: 54578
Status: open
Priority: 0/
Queue: Path-Class

People
Owner: Nobody in particular
Requestors: mschwern [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 0.18
Fixed in: (no value)



Subject: ->parent should stop at root
The following will never end: my $dir = dir(cwd); print $dir while $dir = $dir->parent; The problem is that dir("")->parent returns the root directory again. Whether or not that's technically correct, if the root really is its own parent, its not very useful and makes recursing up the call path require checking if your parent is yourself. print $dir while $dir ne $dir->parent and $dir = $dir->parent; The documentation of parent() and the example given contradict each other. The docs say "it really means we just chop off entries from the end of the directory list until we can't chop no more" but the example shows it repeating the root directory. I think parent() stopping at root has a lot more practical utility than it not. Agreed?
The attached patches do two things. First, it adds is_rootdir() to say if the current directory is the root directory. That's handy regardless. Then it uses that to change parent() to return undef for the parent of the root directory.
Subject: 0002-Change-parent-to-stop-at-the-root-directory.patch
From 40a58986a4eb716c5a99646250ffd50f1718e8c3 Mon Sep 17 00:00:00 2001 From: Michael G. Schwern <schwern@pobox.com> Date: Fri, 12 Feb 2010 16:59:11 -0800 Subject: [PATCH 2/2] Change parent() to stop at the root directory --- lib/Path/Class/Dir.pm | 9 +++++---- t/01-basic.t | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/Path/Class/Dir.pm b/lib/Path/Class/Dir.pm index bc8baa5..f576abd 100644 --- a/lib/Path/Class/Dir.pm +++ b/lib/Path/Class/Dir.pm @@ -96,6 +96,8 @@ sub parent { my $dirs = $self->{dirs}; my ($curdir, $updir) = ($self->_spec->curdir, $self->_spec->updir); + return if $self->is_rootdir; + if ($self->is_absolute) { my $parent = $self->new($self); pop @{$parent->{dirs}}; @@ -438,7 +440,8 @@ Returns the parent directory of C<$dir>. Note that this is the I<logical> parent, not necessarily the physical parent. It really means we just chop off entries from the end of the directory list until we cain't chop no more. If the directory is relative, we start -using the relative forms of parent directories. +using the relative forms of parent directories. If the directory is +root, it will return undef. The following code demonstrates the behavior on absolute and relative directories: @@ -447,6 +450,7 @@ directories: for (1..6) { print "Absolute: $dir\n"; $dir = $dir->parent; + last if not $dir; } $dir = dir('foo/bar'); @@ -459,9 +463,6 @@ directories: Absolute: /foo/bar Absolute: /foo Absolute: / - Absolute: / - Absolute: / - Absolute: / Relative: foo/bar Relative: foo Relative: . diff --git a/t/01-basic.t b/t/01-basic.t index 093932f..2c74252 100644 --- a/t/01-basic.t +++ b/t/01-basic.t @@ -58,7 +58,7 @@ ok $file->parent, '/foo/baz'; ok $dir->parent, '/foo/bar'; ok $dir->parent->parent, '/foo'; ok $dir->parent->parent->parent, '/'; - ok $dir->parent->parent->parent->parent, '/'; + ok !$dir->parent->parent->parent->parent; $dir = dir('foo/bar/baz'); ok $dir->parent, 'foo/bar'; -- 1.6.6.1
Subject: 0001-Add-is_rootdir.patch
From b6fa3a4e3b47002cb39995095abec738f9e4d0c8 Mon Sep 17 00:00:00 2001 From: Michael G. Schwern <schwern@pobox.com> Date: Fri, 12 Feb 2010 16:50:15 -0800 Subject: [PATCH 1/2] Add is_rootdir() This is necessary to make parent() stop at the root, and handy in general. --- lib/Path/Class/Dir.pm | 15 +++++++++++++++ t/rootdir.t | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 0 deletions(-) create mode 100644 t/rootdir.t diff --git a/lib/Path/Class/Dir.pm b/lib/Path/Class/Dir.pm index fb80ebd..bc8baa5 100644 --- a/lib/Path/Class/Dir.pm +++ b/lib/Path/Class/Dir.pm @@ -251,6 +251,12 @@ sub contains { return !!(-d $self and (-e $other or -l $other) and $self->subsumes($other)); } +sub is_rootdir { + my $self = shift; + my $not_root = grep $_ ne '', @{$self->{dirs}}; + return !$not_root; +} + 1; __END__ @@ -389,6 +395,15 @@ absolute path specifier (like C</usr/local> or C<\Windows>). Returns true or false depending on whether the directory refers to a relative path specifier (like C<lib/foo> or C<./dir>). +=item $dir->is_rootdir + +Returns true or false depending on whether the directory refers to +the root directory of the volume (like C</> or C<C:\>). + +This is not currently a file system check, so C<../../..> will never +return true even if it does lead to the root directory. This may +change. + =item $dir->cleanup Performs a logical cleanup of the file path. For instance: diff --git a/t/rootdir.t b/t/rootdir.t new file mode 100644 index 0000000..c7593e5 --- /dev/null +++ b/t/rootdir.t @@ -0,0 +1,47 @@ +#!/usr/bin/perl + +BEGIN { + $^O = 'Unix'; # Test in Unix mode +} + +use Test::More tests => 17; +use warnings; +use strict; +use Path::Class; + +# Basic Unix tests +{ + ok dir("/")->is_rootdir; + ok dir("")->is_rootdir; + ok !dir("/foo")->is_rootdir; + ok !dir("foo")->is_rootdir; + ok dir("//")->is_rootdir; + ok !dir("foo/bar/baz")->is_rootdir; + ok !dir(".")->is_rootdir; + ok !dir("../")->is_rootdir; +} + +# Try Windows +{ + my $new_win = sub { Path::Class::Dir->new_foreign("Win32", @_) }; + ok $new_win->("C:\\")->is_rootdir; + ok $new_win->("\\")->is_rootdir; + ok $new_win->("")->is_rootdir; + ok $new_win->("/")->is_rootdir; + ok $new_win->("C:/")->is_rootdir; + ok !$new_win->("C:/foo")->is_rootdir; + ok !$new_win->("\\foo")->is_rootdir; + ok !$new_win->(".\\foo")->is_rootdir; +} + +# Look up the current path to find the root dir +{ + my $dir = dir->absolute; + for(1..1024) { + if( $dir->is_rootdir ) { + pass("Found the root dir"); + last; + } + $dir = $dir->parent; + } +} -- 1.6.6.1