pathname2 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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