diff --git a/Foundation/CPCoder.j b/Foundation/CPCoder.j index d02d918e0..0bdc7b89a 100644 --- a/Foundation/CPCoder.j +++ b/Foundation/CPCoder.j @@ -53,7 +53,7 @@ @param aType the structure or object type @param anObject the object to be encoded */ -- (void)encodeValueOfObjCType:(CPString)aType at:(id)anObject +- (void)encodeValueOfObjJType:(CPString)aType at:(id)anObject { _CPRaiseInvalidAbstractInvocation(self, _cmd); } diff --git a/Foundation/CPError.j b/Foundation/CPError.j index 4acafe2ce..edc270514 100644 --- a/Foundation/CPError.j +++ b/Foundation/CPError.j @@ -24,31 +24,52 @@ @import "CPObject.j" @import "CPString.j" -CPCappuccinoErrorDomain = CPCocoaErrorDomain = @"CPCappuccinoErrorDomain"; -// CPPOSIXErrorDomain = @"CPPOSIXErrorDomain"; -// CPOSStatusErrorDomain = @"CPOSStatusErrorDomain"; +CPCappuccinoErrorDomain = kCFErrorDomainCappuccino; +CPCocoaErrorDomain = kCFErrorDomainCappuccino; // compat -CPUnderlyingErrorKey = @"CPUnderlyingErrorKey"; +CPUnderlyingErrorKey = kCFErrorUnderlyingErrorKey; -CPLocalizedDescriptionKey = @"CPLocalizedDescriptionKey"; -CPLocalizedFailureReasonErrorKey = @"CPLocalizedFailureReasonErrorKey"; -CPLocalizedRecoverySuggestionErrorKey = @"CPLocalizedRecoverySuggestionErrorKey"; +CPLocalizedDescriptionKey = kCFErrorLocalizedDescriptionKey; +CPLocalizedFailureReasonErrorKey = kCFErrorLocalizedFailureReasonKey; +CPLocalizedRecoverySuggestionErrorKey = kCFErrorLocalizedRecoverySuggestionKey; CPLocalizedRecoveryOptionsErrorKey = @"CPLocalizedRecoveryOptionsErrorKey"; CPRecoveryAttempterErrorKey = @"CPRecoveryAttempterErrorKey"; CPHelpAnchorErrorKey = @"CPHelpAnchorErrorKey"; CPStringEncodingErrorKey = @"CPStringEncodingErrorKey"; -CPURLErrorKey = @"CPURLErrorKey"; -CPFilePathErrorKey = @"CPFilePathErrorKey"; +CPURLErrorKey = kCFErrorURLKey; +CPFilePathErrorKey = kCFErrorFilePathKey; +/*! + @class CPError + @ingroup foundation + @brief Used for encapsulating, presenting, and recovery from errors. + CPError is toll-free bridged with CFError() methods. + + An example of initializing a CPError: +
+
+var userInfo = @{CPLocalizedDescriptionKey: @"A localized error description",
+ CPLocalizedFailureReasonErrorKey: @"A localized failure reason",
+ CPUnderlyingErrorKey: @"An underlying error message"},
+
+ err = [CPError errorWithDomain:CPCappuccinoErrorDomain code:-10 userInfo:userInfo];
+
+ */
@implementation CPError : CPObject
{
- CPInteger _code @accessors(property=code, readonly);
- CPString _domain @accessors(property=domain, readonly);
- CPDictionary _userInfo @accessors(property=userInfo, readonly);
}
++ (id)alloc
+{
+ var obj = new CFError();
+ obj.isa = [self class];
+
+ return obj;
+}
+
+
+ (id)errorWithDomain:(CPString)aDomain code:(CPInteger)aCode userInfo:(CPDictionary)aDict
{
return [[CPError alloc] initWithDomain:aDomain code:aCode userInfo:aDict];
@@ -56,44 +77,94 @@ CPFilePathErrorKey = @"CPFilePathErrorKey";
- (id)initWithDomain:(CPString)aDomain code:(CPInteger)aCode userInfo:(CPDictionary)aDict
{
- if (self = [super init])
- {
- _domain = aDomain;
- _code = aCode;
- _userInfo = aDict;
- }
-
- return self;
+ var result = new CFError(aDomain, aCode, aDict);
+ result.isa = [self class];
+ return result;
}
+- (CPInteger)code
+{
+ return self.code();
+}
+
+- (CPString)userInfo
+{
+ return self.userInfo();
+}
+
+- (CPString)domain
+{
+ return self.domain();
+}
+
+/*!
+ By default this method returns the object in the user info dictionary for the key
+ CPLocalizedDescriptionKey. If the user info dictionary doesn’t contain a value for
+ CPLocalizedDescriptionKey, a default string is constructed from the domain and code.
+ */
- (CPString)localizedDescription
{
- return [_userInfo objectForKey:CPLocalizedDescriptionKey];
+ return self.description();
}
- (CPString)localizedFailureReason
{
- return [_userInfo objectForKey:CPLocalizedFailureReasonErrorKey];
+ return self.failureReason();
}
- (CPArray)localizedRecoveryOptions
{
- return [_userInfo objectForKey:CPLocalizedRecoveryOptionsErrorKey];
+ var userInfo = self.userInfo(),
+ recoveryOptions = userInfo.valueForKey(CPLocalizedRecoveryOptionsErrorKey);
+
+ return recoveryOptions;
}
- (CPString)localizedRecoverySuggestion
{
- return [_userInfo objectForKey:CPLocalizedRecoverySuggestionErrorKey];
+ return self.recoverySuggestion();
}
- (id)recoveryAttempter
{
- return [_userInfo objectForKey:CPRecoveryAttempterErrorKey];
+ var userInfo = self.userInfo(),
+ recoveryAttempter = userInfo.valueForKey(CPRecoveryAttempterErrorKey);
+
+ return recoveryAttempter;
}
- (CPString)description
{
- return [CPString stringWithFormat:@"Error Domain=%@ Code=%d UserInfo=%p %@", _domain, _code, _userInfo, [self localizedDescription]];
+ return [CPString stringWithFormat:@"Error Domain=%@ Code=%d \"%@\" UserInfo=%@", self.domain(), self.code(), self.description(), self.userInfo()];
}
@end
+
+var CPErrorCodeKey = @"CPErrorCodeKey",
+ CPErrorDomainKey = @"CPErrorDomainKey",
+ CPErrorUserInfoKey = @"CPErrorUserInfoKey";
+
+@implementation CPError (CPCoding)
+
+- (id)initWithCoder:(CPCoder)aCoder
+{
+ var code = [aCoder decodeIntForKey:CPErrorCodeKey],
+ domain = [aCoder decodeObjectForKey:CPErrorDomainKey],
+ userInfo = [aCoder decodeObjectForKey:CPErrorUserInfoKey];
+
+ return [self initWithDomain:domain
+ code:code
+ userInfo:userInfo];
+}
+
+- (void)encodeWithCoder:(CPCoder)aCoder
+{
+ [aCoder encodeObject:self.domain() forKey:CPErrorDomainKey];
+ [aCoder encodeObject:self.code() forKey:CPErrorCodeKey];
+ [aCoder encodeObject:self.userInfo() forKey:CPErrorUserInfoKey];
+}
+
+@end
+
+CFError.prototype.isa = CPError;
+
diff --git a/Foundation/CPURLError.j b/Foundation/CPURLError.j
new file mode 100644
index 000000000..77d901256
--- /dev/null
+++ b/Foundation/CPURLError.j
@@ -0,0 +1,39 @@
+
+/*
+ * The CPURL Error Domain
+ */
+CPURLErrorDomain = @"CPURLErrorDomain";
+
+/*
+ * CPURL UserInfo Error Keys
+ */
+CPURLErrorFailingURLErrorKey = @"CPErrorFailingURLKey";
+CPURLErrorFailingURLStringErrorKey = @"CPURLErrorFailingURLStringKey";
+
+/*
+ * CPURL Error Codes
+ */
+CPURLErrorUnknown = -1;
+CPURLErrorCancelled = kCFURLErrorCancelled;
+CPURLErrorBadURL = kCFURLErrorBadURL;
+CPURLErrorTimedOut = kCFURLErrorTimedOut;
+CPURLErrorUnsupportedURL = kCFURLErrorUnsupportedURL;
+CPURLErrorCannotFindHost = kCFURLErrorCannotFindHost;
+CPURLErrorCannotConnectToHost = kCFURLErrorCannotConnectToHost;
+CPURLErrorNetworkConnectionLost = kCFURLErrorNetworkConnectionLost;
+CPURLErrorDNSLookupFailed = kCFURLErrorDNSLookupFailed;
+CPURLErrorHTTPTooManyRedirects = kCFURLErrorHTTPTooManyRedirects;
+CPURLErrorResourceUnavailable = kCFURLErrorResourceUnavailable;
+CPURLErrorNotConnectedToInternet = kCFURLErrorNotConnectedToInternet;
+CPURLErrorRedirectToNonExistentLocation = kCFURLErrorRedirectToNonExistentLocation;
+CPURLErrorBadServerResponse = kCFURLErrorBadServerResponse;
+CPURLErrorUserCancelledAuthentication = kCFURLErrorUserCancelledAuthentication;
+CPURLErrorUserAuthenticationRequired = kCFURLErrorUserAuthenticationRequired;
+CPURLErrorZeroByteResource = kCFURLErrorZeroByteResource;
+CPURLErrorCannotDecodeRawData = kCFURLErrorCannotDecodeRawData;
+CPURLErrorCannotDecodeContentData = kCFURLErrorCannotDecodeContentData;
+CPURLErrorCannotParseResponse = kCFURLErrorCannotParseResponse;
+CPURLErrorFileDoesNotExist = kCFURLErrorFileDoesNotExist;
+CPURLErrorFileIsDirectory = kCFURLErrorFileIsDirectory;
+CPURLErrorNoPermissionsToReadFile = kCFURLErrorNoPermissionsToReadFile;
+CPURLErrorDataLengthExceedsMaximum = kCFURLErrorDataLengthExceedsMaximum;
\ No newline at end of file
diff --git a/Foundation/Foundation.j b/Foundation/Foundation.j
index ab9d5fdb2..3fa485412 100755
--- a/Foundation/Foundation.j
+++ b/Foundation/Foundation.j
@@ -73,6 +73,7 @@
@import "CPUndoManager.j"
@import "CPURL.j"
@import "CPURLConnection.j"
+@import "CPURLError.j"
@import "CPURLRequest.j"
@import "CPURLResponse.j"
@import "CPUserDefaults.j"
diff --git a/Objective-J/CFError.js b/Objective-J/CFError.js
new file mode 100644
index 000000000..615bbade8
--- /dev/null
+++ b/Objective-J/CFError.js
@@ -0,0 +1,164 @@
+/*
+ * CFError.js
+ * Objective-J
+ *
+ * Created by Andrew Hankinson.
+ * Copyright 2014, Andrew Hankinson.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+GLOBAL(kCFErrorLocalizedDescriptionKey) = "CPLocalizedDescription";
+GLOBAL(kCFErrorLocalizedFailureReasonKey) = "CPLocalizedFailureReason";
+GLOBAL(kCFErrorLocalizedRecoverySuggestionKey) = "CPLocalizedRecoverySuggestion";
+GLOBAL(kCFErrorDescriptionKey) = "CPDescription";
+GLOBAL(kCFErrorUnderlyingErrorKey) = "CPUnderlyingError";
+
+GLOBAL(kCFErrorURLKey) = "CPURL";
+GLOBAL(kCFErrorFilePathKey) = "CPFilePath";
+
+// GLOBAL(kCFErrorDomainPOSIX) = "";
+// GLOBAL(kCFErrorDomainOSStatus) = "";
+// GLOBAL(kCFErrorDomainMach) = "";
+GLOBAL(kCFErrorDomainCappuccino) = "CPCappuccinoErrorDomain";
+GLOBAL(kCFErrorDomainCocoa) = kCFErrorDomainCappuccino;
+
+
+GLOBAL(CFError) = function(/* CFString */ domain, /* int */ code, /* CFDictionary */ userInfo)
+{
+ this._domain = domain || NULL;
+ this._code = code || 0;
+ this._userInfo = userInfo || new CFDictionary();
+ this._UID = objj_generateObjectUID();
+};
+
+CFError.prototype.domain = function()
+{
+ return this._domain;
+};
+
+DISPLAY_NAME(CFError.prototype.domain);
+
+CFError.prototype.code = function()
+{
+ return this._code;
+};
+
+DISPLAY_NAME(CFError.prototype.code);
+
+/*
+ This follows the same logic to generate a description as the "real" CFError.
+*/
+CFError.prototype.description = function()
+{
+ var localizedDesc = this._userInfo.valueForKey(kCFErrorLocalizedDescriptionKey);
+ if (localizedDesc)
+ return localizedDesc;
+
+ var reason = this._userInfo.valueForKey(kCFErrorLocalizedFailureReasonKey);
+ if (reason)
+ {
+ var operationFailedStr = "The operation couldn\u2019t be completed. " + reason;
+ return operationFailedStr;
+ }
+
+ // @TODO Add the bundle localized domain handler.
+ var result = "",
+ desc = this._userInfo.valueForKey(kCFErrorDescriptionKey);
+ if (desc)
+ {
+ // we have a description key.
+ var result = "The operation couldn\u2019t be completed. (error " + this._code + " - " + desc + ")";
+ }
+ else
+ {
+ // just use error and code;
+ var result = "The operation couldn\u2019t be completed. (error " + this._code + ")";
+ }
+
+ return result;
+};
+
+DISPLAY_NAME(CFError.prototype.description);
+
+CFError.prototype.failureReason = function()
+{
+ return this._userInfo.valueForKey(kCFErrorLocalizedFailureReasonKey);
+};
+
+DISPLAY_NAME(CFError.prototype.failureReason);
+
+CFError.prototype.recoverySuggestion = function()
+{
+ return this._userInfo.valueForKey(kCFErrorLocalizedRecoverySuggestionKey);
+};
+
+DISPLAY_NAME(CFError.prototype.recoverySuggestion);
+
+CFError.prototype.userInfo = function ()
+{
+ return this._userInfo;
+};
+
+DISPLAY_NAME(CFError.prototype.userInfo);
+
+/*
+ CFError Bridge Functions
+ The "Create" and "Copy" in the function names do not have any meaning
+ in Cappuccino; they are bridged here for compatibility reasons only.
+*/
+GLOBAL(CFErrorCreate) = function(/* String */ domain, /*int */ code, /* CFDictionary */ userInfo)
+{
+ return new CFError(domain, code, userInfo);
+};
+
+GLOBAL(CFErrorCreateWithUserInfoKeysAndValues) = function(/* String */ domain, /* int */ code, /* array */ userInfoKeys, /* array */ userInfoValues, /* int */ numUserInfoValues)
+{
+ var userInfo = new CFMutableDictionary();
+ while (numUserInfoValues--)
+ userInfo.setValueForKey(userInfoKeys[numUserInfoValues], userInfoValues[numUserInfoValues]);
+
+ return new CFError(domain, code, userInfo);
+};
+
+GLOBAL(CFErrorGetCode) = function(/* CFError */ err)
+{
+ return err.code();
+};
+
+GLOBAL(CFErrorGetDomain) = function(/* CFError */ err)
+{
+ return err.domain();
+};
+
+GLOBAL(CFErrorCopyDescription) = function(/* CFError */ err)
+{
+ return err.description();
+};
+
+GLOBAL(CFErrorCopyUserInfo) = function(/* CFError */ err)
+{
+ return err.userInfo();
+};
+
+GLOBAL(CFErrorCopyFailureReason) = function(/* CFError */ err)
+{
+ return err.failureReason();
+};
+
+GLOBAL(CFErrorCopyRecoverySuggestion) = function(/* CFError */err)
+{
+ return err.recoverySuggestion();
+};
diff --git a/Objective-J/CFNetworkErrors.js b/Objective-J/CFNetworkErrors.js
new file mode 100644
index 000000000..9473579b9
--- /dev/null
+++ b/Objective-J/CFNetworkErrors.js
@@ -0,0 +1,25 @@
+GLOBAL(kCFURLErrorUnknown) = -998;
+GLOBAL(kCFURLErrorCancelled) = -999;
+GLOBAL(kCFURLErrorBadURL) = -1000;
+GLOBAL(kCFURLErrorTimedOut) = -1001;
+GLOBAL(kCFURLErrorUnsupportedURL) = -1002;
+GLOBAL(kCFURLErrorCannotFindHost) = -1003;
+GLOBAL(kCFURLErrorCannotConnectToHost) = -1004;
+GLOBAL(kCFURLErrorNetworkConnectionLost) = -1005;
+GLOBAL(kCFURLErrorDNSLookupFailed) = -1006;
+GLOBAL(kCFURLErrorHTTPTooManyRedirects) = -1007;
+GLOBAL(kCFURLErrorResourceUnavailable) = -1008;
+GLOBAL(kCFURLErrorNotConnectedToInternet) = -1009;
+GLOBAL(kCFURLErrorRedirectToNonExistentLocation) = -1010;
+GLOBAL(kCFURLErrorBadServerResponse) = -1011;
+GLOBAL(kCFURLErrorUserCancelledAuthentication) = -1012;
+GLOBAL(kCFURLErrorUserAuthenticationRequired) = -1013;
+GLOBAL(kCFURLErrorZeroByteResource) = -1014;
+GLOBAL(kCFURLErrorCannotDecodeRawData) = -1015;
+GLOBAL(kCFURLErrorCannotDecodeContentData) = -1016;
+GLOBAL(kCFURLErrorCannotParseResponse) = -1017;
+GLOBAL(kCFURLErrorRequestBodyStreamExhausted) = -1021;
+GLOBAL(kCFURLErrorFileDoesNotExist) = -1100;
+GLOBAL(kCFURLErrorFileIsDirectory) = -1101;
+GLOBAL(kCFURLErrorNoPermissionsToReadFile) = -1102;
+GLOBAL(kCFURLErrorDataLengthExceedsMaximum) = -1103;
\ No newline at end of file
diff --git a/Objective-J/Includes.js b/Objective-J/Includes.js
index a4373e3a0..43adc2de2 100644
--- a/Objective-J/Includes.js
+++ b/Objective-J/Includes.js
@@ -38,6 +38,8 @@
#include "CFHTTPRequest.js"
#include "CFPropertyList.js"
#include "CFDictionary.js"
+#include "CFError.js"
+#include "CFNetworkErrors.js"
#include "CFData.js"
#include "CFURL.js"
#include "MarkedStream.js"
diff --git a/Tests/Foundation/CPErrorTest.j b/Tests/Foundation/CPErrorTest.j
new file mode 100644
index 000000000..7e482a3a2
--- /dev/null
+++ b/Tests/Foundation/CPErrorTest.j
@@ -0,0 +1,43 @@
+@import