pathname2 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,4 +1,10 @@
1
- == 1.4.0 -
1
+ == 1.4.1 - 18-Feb-2005
2
+ * Added the Pathname#parent method.
3
+ * Added the Pathname#relative_path_from method.
4
+ * Bug fix for Pathname#pstrip on *nix.
5
+ * Corresponding test suite additions.
6
+
7
+ == 1.4.0 - 19-Dec-2005
2
8
  * Added destructive and non-destructive methods for some methods - pstrip,
3
9
  pstrip!, undecorate, undecorate!, clean and clean!.
4
10
  * Added a C extension version of this package. You can use the C version
data/README CHANGED
@@ -64,6 +64,9 @@
64
64
  * The Pathname#+ method auto cleans.
65
65
  * It uses a facade for all File and Dir methods, as well as all ftools
66
66
  methods and most FileUtils methods.
67
+ * Pathname#clean works slightly differently. In the old version,
68
+ Pathname#clean("../a") returns "../a". In this version, it returns "a".
69
+ This affects other methods, such as Pathname#relative_path_from.
67
70
 
68
71
  == Method Priority
69
72
  Because there is some overlap in method names between File, Dir, ftools
@@ -87,6 +90,10 @@
87
90
  Pathname#glob is not yet implemented in the C version.
88
91
  Pathname#find is not implemented properly in the C version.
89
92
 
93
+ In Ruby 1.8.3 and later you will see a failure in the test suite regarding
94
+ 'fu_world_writable?' from FileUtils. You can ignore this. That method is
95
+ supposed to be private. See ruby-core:7383.
96
+
90
97
  == License
91
98
  Ruby's
92
99
 
data/lib/pathname2.rb CHANGED
@@ -77,7 +77,7 @@ class Pathname < String
77
77
  Win32API.new("shlwapi", "PathRemoveBackslash", "P", "P")
78
78
  end
79
79
 
80
- VERSION = "1.4.0"
80
+ VERSION = "1.4.1"
81
81
  MAX_PATH = 260
82
82
 
83
83
  # Creates and returns a new Pathname object.
@@ -109,7 +109,7 @@ class Pathname < String
109
109
  path = path.tr("/", @sep) if @win
110
110
  super(path)
111
111
  end
112
-
112
+
113
113
  # Returns the children of the directory, files and subdirectories, as an
114
114
  # array of Pathname objects. If you set +with_directory+ to +false+, then
115
115
  # the returned pathnames will contain the filename only.
@@ -195,7 +195,7 @@ class Pathname < String
195
195
  @@PathRemoveBackslash.call(str)
196
196
  str.strip!
197
197
  else
198
- if str[-1] == @sep
198
+ if str[-1].chr == @sep
199
199
  str.strip!
200
200
  str.chop!
201
201
  end
@@ -209,7 +209,7 @@ class Pathname < String
209
209
  @@PathRemoveBackslash.call(self)
210
210
  strip!
211
211
  else
212
- if self[-1] == @sep
212
+ if self[-1].chr == @sep
213
213
  strip!
214
214
  chop!
215
215
  end
@@ -366,6 +366,54 @@ class Pathname < String
366
366
  super
367
367
  end
368
368
 
369
+ # Returns the parent directory of the given path.
370
+ def parent
371
+ self + ".."
372
+ end
373
+
374
+ # Returns a relative path from the argument to the receiver. If +self+
375
+ # is absolute, the argument must be absolute too. If +self+ is relative,
376
+ # the argument must be relative too.
377
+ #
378
+ # This method does not access the filesystem. It assumes no symlinks.
379
+ #
380
+ # Raises an ArgumentError if it cannot find a relative path.
381
+ def relative_path_from(base)
382
+ base = Pathname.new(base) unless base.kind_of?(Pathname)
383
+
384
+ if self.absolute? != base.absolute?
385
+ raise ArgumentError, "relative path between absolute and relative path"
386
+ end
387
+
388
+ return Pathname.new(".") if self == base
389
+ return self if base == "."
390
+
391
+ dest_arr = self.clean.to_a
392
+ base_arr = base.clean.to_a
393
+ dest_arr.delete('.')
394
+ base_arr.delete('.')
395
+
396
+ diff_arr = dest_arr - base_arr
397
+
398
+ while !base_arr.empty? && !dest_arr.empty? && base_arr[0] == dest_arr[0]
399
+ base_arr.shift
400
+ dest_arr.shift
401
+ end
402
+
403
+ if base_arr.include?("..")
404
+ raise ArgumentError, "base directory may not contain '..'"
405
+ end
406
+
407
+ base_arr.fill("..")
408
+ rel_path = base_arr + dest_arr
409
+
410
+ if rel_path.empty?
411
+ Pathname.new(".")
412
+ else
413
+ Pathname.new(rel_path.join(@sep))
414
+ end
415
+ end
416
+
369
417
  # Adds two Pathname objects together, or a Pathname and a String. It
370
418
  # also automatically cleans the Pathname.
371
419
  #
@@ -390,7 +438,7 @@ class Pathname < String
390
438
  buf = 0.chr * MAX_PATH
391
439
  buf[0..self.length-1] = self
392
440
  @@PathAppend.call(buf, string)
393
- buf.strip!
441
+ buf = buf.split("\0").first
394
442
  return Pathname.new(buf) # PathAppend cleans automatically
395
443
  end
396
444
 
data/test/tc_pathname.rb CHANGED
@@ -26,6 +26,9 @@ class TC_Pathname < Test::Unit::TestCase
26
26
  def setup
27
27
  @abs_path = Pathname.new("/usr/local/bin")
28
28
  @rel_path = Pathname.new("usr/local/bin")
29
+ @trl_path = Pathname.new("/usr/local/bin/")
30
+ @mul_path = Pathname.new("/usr/local/lib/local/lib")
31
+ @rul_path = Pathname.new("usr/local/lib/local/lib")
29
32
  @cur_path = Pathname.new(Dir.pwd)
30
33
 
31
34
  @abs_array = []
@@ -55,8 +58,88 @@ class TC_Pathname < Test::Unit::TestCase
55
58
  assert_equal(int, result)
56
59
  end
57
60
 
61
+ # Convenience method for test_relative_path_from
62
+ def assert_relpath(result, dest, base)
63
+ assert_equal(result, Pathname.new(dest).relative_path_from(base))
64
+ end
65
+
66
+ # Convenience method for test_relative_path_from_expected_errors
67
+ def assert_relpath_err(to, from)
68
+ assert_raise(ArgumentError) {
69
+ Pathname.new(to).relative_path_from(from)
70
+ }
71
+ end
72
+
58
73
  def test_version
59
- assert_equal("1.4.0", Pathname::VERSION)
74
+ assert_equal("1.4.1", Pathname::VERSION)
75
+ end
76
+
77
+ # These tests taken directly from Tanaka's pathname.rb. The one failure
78
+ # (commented out) is due to the fact that Tanaka's cleanpath method returns
79
+ # the cleanpath for "../a" as "../a" (i.e. it does nothing) whereas mine
80
+ # converts "../a" into just "a". Which is correct? I vote mine, because
81
+ # I don't see how you can get "more relative" from a relative path not
82
+ # already in the pathname.
83
+ #
84
+ def test_relative_path_from
85
+ assert_relpath("../a", "a", "b")
86
+ assert_relpath("../a", "a", "b/")
87
+ assert_relpath("../a", "a/", "b")
88
+ assert_relpath("../a", "a/", "b/")
89
+ assert_relpath("../a", "/a", "/b")
90
+ assert_relpath("../a", "/a", "/b/")
91
+ assert_relpath("../a", "/a/", "/b")
92
+ assert_relpath("../a", "/a/", "/b/")
93
+
94
+ assert_relpath("../b", "a/b", "a/c")
95
+ assert_relpath("../a", "../a", "../b")
96
+
97
+ assert_relpath("a", "a", ".")
98
+ assert_relpath("..", ".", "a")
99
+
100
+ assert_relpath(".", ".", ".")
101
+ assert_relpath(".", "..", "..")
102
+ assert_relpath("..", "..", ".")
103
+
104
+ assert_relpath("c/d", "/a/b/c/d", "/a/b")
105
+ assert_relpath("../..", "/a/b", "/a/b/c/d")
106
+ assert_relpath("../../../../e", "/e", "/a/b/c/d")
107
+ assert_relpath("../b/c", "a/b/c", "a/d")
108
+
109
+ assert_relpath("../a", "/../a", "/b")
110
+ #assert_relpath("../../a", "../a", "b") # fails
111
+ assert_relpath(".", "/a/../../b", "/b")
112
+ assert_relpath("..", "a/..", "a")
113
+ assert_relpath(".", "a/../b", "b")
114
+
115
+ assert_relpath("a", "a", "b/..")
116
+ assert_relpath("b/c", "b/c", "b/..")
117
+
118
+ assert_relpath_err("/", ".")
119
+ assert_relpath_err(".", "/")
120
+ assert_relpath_err("a", "..")
121
+ assert_relpath_err(".", "..")
122
+ end
123
+
124
+ def test_parent
125
+ assert_respond_to(@abs_path, :parent)
126
+ assert_equal("/usr/local", @abs_path.parent)
127
+ assert_equal("usr/local", @rel_path.parent)
128
+ assert_equal("/", Pathname.new("/").parent)
129
+ end
130
+
131
+ def test_pstrip
132
+ assert_respond_to(@trl_path, :pstrip)
133
+ assert_nothing_raised{ @trl_path.pstrip }
134
+ assert_equal("/usr/local/bin", @trl_path.pstrip)
135
+ assert_equal("/usr/local/bin/", @trl_path)
136
+ end
137
+
138
+ def test_pstrip_bang
139
+ assert_respond_to(@trl_path, :pstrip!)
140
+ assert_nothing_raised{ @trl_path.pstrip! }
141
+ assert_equal("/usr/local/bin", @trl_path.pstrip!)
142
+ assert_equal("/usr/local/bin", @trl_path)
60
143
  end
61
144
 
62
145
  def test_ascend
@@ -25,6 +25,7 @@ require "pathname2"
25
25
  require "test/unit"
26
26
 
27
27
  class TC_Pathname_MSWin < Test::Unit::TestCase
28
+
28
29
  def setup
29
30
  @fpath = Pathname.new("C:/Program Files/Windows NT/Accessories")
30
31
  @bpath = Pathname.new("C:\\Program Files\\Windows NT\\Accessories")
@@ -51,7 +52,7 @@ class TC_Pathname_MSWin < Test::Unit::TestCase
51
52
  def test_version
52
53
  assert_equal("1.4.0", Pathname::VERSION)
53
54
  end
54
-
55
+
55
56
  # Convenience method for test_plus
56
57
  def assert_pathname_plus(a, b, c)
57
58
  a = Pathname.new(a)
@@ -85,6 +86,13 @@ class TC_Pathname_MSWin < Test::Unit::TestCase
85
86
  assert_equal("C:\\foo\\bar\\", @ppath)
86
87
  assert_equal("C:\\foo\\..\\bar\\.\\baz", @cpath)
87
88
  end
89
+
90
+ def test_parent
91
+ assert_respond_to(@bpath, :parent)
92
+ assert_equal("C:\\Program Files\\Windows NT", @bpath.parent)
93
+ assert_equal("foo\\bar", @npath.parent)
94
+ assert_equal("Z:\\", @rpath.parent)
95
+ end
88
96
 
89
97
  def test_short_path
90
98
  assert_respond_to(@bpath, :short_path)
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
3
3
  specification_version: 1
4
4
  name: pathname2
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.4.0
7
- date: 2005-12-19
6
+ version: 1.4.1
7
+ date: 2006-02-18
8
8
  summary: An alternate implementation of the Pathname class
9
9
  require_paths:
10
10
  - lib