aboutsummaryrefslogtreecommitdiff
path: root/Foundation
diff options
context:
space:
mode:
authorGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2009-12-14 13:00:42 +0000
committerGravatar gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2009-12-14 13:00:42 +0000
commit4365eeb9dd643c28472cff6f06ad8955d1d2f2c9 (patch)
treea41cf2eabde3460bd54fb788746b11b4f44c5c26 /Foundation
parent7252815552530ba1f552d1a48d3fae85ecf67b45 (diff)
[Author: dmaclach]
Tighten up our AppleScript error handling code, and get rid of a private symbol. R=thomasvl DELTA=154 (144 added, 4 deleted, 6 changed)
Diffstat (limited to 'Foundation')
-rw-r--r--Foundation/GTMNSAppleScript+Handler.h13
-rw-r--r--Foundation/GTMNSAppleScript+Handler.m129
-rw-r--r--Foundation/GTMNSAppleScript+HandlerTest.m17
3 files changed, 149 insertions, 10 deletions
diff --git a/Foundation/GTMNSAppleScript+Handler.h b/Foundation/GTMNSAppleScript+Handler.h
index 65f57c5..8fcb8fc 100644
--- a/Foundation/GTMNSAppleScript+Handler.h
+++ b/Foundation/GTMNSAppleScript+Handler.h
@@ -123,4 +123,17 @@ enum {
// Return YES if the script has an open documents (odoc) handler
// Does not require script compilation, so it's a fast check.
- (BOOL)gtm_hasOpenDocumentsHandler;
+
+@end
+
+// Error keys that we may return in the error dictionary on top of the standard
+// NSAppleScriptError* keys.
+extern NSString const* GTMNSAppleScriptErrorPartialResult; // id
+extern NSString const* GTMNSAppleScriptErrorOffendingObject; // id
+extern NSString const* GTMNSAppleScriptErrorExpectedType; // GTMFourCharCode
+
+@interface NSAppleEventDescriptor (GTMAppleEventDescriptorOSAAdditions)
+// Returns an NSValue containing an NSRange of script source when an error
+// occurs while compiling and/or executing a script.
+- (id)gtm_OSAErrorRangeValue;
@end
diff --git a/Foundation/GTMNSAppleScript+Handler.m b/Foundation/GTMNSAppleScript+Handler.m
index dd548e4..5bb1f46 100644
--- a/Foundation/GTMNSAppleScript+Handler.m
+++ b/Foundation/GTMNSAppleScript+Handler.m
@@ -30,13 +30,21 @@ static NSString *const GTMNSAppleScriptEventKey = @"GTMNSAppleScriptEvent";
static NSString *const GTMNSAppleScriptResultKey = @"GTMNSAppleScriptResult";
static NSString *const GTMNSAppleScriptErrorKey = @"GTMNSAppleScriptError";
+// Error keys that we may return in the error dictionary on top of the standard
+// NSAppleScriptError* keys.
+NSString const* GTMNSAppleScriptErrorPartialResult
+ = @"GTMNSAppleScriptErrorPartialResult";
+NSString const* GTMNSAppleScriptErrorOffendingObject
+ = @"GTMNSAppleScriptErrorOffendingObject";
+NSString const* GTMNSAppleScriptErrorExpectedType
+ = @"GTMNSAppleScriptErrorExpectedType";
+
// Some private methods that we need to call
@interface NSAppleScript (NSPrivate)
+ (ComponentInstance)_defaultScriptingComponent;
- (OSAID) _compiledScriptID;
- (id)_initWithData:(NSData*)data error:(NSDictionary**)error;
- (id)_initWithScriptIDNoCopy:(OSAID)osaID;
-+ (id)_infoForOSAError:(OSAError)error;
@end
@interface NSMethodSignature (NSPrivate)
@@ -76,6 +84,9 @@ static NSString *const GTMNSAppleScriptErrorKey = @"GTMNSAppleScriptError";
- (OSAID)gtm_realIDAndComponent:(ComponentInstance*)component;
- (void)gtm_internalExecuteAppleEvent:(NSMutableDictionary *)data;
+
+- (NSDictionary *)gtm_errorDictionaryFromOSStatus:(OSStatus)status
+ component:(ComponentInstance)component;
@end
@implementation NSAppleScript(GTMAppleScriptHandlerAdditions)
@@ -473,16 +484,15 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:);
kOSAModeNull, &valueID);
if (err == noErr) {
// descForScriptID:component: is what sets this apart from the
- // standard executeAppelEvent:error: in that it handles
+ // standard executeAppleEvent:error: in that it handles
// taking script results and turning them into AEDescs of typeGTMOSAID
// instead of typeScript.
desc = [self descForScriptID:valueID component:component];
if (desc) {
[data setObject:desc forKey:GTMNSAppleScriptResultKey];
}
- }
- if (err) {
- error = [NSAppleScript _infoForOSAError:err];
+ } else {
+ error = [self gtm_errorDictionaryFromOSStatus:err component:component];
}
}
if (error) {
@@ -490,6 +500,98 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:);
}
}
+- (NSDictionary *)gtm_errorDictionaryFromOSStatus:(OSStatus)status
+ component:(ComponentInstance)component {
+ NSMutableDictionary *error = nil;
+ if (status == errOSAScriptError) {
+ error = [NSMutableDictionary dictionary];
+ struct {
+ OSType selector;
+ DescType desiredType;
+ SEL extractor;
+ id key;
+ } errMap[] = {
+ {
+ kOSAErrorNumber,
+ typeSInt16,
+ @selector(gtm_numberValue),
+ NSAppleScriptErrorNumber
+ },
+ {
+ kOSAErrorMessage,
+ typeText,
+ @selector(stringValue),
+ NSAppleScriptErrorMessage
+ },
+ {
+ kOSAErrorBriefMessage,
+ typeText,
+ @selector(stringValue),
+ NSAppleScriptErrorBriefMessage
+ },
+ { kOSAErrorApp,
+ typeText,
+ @selector(stringValue),
+ NSAppleScriptErrorAppName
+ },
+ { kOSAErrorRange,
+ typeOSAErrorRange,
+ @selector(gtm_OSAErrorRangeValue),
+ NSAppleScriptErrorRange
+ },
+ {
+ kOSAErrorPartialResult,
+ typeBest,
+ @selector(gtm_objectValue),
+ GTMNSAppleScriptErrorPartialResult
+ },
+ {
+ kOSAErrorOffendingObject,
+ typeBest,
+ @selector(gtm_objectValue),
+ GTMNSAppleScriptErrorOffendingObject
+ },
+ {
+ kOSAErrorExpectedType,
+ typeType,
+ @selector(gtm_fourCharCodeValue),
+ GTMNSAppleScriptErrorExpectedType
+ },
+ };
+ for (size_t i = 0; i < sizeof(errMap) / sizeof(errMap[0]); ++i) {
+ AEDesc errorResult = { typeNull, NULL };
+ OSStatus err = OSAScriptError(component,
+ errMap[i].selector,
+ errMap[i].desiredType,
+ &errorResult);
+ if (err == noErr) {
+ NSAppleEventDescriptor *desc = [[[NSAppleEventDescriptor alloc]
+ initWithAEDescNoCopy:&errorResult] autorelease];
+ id value = [desc performSelector:errMap[i].extractor];
+ if (value) {
+ [error setObject:value forKey:errMap[i].key];
+ }
+ }
+ }
+ } else if (status != noErr) {
+ // Unknown error. Do our best to give the user something good.
+ NSNumber *errNum = [NSNumber numberWithInt:status];
+ error
+ = [NSMutableDictionary dictionaryWithObject:errNum
+ forKey:NSAppleScriptErrorNumber];
+ NSString *briefMessage
+ = [NSString stringWithUTF8String:GetMacOSStatusErrorString(status)];
+ if (briefMessage) {
+ [error setValue:briefMessage forKey:NSAppleScriptErrorBriefMessage];
+ }
+ NSString *message
+ = [NSString stringWithUTF8String:GetMacOSStatusCommentString(status)];
+ if (message) {
+ [error setValue:message forKey:NSAppleScriptErrorMessage];
+ }
+ }
+ return error;
+}
@end
// Private methods for dealing with Scripts/Events and NSAppleEventDescriptors
@@ -543,3 +645,20 @@ GTM_METHOD_CHECK(NSAppleEventDescriptor, gtm_registerSelector:forTypes:count:);
}
@end
+@implementation NSAppleEventDescriptor (GTMAppleEventDescriptorOSAAdditions)
+
+- (id)gtm_OSAErrorRangeValue {
+ id value = nil;
+ NSAppleEventDescriptor *start = [self descriptorForKeyword:keyOSASourceStart];
+ if (start) {
+ NSAppleEventDescriptor *end = [self descriptorForKeyword:keyOSASourceEnd];
+ if (end) {
+ NSRange range = NSMakeRange([start int32Value], [end int32Value]);
+ value = [NSValue valueWithRange:range];
+ }
+ }
+ return value;
+}
+
+@end
+
diff --git a/Foundation/GTMNSAppleScript+HandlerTest.m b/Foundation/GTMNSAppleScript+HandlerTest.m
index e7d4ecc..dd559e9 100644
--- a/Foundation/GTMNSAppleScript+HandlerTest.m
+++ b/Foundation/GTMNSAppleScript+HandlerTest.m
@@ -39,11 +39,11 @@
// 10.5.8 and below. Radar 6126682.
SInt32 major, minor, bugfix;
[GTMSystemVersion getMajor:&major minor:&minor bugFix:&bugfix];
- if (!(GTMIsGarbageCollectionEnabled()
- && major <= 10 && minor <= 5 && bugfix <= 8)) {
- [super invokeTest];
- } else {
+ BOOL gcEnabled = GTMIsGarbageCollectionEnabled();
+ if (gcEnabled && major <= 10 && minor <= 5 && bugfix <= 8) {
NSLog(@"--- %@ NOT run because of GC incompatibilites ---", [self name]);
+ } else {
+ [super invokeTest];
}
}
@@ -159,7 +159,14 @@
parameters:[NSArray array]
error:&error];
STAssertNil(desc, @"Desc should by nil %@", desc);
- STAssertNotNil(error, nil);
+
+ // Verify that our error handling is working correctly.
+ STAssertEquals([[error allKeys] count], (NSUInteger)6, @"%@", error);
+ STAssertNotNil([error objectForKey:GTMNSAppleScriptErrorOffendingObject],
+ @"%@", error);
+ STAssertNotNil([error objectForKey:GTMNSAppleScriptErrorPartialResult],
+ @"%@", error);
+
error = nil;
desc = [script_ gtm_executePositionalHandler:@"testReturnParam"