Added stringByAppendingPathComponent: and stringByAppendingPathExtension: to CPString. Also, changed CPString path behaviour to correspond to Cocoa behaviour.

This commit is contained in:
Martin Carlberg committed 2012-05-11 15:32:18 +02:00
1 parent c437537749
commit c35ccde682
2 files changed
+193 -18

No files matched your search

+106 -14
View File
@@ -706,14 +706,67 @@ var CPStringRegexSpecialCharacters = [
Returns an the path components of this string. This
method assumes that the string's content is a '/'
separated file system path.
Multiple '/' separators between components are truncated to a single one.
*/
- (CPArray)pathComponents
{
if (length === 0) return [""];
if (self === "/") return ["/"];
var result = split('/');
if (result[0] === "")
result[0] = "/";
if (result[result.length - 1] === "")
result.pop();
var index = result.length - 1;
if (index > 0)
{
if (result[index] === "")
result[index] = "/";
while (index--)
{
while (result[index] === "")
{
result.splice(index--, 1);
}
}
}
return result;
}
/*!
Returns a string built from the strings in a given array by
concatenating them with a path separator between each pair.
This method assumes that the string's content is a '/'
separated file system path.
Multiple '/' separators between components are truncated to a single one.
*/
+ (CPString)pathWithComponents:(CPArray)components
{
var size = components.length,
result = "",
i = -1,
firstRound = true,
firstIsSlash = false;
while (++i < size)
{
var component = components[i],
lenMinusOne = component.length - 1;
if (lenMinusOne >= 0 && (component !== "/" || firstRound)) // Skip "" and "/" (not first time)
{
if (lenMinusOne > 0 && component.indexOf("/",lenMinusOne) === lenMinusOne) // Ends with "/"
component = component.substring(0, lenMinusOne);
if (firstRound)
{
if (component === "/")
firstIsSlash = true;
firstRound = false;
}
else if (!firstIsSlash)
result += "/";
else
firstIsSlash = false;
result += component;
}
}
return result;
}
@@ -737,33 +790,72 @@ var CPStringRegexSpecialCharacters = [
*/
- (CPString)lastPathComponent
{
var components = [self pathComponents];
return components[components.length - 1];
var components = [self pathComponents],
lastIndex = components.length - 1,
lastComponent = components[lastIndex];
return lastIndex > 0 && lastComponent === "/" ? components[lastIndex - 1] : lastComponent;
}
/*!
Returns a new string made by appending to the receiver a given string
This method assumes that the string's content is a '/'
separated file system path.
Multiple '/' separators between components are truncated to a single one.
*/
- (CPString)stringByAppendingPathComponent:(CPString)aString
{
var components = [self pathComponents],
addComponents = aString && aString !== "/" ? [aString pathComponents] : [];
return [CPString pathWithComponents:components.concat(addComponents)];
}
/*!
Returns a new string made by appending to the receiver an extension separator followed by a given extension
This method assumes that the extension separator is a '.'
Extension can't include a '/' character, receiver can't be empty or be just a '/'. If so the
result will be the receiver itself.
Multiple '/' separators between components are truncated to a single one.
*/
- (CPString)stringByAppendingPathExtension:(CPString)ext
{
if (ext.indexOf('/') >= 0 || length === 0 || self === "/") // Can't handle these
return self;
var components = [self pathComponents],
last = components.length - 1;
if (last > 0 && components[last] === "/")
components.splice(last--, 1);
components[last] = components[last] + "." + ext;
return [CPString pathWithComponents:components];
}
/*!
Deletes the last path component of a string.
This method assumes that the string's content is a '/'
separated file system path.
Multiple '/' separators between components are truncated to a single one.
*/
- (CPString)stringByDeletingLastPathComponent
{
var path = self,
start = length - 1;
if (length === 0) return "";
if (self === "/") return "/";
var components = [self pathComponents],
last = components.length - 1;
while (path.charAt(start) === '/')
start--;
if (components[last] === "/")
last--;
components.splice(last, components.length - last);
path = path.substr(0, path.lastIndexOf('/', start));
if (path === "" && charAt(0) === '/')
return '/';
return path;
return [CPString pathWithComponents:components];
}
/*!
Deletes the extension of a string.
This method assumes that the string's content is a '/'
separated file system path.
Multiple '/' separators between components are truncated to a single one.
*/
- (CPString)stringByDeletingPathExtension
{
+87 -4
View File
@@ -225,6 +225,52 @@
[self assert:"ffffff" equals:[CPString stringWithHash:16777215]];
}
- (void)testStringByAppendingPathComponent
{
var testStrings = [
["/tmp/", "scratch.tiff", "/tmp/scratch.tiff"],
["/tmp///", "scratch.tiff", "/tmp/scratch.tiff"],
["/tmp///", "///scratch.tiff", "/tmp/scratch.tiff"],
["/tmp", "scratch.tiff", "/tmp/scratch.tiff"],
["/tmp///", "scratch.tiff", "/tmp/scratch.tiff"],
["/tmp///", "///scratch.tiff", "/tmp/scratch.tiff"],
["/", "scratch.tiff", "/scratch.tiff"],
["", "scratch.tiff", "scratch.tiff"],
["", "", ""],
["", "/", ""],
["/", "/", "/"],
["/tmp", nil, "/tmp"],
["/tmp", "/", "/tmp"],
["/tmp/", "", "/tmp"]
];
for (var i = 0; i < testStrings.length; i++)
{
var result = [testStrings[i][0] stringByAppendingPathComponent:testStrings[i][1]];
[self assertTrue:result === testStrings[i][2] message:"Value <" + testStrings[i][0] + "> Adding <" + testStrings[i][1] + "> Expected <" + testStrings[i][2] + "> was <" + result + ">"];
}
}
- (void)testStringByAppendingPathExtension
{
var testStrings = [
["/tmp/scratch.old", "tiff", "/tmp/scratch.old.tiff"],
["/tmp/scratch.", "tiff", "/tmp/scratch..tiff"],
["/tmp///", "tiff", "/tmp.tiff"],
["scratch", "tiff", "scratch.tiff"],
["/", "tiff", "/"],
["", "tiff", ""]
];
for (var i = 0; i < testStrings.length; i++)
{
var result = [testStrings[i][0] stringByAppendingPathExtension:testStrings[i][1]];
[self assertTrue:result === testStrings[i][2] message:"Value <" + testStrings[i][0] + "> Adding <" + testStrings[i][1] + "> Expected <" + testStrings[i][2] + "> was <" + result + ">"];
}
}
- (void)testStringByDeletingLastPathComponent
{
var testStrings = [
@@ -235,22 +281,58 @@
["/", "/"],
["scratch.tiff", ""],
["a/b/c/d//////", "a/b/c"],
["a/b/////////c/d//////", "a/b/c"],
["a/b/././././c/d/./././", "a/b/././././c/d/./."],
[@"a/b/././././d////", "a/b/./././."],
[@"~/a", "~"],
[@"~/a/", "~"],
[@"../../", ".."]
[@"../../", ".."],
[@"", ""]
];
for (var i = 0; i < testStrings.length; i++)
[self assert:[testStrings[i][0] stringByDeletingLastPathComponent] equals:testStrings[i][1]];
{
var result = [testStrings[i][0] stringByDeletingLastPathComponent];
[self assertTrue:result === testStrings[i][1] message:"Value <" + testStrings[i][0] + "> Expected <" + testStrings[i][1] + "> was <" + result + ">"];
}
}
- (void)testPathWithComponents
{
var testStrings = [
[["tmp", "scratch"], "tmp/scratch"],
[["/", "tmp", "scratch"], "/tmp/scratch"],
[["/", "tmp", "/", "scratch"], "/tmp/scratch"],
[["/", "tmp", "scratch", "/"], "/tmp/scratch"],
[["/", "tmp", "scratch", ""], "/tmp/scratch"],
[["", "/tmp", "scratch", ""], "/tmp/scratch"],
[["", "tmp", "scratch", ""], "tmp/scratch"],
[["/"], "/"],
[["/", "/", "/"], "/"],
[["", "", ""], ""],
[[""], ""]
];
for (var i = 0; i < testStrings.length; i++)
{
var result = [CPString pathWithComponents:testStrings[i][0]];
[self assertTrue:result === testStrings[i][1] message:"Value <" + testStrings[i][0] + "> Expected [" + testStrings[i][1] + "] was [" + result + "]"];
}
}
- (void)testPathComponents
{
var testStrings = [
["tmp/scratch", ["tmp", "scratch"]],
["/tmp/scratch", ["/", "tmp", "scratch"]]
["/tmp/scratch", ["/", "tmp", "scratch"]],
["/tmp/scratch/", ["/", "tmp", "scratch", "/"]],
["/tmp/", ["/", "tmp", "/"]],
["/////tmp/////scratch///", ["/", "tmp", "scratch", "/"]],
["scratch.tiff", ["scratch.tiff"]],
["/", ["/"]],
["", [""]]
];
for (var i = 0; i < testStrings.length; i++)
@@ -268,7 +350,8 @@
["/tmp/scratch", "scratch"],
["/tmp/", "tmp"],
["scratch", "scratch"],
["/", "/"]
["/", "/"],
["", ""]
];
for (var i = 0; i < testStrings.length; i++)