diff options
author | gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3> | 2009-12-14 13:00:42 +0000 |
---|---|---|
committer | gtm.daemon <gtm.daemon@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3> | 2009-12-14 13:00:42 +0000 |
commit | 4365eeb9dd643c28472cff6f06ad8955d1d2f2c9 (patch) | |
tree | a41cf2eabde3460bd54fb788746b11b4f44c5c26 /Foundation | |
parent | 7252815552530ba1f552d1a48d3fae85ecf67b45 (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.h | 13 | ||||
-rw-r--r-- | Foundation/GTMNSAppleScript+Handler.m | 129 | ||||
-rw-r--r-- | Foundation/GTMNSAppleScript+HandlerTest.m | 17 |
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" |