diff --git a/IRRemoteResourceDownloadOperation.h b/IRRemoteResourceDownloadOperation.h index 869ae07..c89ec5f 100644 --- a/IRRemoteResourceDownloadOperation.h +++ b/IRRemoteResourceDownloadOperation.h @@ -22,9 +22,9 @@ - (void) remoteResourceDownloadOperationWillBegin:(IRRemoteResourceDownloadOperation *)anOperation; -// @optional +@optional // - (void) remoteResourceDownloadOperation:(IRRemoteResourceDownloadOperation *)anOperation didChangeProgress:(float_t)currentProgress; -// - (void) remoteResourceDownloadOperationDidEnd:(IRRemoteResourceDownloadOperation *)anOperation successfully:(BOOL)wasCompleted; +- (void) remoteResourceDownloadOperationDidEnd:(IRRemoteResourceDownloadOperation *)anOperation successfully:(BOOL)wasCompleted; @end diff --git a/IRRemoteResourceDownloadOperation.m b/IRRemoteResourceDownloadOperation.m index 442a1da..a50d9bd 100644 --- a/IRRemoteResourceDownloadOperation.m +++ b/IRRemoteResourceDownloadOperation.m @@ -41,7 +41,8 @@ - (void) onOriginalQueue:(void(^)(void))aBlock; @implementation IRRemoteResourceDownloadOperation @synthesize path, mimeType, url, processedBytes, totalBytes, preferredByteOffset, executing, finished, cancelled; -@synthesize fileHandle, connection; +@synthesize fileHandle = _fileHandle; +@synthesize connection = _connection; @synthesize actualDispatchQueue; @synthesize onMain; @synthesize appendedCompletionBlocks; @@ -52,41 +53,38 @@ + (IRRemoteResourceDownloadOperation *) operationWithURL:(NSURL *)aRemoteURL pat NSParameterAssert(aRemoteURL); NSParameterAssert(aLocalPath); - IRRemoteResourceDownloadOperation *returnedOperation = [[[self alloc] init] autorelease]; + IRRemoteResourceDownloadOperation *returnedOperation = [[self alloc] init]; returnedOperation.url = aRemoteURL; returnedOperation.path = aLocalPath; returnedOperation.onMain = aPrelude; returnedOperation.completionBlock = aBlock; + return returnedOperation; } -- (void) dealloc { +- (id)init { - [mimeType release]; + self = [super init]; - [path release]; - [url release]; - [fileHandle release]; - - __block NSURLConnection *nrConnection = connection; - dispatch_async(dispatch_get_main_queue(), ^ { - [nrConnection release]; - }); - - [onMain release]; - [appendedCompletionBlocks release]; - - [super dealloc]; + if (self) { + self.actualDispatchQueue = dispatch_queue_create("com.waveface.download.queue", DISPATCH_QUEUE_SERIAL); + } + + return self; + +} + +- (void) dealloc { + + [_connection cancel]; + dispatch_release(self.actualDispatchQueue); } - (void) onMainQueue:(void(^)(void))aBlock { - if (!self.actualDispatchQueue) - self.actualDispatchQueue = dispatch_get_current_queue(); - if ([NSThread isMainThread]) { aBlock(); return; @@ -111,13 +109,13 @@ - (void) start { return; } - if ([self isCancelled]) { - self.finished = YES; - return; - } - - self.executing = YES; - [self main]; + if ([self isCancelled]) { + self.finished = YES; + return; + } + + self.executing = YES; + [self main]; } @@ -135,18 +133,19 @@ - (void) main { [self onMainQueue: ^ { - NSMutableURLRequest *usedRequest = [NSMutableURLRequest requestWithURL:self.url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10]; - NSURLConnection *usedConnection = [[[NSURLConnection alloc] initWithRequest:usedRequest delegate:self startImmediately:NO] autorelease]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10]; - objc_setAssociatedObject(usedConnection, &kIRRemoteResourcesDownloadOperation_connectionRequest, usedRequest, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - self.connection = usedConnection; + NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; + + objc_setAssociatedObject(connection, &kIRRemoteResourcesDownloadOperation_connectionRequest, request, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + self.connection = connection; [self.delegate remoteResourceDownloadOperationWillBegin:self]; - usedConnection = [[[NSURLConnection alloc] initWithRequest:usedRequest delegate:self startImmediately:NO] autorelease]; + connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; - objc_setAssociatedObject(usedConnection, &kIRRemoteResourcesDownloadOperation_connectionRequest, usedRequest, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - self.connection = usedConnection; + objc_setAssociatedObject(connection, &kIRRemoteResourcesDownloadOperation_connectionRequest, request, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + self.connection = connection; // Do not mutate the URL // self.url = usedRequest.URL; @@ -165,6 +164,7 @@ - (void) cancel { [self onOriginalQueue: ^ { [self.fileHandle closeFile]; + self.fileHandle = nil; }]; if (self.executing) { @@ -235,30 +235,44 @@ - (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data - (void) connectionDidFinishLoading:(NSURLConnection *)connection { - if ([self isCancelled]) - return; - + if ([self isCancelled]) { + if ([self.delegate respondsToSelector:@selector(remoteResourceDownloadOperationDidEnd:successfully:)]) + [self.delegate remoteResourceDownloadOperationDidEnd:self successfully:NO]; + return; + } + [self onOriginalQueue: ^ { [self.fileHandle closeFile]; + self.fileHandle = nil; - if (self.mimeType) { + // no need to move downloaded file for JSON response + if (self.mimeType && ![self.mimeType isEqualToString:@"application/json"]) { // If there is a MIME type available, rename the underlying file - NSFileManager *fm = [NSFileManager defaultManager]; + CFStringRef const tag = (__bridge CFStringRef)self.mimeType; + NSString *utiType = (NSString *)CFBridgingRelease(UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, tag, NULL)); + + CFStringRef const tagClass = kUTTagClassFilenameExtension; + NSString *pathExtension = (NSString *)CFBridgingRelease(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)utiType, tagClass)); - NSString *utiType = [(NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (CFStringRef)self.mimeType, NULL) autorelease]; - NSString *pathExtension = [(NSString *)UTTypeCopyPreferredTagWithClass((CFStringRef)utiType, kUTTagClassFilenameExtension) autorelease]; - NSString *fromPath = self.path; - NSString *toPath = [[self.path stringByDeletingPathExtension] stringByAppendingPathExtension:pathExtension]; - NSError *error = nil; + if (pathExtension) { + + NSFileManager * const fm = [NSFileManager defaultManager]; + + NSString *fromPath = self.path; + NSString *toPath = [[self.path stringByDeletingPathExtension] stringByAppendingPathExtension:pathExtension]; + + NSError *error = nil; + + BOOL didMove = [fm moveItemAtPath:fromPath toPath:toPath error:&error]; + if (!didMove) { + NSLog(@"%s: %@ -> %@ Error: %@", __PRETTY_FUNCTION__, fromPath, toPath, error); + } else { + self.path = toPath; + } - BOOL didMove = [fm moveItemAtPath:fromPath toPath:toPath error:&error]; - if (!didMove) { - NSLog(@"%s: %@ -> %@ Error: %@", __PRETTY_FUNCTION__, fromPath, toPath, error); - } else { - self.path = toPath; } } @@ -267,6 +281,9 @@ - (void) connectionDidFinishLoading:(NSURLConnection *)connection { self.executing = NO; self.finished = YES; } + + if ([self.delegate respondsToSelector:@selector(remoteResourceDownloadOperationDidEnd:successfully:)]) + [self.delegate remoteResourceDownloadOperationDidEnd:self successfully:YES]; }]; @@ -280,6 +297,7 @@ - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)er [self onOriginalQueue: ^ { [self.fileHandle closeFile]; + self.fileHandle = nil; [[NSFileManager defaultManager] removeItemAtPath:self.path error:nil]; @@ -297,8 +315,9 @@ - (NSURLRequest *) connection:(NSURLConnection *)connection willSendRequest:(NSU if (!aRedirectResponse) return aRequest; - NSMutableURLRequest *mutatedRequest = [[[self underlyingRequest] mutableCopy] autorelease]; + NSMutableURLRequest *mutatedRequest = [[self underlyingRequest] mutableCopy]; mutatedRequest.URL = [aRequest URL]; + return mutatedRequest; } @@ -374,17 +393,17 @@ - (NSString *) description { - (NSMutableArray *) appendedCompletionBlocks { - if (appendedCompletionBlocks) - return appendedCompletionBlocks; + if (!appendedCompletionBlocks) { + appendedCompletionBlocks = [NSMutableArray array]; + } - appendedCompletionBlocks = [[NSMutableArray array] retain]; return appendedCompletionBlocks; } - (void) appendCompletionBlock:(void (^)(void))aBlock { - [self.appendedCompletionBlocks addObject:[[aBlock copy] autorelease]]; + [self.appendedCompletionBlocks addObject:[aBlock copy]]; } @@ -392,7 +411,7 @@ - (void) invokeCompletionBlocks { @synchronized (self) { - for (void(^aBlock)(void) in [[self.appendedCompletionBlocks copy] autorelease]) + for (void(^aBlock)(void) in self.appendedCompletionBlocks) aBlock(); self.appendedCompletionBlocks = [NSMutableArray array]; @@ -406,7 +425,7 @@ - (IRRemoteResourceDownloadOperation *) continuationOperationCancellingCurrentOp if (!self.path || !self.url) return nil; - __block IRRemoteResourceDownloadOperation *continuationOperation = [[[[self class] alloc] init] autorelease]; + __block IRRemoteResourceDownloadOperation *continuationOperation = [[[self class] alloc] init]; continuationOperation.path = self.path; continuationOperation.url = self.url; continuationOperation.preferredByteOffset = self.processedBytes; diff --git a/IRRemoteResourcesManager.h b/IRRemoteResourcesManager.h index 2e5e0fd..9092189 100644 --- a/IRRemoteResourcesManager.h +++ b/IRRemoteResourcesManager.h @@ -49,6 +49,8 @@ enum { @property (nonatomic, readwrite, copy) void (^onRemoteResourceDownloadOperationWillBegin)(IRRemoteResourceDownloadOperation *anOperation); +@property (nonatomic, readwrite, copy) void (^ onRemoteResourceDownloadOperationDidEnd) (IRRemoteResourceDownloadOperation *anOperation); + - (void) retrieveResourceAtURL:(NSURL *)inRemoteURL withCompletionBlock:(void(^)(NSURL *tempFileURLOrNil))aBlock; - (void) retrieveResourceAtURL:(NSURL *)inRemoteURL usingPriority:(NSOperationQueuePriority)priority forced:(BOOL)forcesReload withCompletionBlock:(void(^)(NSURL *tempFileURLOrNil))aBlock; diff --git a/IRRemoteResourcesManager.m b/IRRemoteResourcesManager.m index 41c1003..ed6fef3 100644 --- a/IRRemoteResourcesManager.m +++ b/IRRemoteResourcesManager.m @@ -81,9 +81,9 @@ - (id) init { queue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 1; operationQueue = dispatch_queue_create("iridia.remoteResourcesManager.operationQueue", DISPATCH_QUEUE_SERIAL); - enqueuedOperations = [[NSMutableArray array] retain]; + enqueuedOperations = [NSMutableArray array]; - allOperations = [[NSMutableDictionary dictionary] retain]; + allOperations = [NSMutableDictionary dictionary]; allOperationsQueue = dispatch_queue_create("iridia.remoteResourcesManager.operationsManagingQueue", DISPATCH_QUEUE_SERIAL); return self; @@ -96,20 +96,10 @@ - (void) dealloc { if (operationQueue) dispatch_release(operationQueue); - - [queue release]; - [enqueuedOperations release]; - [cacheDirectoryPath release]; - - [onRemoteResourceDownloadOperationWillBegin release]; - - [allOperations release]; - + if (allOperationsQueue) dispatch_release(allOperationsQueue); - [super dealloc]; - } @@ -290,30 +280,28 @@ - (IRRemoteResourceDownloadOperation *) enqueuedOperationForURL:(NSURL *)anURL { - (IRRemoteResourceDownloadOperation *) prospectiveOperationForURL:(NSURL *)anURL enqueue:(BOOL)enqueuesOperation { - __block __typeof__(self) nrSelf = self; + __weak IRRemoteResourcesManager *wSelf = self; __block IRRemoteResourceDownloadOperation *operation = nil; operation = [IRRemoteResourceDownloadOperation operationWithURL:anURL path:[self pathForCachedContentsOfRemoteURL:anURL usedProspectiveURL:NULL] prelude: ^ { - [nrSelf.delegate remoteResourcesManager:nrSelf didBeginDownloadingResourceAtURL:operation.url]; + [wSelf.delegate remoteResourcesManager:wSelf didBeginDownloadingResourceAtURL:operation.url]; } completion: ^ { BOOL didFinish = !!(operation.path); - NSString *operationPath = operation.path; + // NSString *operationPath = operation.path; NSURL *operationURL = operation.url; if (didFinish) { - [operation retain]; - dispatch_async(dispatch_get_main_queue(), ^ { [operation invokeCompletionBlocks]; - [operation autorelease]; + operation = nil; - [nrSelf notifyUpdatedResourceForRemoteURL:operationURL]; - [nrSelf.delegate remoteResourcesManager:nrSelf didFinishDownloadingResourceAtURL:operationURL]; + [wSelf notifyUpdatedResourceForRemoteURL:operationURL]; + [wSelf.delegate remoteResourcesManager:wSelf didFinishDownloadingResourceAtURL:operationURL]; }); @@ -321,23 +309,25 @@ - (IRRemoteResourceDownloadOperation *) prospectiveOperationForURL:(NSURL *)anUR dispatch_async(dispatch_get_main_queue(), ^ { - [nrSelf.delegate remoteResourcesManager:nrSelf didFailDownloadingResourceAtURL:operationURL]; + [wSelf.delegate remoteResourcesManager:wSelf didFailDownloadingResourceAtURL:operationURL]; + operation = nil; + }); } dispatch_async(dispatch_get_main_queue(), ^{ - [nrSelf beginSuspendingOperationQueue]; + [wSelf beginSuspendingOperationQueue]; - [nrSelf performInBackground: ^ { + [wSelf performInBackground: ^ { - [nrSelf enqueueOperationsIfNeeded]; + [wSelf enqueueOperationsIfNeeded]; dispatch_async(dispatch_get_main_queue(), ^{ - [nrSelf endSuspendingOperationQueue]; + [wSelf endSuspendingOperationQueue]; }); @@ -368,9 +358,16 @@ - (void) remoteResourceDownloadOperationWillBegin:(IRRemoteResourceDownloadOpera } +- (void) remoteResourceDownloadOperationDidEnd:(IRRemoteResourceDownloadOperation *)anOperation successfully:(BOOL)wasCompleted +{ + if (self.onRemoteResourceDownloadOperationDidEnd) + self.onRemoteResourceDownloadOperationDidEnd(anOperation); + +} + - (void) retrieveResourceAtURL:(NSURL *)inRemoteURL withCompletionBlock:(void(^)(NSURL *tempFileURLOrNil))aBlock { - [self retrieveResourceAtURL:inRemoteURL usingPriority:NSOperationQueuePriorityNormal forced:NO withCompletionBlock:aBlock]; + [self retrieveResourceAtURL:inRemoteURL usingPriority:NSOperationQueuePriorityHigh forced:NO withCompletionBlock:aBlock]; } @@ -390,93 +387,119 @@ - (void) retrieveResourceAtURL:(NSURL *)anURL usingPriority:(NSOperationQueuePri } - __block __typeof__(self) nrSelf = self; + __weak IRRemoteResourcesManager *wSelf = self; - [nrSelf performInBackground: ^ { + [wSelf performInBackground: ^ { - __block IRRemoteResourceDownloadOperation *operation = [self operationWithURL:anURL]; + BOOL isNewOperation = NO; + IRRemoteResourceDownloadOperation *operation = [wSelf operationWithURL:anURL]; if (!operation) { - operation = [self prospectiveOperationForURL:anURL enqueue:YES]; + operation = [wSelf prospectiveOperationForURL:anURL enqueue:YES]; operation.queuePriority = priority; - [nrSelf addOperation:operation]; - [operation appendCompletionBlock:^{ - [nrSelf removeOperation:operation]; - }]; + [wSelf addOperation:operation]; + + isNewOperation = YES; } else { - if (forcesReload && [nrSelf.queue.operations containsObject:operation]) { + if (forcesReload && [wSelf.queue.operations containsObject:operation]) { operation = [operation continuationOperationCancellingCurrentOperation:YES]; operation.queuePriority = priority; - [nrSelf addOperation:operation]; - [operation appendCompletionBlock:^{ - [nrSelf removeOperation:operation]; - }]; + [wSelf addOperation:operation]; + isNewOperation = YES; } + if (priority > operation.queuePriority) { + + operation.queuePriority = priority; + + } + } - if (aBlock) { - - [operation appendCompletionBlock: ^ { - - NSString *capturedPath = operation.path; - - if (![[NSFileManager defaultManager] fileExistsAtPath:capturedPath]) { - - [nrSelf performInBackground:^{ - aBlock(nil); - }]; - - return; - - } - - [nrSelf performInBackground: ^ { - - NSCParameterAssert([[NSFileManager defaultManager] fileExistsAtPath:capturedPath]); - aBlock([NSURL fileURLWithPath:capturedPath]); - - }]; - - }]; - - } - - dispatch_async(dispatch_get_main_queue(), ^{ + if (isNewOperation) { - [self beginSuspendingOperationQueue]; - - [nrSelf performInBackground: ^ { - - [self enqueueOperationsIfNeeded]; - - if ([self.enqueuedOperations containsObject:operation]) { - - // Hoist it — This is last come, first serve - - [[operation retain] autorelease]; - [self.enqueuedOperations removeObject:operation]; - [self.enqueuedOperations insertObject:operation atIndex:0]; - - } - - dispatch_async(dispatch_get_main_queue(), ^{ + if (aBlock) { - [self endSuspendingOperationQueue]; - - }); + [operation appendCompletionBlock: ^ { + + NSCAssert(![operation isCancelled], @"canceled operation shouldn't call completion blocks"); + + NSString *capturedPath = operation.path; + + if (![[NSFileManager defaultManager] fileExistsAtPath:capturedPath]) { + + if ([operation.mimeType isEqualToString:@"application/json"]) { + [wSelf performInBackground:^{ + [wSelf removeOperation:operation]; + aBlock(nil); + }]; + } else { + [wSelf performInBackground:^{ + [wSelf removeOperation:operation]; + aBlock([NSURL URLWithString:@"invalidFileURL"]); + }]; + } + + return; + + } + + [wSelf performInBackground: ^ { + + NSCParameterAssert([[NSFileManager defaultManager] fileExistsAtPath:capturedPath]); + aBlock([NSURL fileURLWithPath:capturedPath]); + double delayInSeconds = 2.0; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + [wSelf removeOperation:operation]; + }); + + }]; + + }]; + + } + + } + + if (isNewOperation || operation.queuePriority > NSOperationQueuePriorityNormal) { + + dispatch_async(dispatch_get_main_queue(), ^{ + + [wSelf beginSuspendingOperationQueue]; + + [wSelf performInBackground: ^ { + + if (!isNewOperation && [wSelf.enqueuedOperations containsObject:operation]) { + + // Hoist it — This is last come, first serve + + [wSelf.enqueuedOperations removeObject:operation]; + [wSelf.enqueuedOperations insertObject:operation atIndex:0]; + + } + + [wSelf enqueueOperationsIfNeeded]; + + dispatch_async(dispatch_get_main_queue(), ^{ + + [wSelf endSuspendingOperationQueue]; + + }); + + }]; + + }); + + } - }]; - - }); - }]; } @@ -528,14 +551,23 @@ - (void) enqueueOperationsIfNeeded { return (BOOL)![legitimateOperations containsObject:evaluatedObject]; }); - for (NSOperation *anOperation in insertedOperations) - if (![self.queue.operations containsObject:anOperation]) - [self.queue addOperation:anOperation]; - - [self.enqueuedOperations removeObjectsInArray:insertedOperations]; + for (IRRemoteResourceDownloadOperation *anOperation in insertedOperations) { + if (![self.queue.operations containsObject:anOperation]) { + // sometimes the delegate will be nil, so add a workaround here + if (!anOperation.delegate) { + anOperation.delegate = self; + } + [self.queue addOperation:anOperation]; + } + } + + [self.enqueuedOperations removeObjectsInArray:insertedOperations]; [postponedOperations enumerateObjectsUsingBlock: ^ (IRRemoteResourceDownloadOperation *anOperation, NSUInteger idx, BOOL *stop) { - [self.enqueuedOperations addObject:[anOperation continuationOperationCancellingCurrentOperation:YES]]; + // create a new download operation, because we don't support resume downloading + IRRemoteResourceDownloadOperation *newOperation = [self prospectiveOperationForURL:anOperation.url enqueue:YES]; + [self removeOperation:anOperation]; + [self addOperation:newOperation]; }]; } @@ -545,18 +577,20 @@ - (void) enqueueOperationsIfNeeded { - (NSString *) cacheDirectoryPath { - if (cacheDirectoryPath) - return cacheDirectoryPath; + if (!cacheDirectoryPath) { - NSString *prospectivePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:NSStringFromClass([self class])]; + NSString *prospectivePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:NSStringFromClass([self class])]; + + NSError *cacheDirectoryCreationError; + if (![[NSFileManager defaultManager] createDirectoryAtPath:prospectivePath withIntermediateDirectories:YES attributes:nil error:&cacheDirectoryCreationError]) { + NSLog(@"Error occurred while creating or assuring cache directory: %@", cacheDirectoryCreationError); + return nil; + } + + cacheDirectoryPath = [prospectivePath copy]; - NSError *cacheDirectoryCreationError; - if (![[NSFileManager defaultManager] createDirectoryAtPath:prospectivePath withIntermediateDirectories:YES attributes:nil error:&cacheDirectoryCreationError]) { - NSLog(@"Error occurred while creating or assuring cache directory: %@", cacheDirectoryCreationError); - return nil; } - cacheDirectoryPath = [prospectivePath retain]; return cacheDirectoryPath; } @@ -580,7 +614,7 @@ - (BOOL) clearCacheDirectory { - (void) notifyUpdatedResourceForRemoteURL:(NSURL *)inRemoteURL { - inRemoteURL = [[inRemoteURL copy] autorelease]; + inRemoteURL = [inRemoteURL copy]; dispatch_async(dispatch_get_main_queue(), ^ { @@ -609,7 +643,7 @@ - (void) retrieveImageAtURL:(NSURL *)inRemoteURL forced:(BOOL)forcesReload withC #else - NSParameterAssert(NO); + NSCParameterAssert(NO); #endif diff --git a/IRSiteReachability.j b/IRSiteReachability.j deleted file mode 100644 index a7163c6..0000000 --- a/IRSiteReachability.j +++ /dev/null @@ -1,33 +0,0 @@ -// IRSiteReachability.j -// Evadne Wu at Iridia, 2010 - - - - - -var _IRSiteReachabilityResult = nil; - -var kIRSiteReachabilityResultUnknown = @"IRSiteReachabilityResultUnknown", - kIRSiteReachabilityResultReachable = @"IRSiteReachabilityResultReachable", - kIRSiteReachabilityResultUnavailable = @"IRSiteReachabilityResultUnavailable"; - - - - - - - - - - -@implementation IRSiteReachability : CPObject { - -} - -+ (IRSiteReachabilityType) status { - - return _IRSiteReachabilityResult; - -} - -@end \ No newline at end of file diff --git a/IRWebAPIAuthenticator.m b/IRWebAPIAuthenticator.m index f6f69ab..26199c0 100644 --- a/IRWebAPIAuthenticator.m +++ b/IRWebAPIAuthenticator.m @@ -38,19 +38,6 @@ - (void) createTransformerBlocks { } -- (void) dealloc { - - self.globalRequestPreTransformerBlock = nil; - self.globalRequestPostTransformerBlock = nil; - self.globalResponsePreTransformerBlock = nil; - self.globalResponsePostTransformerBlock = nil; - - self.currentCredentials = nil; - - [super dealloc]; - -} - - (void) associateWithEngine:(IRWebAPIEngine *)inEngine { if (self.globalRequestPreTransformerBlock) diff --git a/IRWebAPIContext.j b/IRWebAPIContext.j deleted file mode 100644 index ba5e475..0000000 --- a/IRWebAPIContext.j +++ /dev/null @@ -1,78 +0,0 @@ -// IRWebAPIContext.j -// Evadne Wu at Iridia, 2010 - - - - - -@class IRWebAPIEngine; - - - - - -@implementation IRWebAPIContext : CPObject { - - CPURL baseURL @accessors; - -} - -+ (IRWebAPIContext) contextWithBaseURL:(CPURL)inURL { - - return [[[self class] alloc] initWithBaseURL:inURL]; - -} - - - - - -- (IRWebAPIContext) initWithBaseURL:(CPURL)inURL { - - self = [super init]; if (self == nil) return nil; - - [self setBaseURL:inURL]; - - return self; - -} - - - - - -- (CPURL) connectionURLForMethodNamed:(CPString)methodName additions:(CPString)additions { - - var baseURLString = String([[self baseURL] absoluteString]); - baseURLString = baseURLString.replace("#{methodName}", (methodName || "")); - baseURLString = baseURLString.replace("#{methodArguments}", (additions || "")); - - return [CPURL URLWithString:baseURLString]; - -} - -- (CPURL) connectionURLForPOSTMethodNamed:(CPString)methodName { - - var baseURLString = String([[self baseURL] absoluteString]); - baseURLString = baseURLString.replace("#{methodName}", (methodName || "")); - baseURLString = baseURLString.replace("#{methodArguments}", ""); - baseURLString = baseURLString.replace("?", ""); - - return [CPURL URLWithString:baseURLString]; - -} - - - - -- (CPString) description { - - return [super description] + @" — " + [baseURL description]; - -} - -@end - - - - diff --git a/IRWebAPICredentials.m b/IRWebAPICredentials.m index 1327602..c57c431 100644 --- a/IRWebAPICredentials.m +++ b/IRWebAPICredentials.m @@ -46,24 +46,6 @@ - (id) initWithIdentifier:(NSString *)inIdentifier qualifier:(NSString *)inQuali } -- (void) dealloc { - - self.identifier = nil; - self.identifierPlaceholder = nil; - self.identifierLabelText = nil; - - self.qualifier = nil; - self.qualifierPlaceholder = nil; - self.qualifierLabelText = nil; - - self.displayName = nil; - self.notes = nil; - self.userInfo = nil; - - [super dealloc]; - -} - - (id) initWithCoder:(NSCoder *)inCoder { self = [self init]; if (!self) return nil; @@ -98,27 +80,10 @@ - (void) encodeWithCoder:(NSCoder *)inCoder { } -- (id)copyWithZone:(NSZone *)zone { +- (id) copyWithZone:(NSZone *)zone { return self; -// Although copying sounds good, it breaks our hash in an authentication manager - - IRWebAPICredentials *copy = [[[self class] allocWithZone: zone] init]; - - copy.identifier = self.identifier; - copy.identifierPlaceholder = self.identifierPlaceholder; - copy.identifierLabelText = self.identifierLabelText; - copy.qualifier = self.qualifier; - copy.qualifierPlaceholder = self.qualifierPlaceholder; - copy.qualifierLabelText = self.qualifierLabelText; - copy.displayName = self.displayName; - copy.notes = self.notes; - copy.userInfo = [[self.userInfo copy] autorelease]; - copy.authenticated = self.authenticated; - - return copy; - } - (NSString *) description { diff --git a/IRWebAPIEngine+ExternalTransforms.h b/IRWebAPIEngine+ExternalTransforms.h index 3ac50ff..a75ae99 100644 --- a/IRWebAPIEngine+ExternalTransforms.h +++ b/IRWebAPIEngine+ExternalTransforms.h @@ -12,7 +12,7 @@ @interface IRWebAPIEngine (ExternalTransforms) - (NSURLRequest *) transformedRequestWithRequest:(NSURLRequest *)aRequest usingMethodName:(NSString *)aName; - +- (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse withRequestContext:(IRWebAPIRequestContext *)inRequestContext forMethodNamed:(NSString *)inMethodName; // Infers a context object from the request, punts it thru the global pre transformers, method-specific ones if any, then the global post transformers, and finally configures a new request with the transformed context object. @end diff --git a/IRWebAPIEngine+ExternalTransforms.m b/IRWebAPIEngine+ExternalTransforms.m index e11329e..f8b5987 100644 --- a/IRWebAPIEngine+ExternalTransforms.m +++ b/IRWebAPIEngine+ExternalTransforms.m @@ -7,14 +7,14 @@ // #import "IRWebAPIEngine+ExternalTransforms.h" +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIHelpers.h" @interface IRWebAPIEngine (ExternalTransforms_KnownPrivate) -- (NSDictionary *) baseRequestContextWithMethodName:(NSString *)inMethodName arguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil; +- (IRWebAPIRequestContext *) requestContextByTransformingContext:(IRWebAPIRequestContext *)inContext forMethodNamed:(NSString *)inMethodName; -- (NSDictionary *) requestContextByTransformingContext:(NSDictionary *)inContext forMethodNamed:(NSString *)inMethodName; - -- (NSURLRequest *) requestWithContext:(NSDictionary *)inContext; +//- (NSURLRequest *) requestWithContext:(IRWebAPIRequestContext *)inContext; @end @@ -22,14 +22,16 @@ @implementation IRWebAPIEngine (ExternalTransforms) - (NSURLRequest *) transformedRequestWithRequest:(NSURLRequest *)aRequest usingMethodName:(NSString *)aName { - NSDictionary *baseContext = [self baseRequestContextWithMethodName:aName arguments:nil options:nil]; + IRWebAPIRequestContext *baseContext = [IRWebAPIRequestContext new]; + baseContext.baseURL = [self.context baseURLForMethodNamed:aName]; + baseContext.engineMethod = aName; - NSURL *baseURL = [baseContext objectForKey:kIRWebAPIEngineRequestHTTPBaseURL]; - NSDictionary *headerFields = [baseContext objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - NSDictionary *arguments = [baseContext objectForKey:kIRWebAPIEngineRequestHTTPQueryParameters]; - NSData *httpBody = [baseContext objectForKey:kIRWebAPIEngineRequestHTTPBody]; - NSString *httpMethod = [baseContext objectForKey:kIRWebAPIEngineRequestHTTPMethod]; - IRWebAPIResponseParser responseParser = [baseContext objectForKey:kIRWebAPIEngineParser]; + NSURL *baseURL = baseContext.baseURL; + NSDictionary *headerFields = baseContext.headerFields; + NSDictionary *arguments = baseContext.queryParams; + NSData *httpBody = baseContext.body; + NSString *httpMethod = baseContext.method; + IRWebAPIResponseParser responseParser = baseContext.parser; if ([[aRequest allHTTPHeaderFields] count]) headerFields = [aRequest allHTTPHeaderFields]; @@ -59,22 +61,21 @@ - (NSURLRequest *) transformedRequestWithRequest:(NSURLRequest *)aRequest usingM } - NSDictionary *inferredContext = [NSDictionary dictionaryWithObjectsAndKeys: - - baseURL, kIRWebAPIEngineRequestHTTPBaseURL, - headerFields, kIRWebAPIEngineRequestHTTPHeaderFields, - arguments, kIRWebAPIEngineRequestHTTPQueryParameters, - httpBody, kIRWebAPIEngineRequestHTTPBody, - httpMethod, kIRWebAPIEngineRequestHTTPMethod, - responseParser, kIRWebAPIEngineParser, - aName, kIRWebAPIEngineIncomingMethodName, - - nil]; - - NSDictionary *transformedContext = [self requestContextByTransformingContext:inferredContext forMethodNamed:aName]; - NSURLRequest *returnedRequest = [self requestWithContext:transformedContext]; + IRWebAPIRequestContext *inferredContext = [IRWebAPIRequestContext new]; + inferredContext.baseURL = baseURL; + inferredContext.engineMethod = baseContext.engineMethod; + [headerFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [inferredContext setValue:obj forHeaderField:key]; + }]; + [arguments enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [inferredContext setValue:obj forQueryParam:key]; + }]; + inferredContext.body = httpBody; + inferredContext.method = httpMethod; + inferredContext.parser = responseParser; - return returnedRequest; + IRWebAPIRequestContext *transformedContext = [self requestContextByTransformingContext:inferredContext forMethodNamed:aName]; + return [[IRWebAPIRequestOperation alloc] initWithContext:transformedContext].request; } diff --git a/IRWebAPIEngine+FormMultipart.h b/IRWebAPIEngine+FormMultipart.h index 401cad5..d6857c7 100644 --- a/IRWebAPIEngine+FormMultipart.h +++ b/IRWebAPIEngine+FormMultipart.h @@ -7,9 +7,15 @@ // #import "IRWebAPIEngine.h" +#import "IRWebAPIRequestContext.h" +@interface IRWebAPIRequestContext (FormMultipart) -extern NSString * const kIRWebAPIEngineRequestContextFormMultipartFieldsKey; +@property (nonatomic, readonly, copy) NSDictionary *formMultipartFields; +- (void) removeAllFormMultipartFieldValues; +- (void) setValue:(id)obj forFormMultipartField:(NSString *)key; + +@end @interface IRWebAPIEngine (FormMultipart) @@ -17,102 +23,4 @@ extern NSString * const kIRWebAPIEngineRequestContextFormMultipartFieldsKey; @end - - - - -/* - - +defaultFormMultipartTransformer emits a block that expects : - - { - - kIRWebAPIEngineRequestContextFormMultipartFieldsKey = { - - aFormName = "aStringValue", - - anotherFormName = file://myFile.txt , - - anotherThing = <00325296> - - } - - } - - Where a string value gets sent, a URL gets mapped and dumped, its UTI guessed, and a NSData simply copied. - - The HTTP method is changed to POST and there must be nothing in the old HTTP body. - - - Since transforming could be expensive you explicitly hook the transformer up. - This category works with the +defaultCleanUpTemporaryFilesResponseTransformer so as to keep things neat. - - Here’s a use case: - - - (void) testMultipart { - - NSString *path = [[IRWebAPIEngine newTemporaryFileURL] path]; - - [[NSData dataWithData:UIImagePNGRepresentation(( ^ { - - UIGraphicsBeginImageContext([UIScreen mainScreen].bounds.size); - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor); - CGContextFillRect(context, [UIScreen mainScreen].bounds); - - [self.window.layer renderInContext:ctx]; - - UIImage *returnedImage = UIGraphicsGetImageFromCurrentImageContext(); - - UIGraphicsEndImageContext(); - - - return returnedImage; - - })())] writeToFile:path atomically:YES]; - - - IRWebAPIEngine *testEngine = [[[IRWebAPIEngine alloc] initWithContext:(( ^ { - - IRWebAPIContext *returnedContext = [[[IRWebAPIContext alloc] initWithBaseURL:[NSURL URLWithString:@"http://Museo.local/~evadne/postTest/"]] autorelease]; - - return returnedContext; - - })())] autorelease]; - - [testEngine.globalRequestPreTransformers addObject:[[testEngine class] defaultFormMultipartTransformer]]; - [testEngine.globalResponsePostTransformers addObject:[[testEngine class] defaultCleanUpTemporaryFilesResponseTransformer]]; - - [testEngine fireAPIRequestNamed:@"test.php" withArguments:nil options:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSDictionary dictionaryWithObjectsAndKeys: - - [NSURL fileURLWithPath:path], @"image", - - nil], kIRWebAPIEngineRequestContextFormMultipartFieldsKey, - - nil] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"Success: %@", inResponseOrNil); - - } failureHandler:nil]; - - } - - - This PHP snippet works with OS X 10.6’s bundled Apache: - - - -*/ - - - - +extern NSString * const kIRWebAPIEngineRequestContextFormMultipartFieldsKey; diff --git a/IRWebAPIEngine+FormMultipart.m b/IRWebAPIEngine+FormMultipart.m index 2244ed2..51b1e51 100644 --- a/IRWebAPIEngine+FormMultipart.m +++ b/IRWebAPIEngine+FormMultipart.m @@ -6,57 +6,90 @@ // Copyright 2011 Iridia Productions. All rights reserved. // +#import #import "IRWebAPIEngine+FormMultipart.h" - #import "IRWebAPIEngine+LocalCaching.h" +#import "IRWebAPIHelpers.h" NSString * const kIRWebAPIEngineRequestContextFormMultipartFieldsKey = @"kIRWebAPIEngineRequestContextFormMultipartFieldsKey"; +static NSString * const kFormMultipartFields = @"-[IRWebAPIRequestContext(FormMultipart) formMultipartFields]"; + +@implementation IRWebAPIRequestContext (FormMultipart) + +- (NSDictionary *) formMultipartFields { + + NSMutableDictionary *formMultipartFields = objc_getAssociatedObject(self, &kFormMultipartFields); + + if (!formMultipartFields) { + formMultipartFields = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, &kFormMultipartFields, formMultipartFields, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + return [formMultipartFields copy]; + +} + +- (void) removeAllFormMultipartFieldValues { + + [self willChangeValueForKey:@"formMultipartFields"]; + objc_setAssociatedObject(self, &kFormMultipartFields, nil, OBJC_ASSOCIATION_ASSIGN); + [self didChangeValueForKey:@"formMultipartFields"]; + +} + +- (void) setValue:(id)obj forFormMultipartField:(NSString *)key { + + NSMutableDictionary *formMultipartFields = objc_getAssociatedObject(self, &kFormMultipartFields); + + if (!formMultipartFields) { + formMultipartFields = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, &kFormMultipartFields, formMultipartFields, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + [self willChangeValueForKey:@"formMultipartFields"]; + + if (obj) { + [formMultipartFields setObject:obj forKey:key]; + } else { + [formMultipartFields removeObjectForKey:key]; + } + + [self didChangeValueForKey:@"formMultipartFields"]; + +} + +@end + @implementation IRWebAPIEngine (FormMultipart) + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { - return [[(^ (NSDictionary *inOriginalContext) { + return [(^ (IRWebAPIRequestContext *context) { - NSDictionary *formNamesToContents = [inOriginalContext objectForKey:kIRWebAPIEngineRequestContextFormMultipartFieldsKey]; + NSDictionary *formNamesToContents = context.formMultipartFields; - if(!formNamesToContents || ([formNamesToContents count] == 0)) - return inOriginalContext; - - NSMutableDictionary *returnedContext = [[inOriginalContext mutableCopy] autorelease]; + if (![formNamesToContents count]) + return context; NSError *error; - NSURL *fileHandleURL = [[[self class] newTemporaryFileURL] autorelease]; + NSURL *fileHandleURL = [[self class] newTemporaryFileURL]; if (![[NSFileManager defaultManager] createFileAtPath:[fileHandleURL path] contents:[NSData data] attributes:nil]) { - NSLog(@"Error creating file for URL %@.", fileHandleURL); - return (NSDictionary *)returnedContext; - + return context; } NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingToURL:fileHandleURL error:&error]; if (!fileHandle) { - NSLog(@"Error grabbing file handle for URL %@: %@", fileHandleURL, error); - return (NSDictionary *)returnedContext; - + return context; } [fileHandle truncateFileAtOffset:0]; [fileHandle seekToEndOfFile]; - - NSMutableDictionary *headerFields = [returnedContext objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - if (!headerFields) { - - headerFields = [NSMutableDictionary dictionary]; - [returnedContext setObject:headerFields forKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - - } - - [headerFields setObject:@"8bit" forKey:@"Content-Transfer-Encoding"]; - + [context setValue:@"8bit" forHeaderField:@"Content-Transfer-Encoding"]; NSString *mineBoundary = [NSString stringWithFormat:@"----_=_%@_%@_%@_=_----", @@ -70,35 +103,24 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { NSData *newLineData = [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]; NSData *separatorData = [@"--" dataUsingEncoding:NSUTF8StringEncoding]; - [headerFields setObject:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", mineBoundary] forKey:@"Content-Type"]; + NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", mineBoundary]; + [context setValue:contentType forHeaderField:@"Content-Type"]; // Start writing for (id incomingFormName in formNamesToContents) { - // -- ↵ + if ([incomingFormName isEqualToString:@"file_data"]) { + continue; + } + + // -- ↵ [fileHandle writeData:separatorData]; [fileHandle writeData:boundaryData]; [fileHandle writeData:newLineData]; id incomingObject = [formNamesToContents objectForKey:incomingFormName]; - if ([incomingObject isKindOfClass:[NSString class]]) { - - // Append contents of string - - [fileHandle writeData:[[NSString stringWithFormat: - - @"Content-Disposition: form-data; name=\"%@\"", - incomingFormName - - ] dataUsingEncoding:NSUTF8StringEncoding]]; - - [fileHandle writeData:newLineData]; - [fileHandle writeData:newLineData]; - - [fileHandle writeData:[(NSString *)incomingObject dataUsingEncoding:NSUTF8StringEncoding]]; - - } else if ([incomingObject isKindOfClass:[NSURL class]]) { + if ([incomingFormName isEqualToString:@"file"]) { // Append contents of file @@ -106,14 +128,14 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { @"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"", incomingFormName, - [[(NSURL *)incomingObject path] lastPathComponent] + incomingObject ] dataUsingEncoding:NSUTF8StringEncoding]]; [fileHandle writeData:newLineData]; - NSString *mimeType = IRWebAPIKitMIMETypeOfExtension([[[(NSURL *)incomingObject path] lastPathComponent] pathExtension]); + NSString *mimeType = IRWebAPIKitMIMETypeOfExtension([incomingObject pathExtension]); [fileHandle writeData:[[NSString stringWithFormat: @@ -124,15 +146,31 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { [fileHandle writeData:newLineData]; [fileHandle writeData:newLineData]; - [fileHandle writeData:[NSData dataWithContentsOfMappedFile:[(NSURL *)incomingObject path]]]; + [fileHandle writeData:[formNamesToContents objectForKey:@"file_data"]]; + } else if ([incomingObject isKindOfClass:[NSString class]]) { + + // Append contents of string + + [fileHandle writeData:[[NSString stringWithFormat: + + @"Content-Disposition: form-data; name=\"%@\"", + incomingFormName + + ] dataUsingEncoding:NSUTF8StringEncoding]]; + + [fileHandle writeData:newLineData]; + [fileHandle writeData:newLineData]; + + [fileHandle writeData:[(NSString *)incomingObject dataUsingEncoding:NSUTF8StringEncoding]]; + } else if ([incomingObject isKindOfClass:[NSData class]]) { - [fileHandle writeData:(NSData *)incomingObject]; + [fileHandle writeData:(NSData *)incomingObject]; } else { - NSAssert(NO, @"%s Can’t understand incoming object %@", __PRETTY_FUNCTION__, incomingObject); + NSCAssert(NO, @"%s Can’t understand incoming object %@", __PRETTY_FUNCTION__, incomingObject); } @@ -148,26 +186,21 @@ + (IRWebAPIRequestContextTransformer) defaultFormMultipartTransformer { [fileHandle closeFile]; - [returnedContext setObject:[NSData dataWithContentsOfMappedFile:[fileHandleURL path]] forKey:kIRWebAPIEngineRequestHTTPBody]; - - - NSMutableArray *temporaryFileURLs = [returnedContext objectForKey:kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey]; - if (!temporaryFileURLs) { - - temporaryFileURLs = [NSMutableArray array]; - [returnedContext setObject:temporaryFileURLs forKey:kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey]; - - } - - [temporaryFileURLs addObject:fileHandleURL]; - - [returnedContext setObject:temporaryFileURLs forKey:kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey]; - [returnedContext removeObjectForKey:kIRWebAPIEngineRequestContextFormMultipartFieldsKey]; - [returnedContext setObject:@"POST" forKey:kIRWebAPIEngineRequestHTTPMethod]; - - return (NSDictionary *)returnedContext; + [context setBody:[NSData dataWithContentsOfFile:[fileHandleURL path] options:NSDataReadingMappedIfSafe error:nil]]; + [context addCacheFileURL:fileHandleURL]; + [context removeAllFormMultipartFieldValues]; + [context setMethod:@"POST"]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:[fileHandleURL path]]) { + NSError *error = nil; + [[NSFileManager defaultManager] removeItemAtURL:fileHandleURL error:&error]; + if (error != nil) { + NSLog(@"failed to remove cached file for multipart transformer: %@", fileHandleURL); + } + } + return context; - }) copy] autorelease]; + }) copy]; } diff --git a/IRWebAPIEngine+FormURLEncoding.h b/IRWebAPIEngine+FormURLEncoding.h index ce9a911..1b108e1 100644 --- a/IRWebAPIEngine+FormURLEncoding.h +++ b/IRWebAPIEngine+FormURLEncoding.h @@ -8,12 +8,18 @@ #import "IRWebAPIEngine.h" -extern NSString * const kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey; +@interface IRWebAPIRequestContext (FormURLEncoding) -NSData * IRWebAPIEngineFormURLEncodedDataWithDictionary (NSDictionary *dictionary); +@property (nonatomic, readonly, copy) NSDictionary *formURLEncodingFields; +- (void) removeAllFormURLEncodingFieldValues; +- (void) setValue:(id)obj forFormURLEncodingField:(NSString *)key; + +@end @interface IRWebAPIEngine (FormURLEncoding) + (IRWebAPIRequestContextTransformer) defaultFormURLEncodingTransformer; @end + +extern NSData * IRWebAPIEngineFormURLEncodedDataWithDictionary (NSDictionary *formNamesToContents); diff --git a/IRWebAPIEngine+FormURLEncoding.m b/IRWebAPIEngine+FormURLEncoding.m index 9c6b1db..a48f379 100644 --- a/IRWebAPIEngine+FormURLEncoding.m +++ b/IRWebAPIEngine+FormURLEncoding.m @@ -9,41 +9,79 @@ #import "IRWebAPIHelpers.h" #import "IRWebAPIEngine+FormURLEncoding.h" -NSString * const kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey = @"IRWebAPIEngineRequestContextFormURLEncodingFields"; +extern NSData * IRWebAPIEngineFormURLEncodedDataWithDictionary (NSDictionary *dictionary); + +static NSString * const kFormURLEncodingFields = @"-[IRWebAPIRequestContext(FormURLEncoding) formURLEncodingFields]"; + +@implementation IRWebAPIRequestContext (FormURLEncoding) + +- (NSDictionary *) formURLEncodingFields { + + NSMutableDictionary *formURLEncodingFields = objc_getAssociatedObject(self, &kFormURLEncodingFields); + + if (!formURLEncodingFields) { + formURLEncodingFields = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, &kFormURLEncodingFields, formURLEncodingFields, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + return [formURLEncodingFields copy]; + +} + +- (void) removeAllFormURLEncodingFieldValues { + + [self willChangeValueForKey:@"formURLEncodingFields"]; + objc_setAssociatedObject(self, &kFormURLEncodingFields, nil, OBJC_ASSOCIATION_ASSIGN); + [self didChangeValueForKey:@"formURLEncodingFields"]; + +} + +- (void) setValue:(id)obj forFormURLEncodingField:(NSString *)key { + + NSMutableDictionary *formURLEncodingFields = objc_getAssociatedObject(self, &kFormURLEncodingFields); + + if (!formURLEncodingFields) { + formURLEncodingFields = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, &kFormURLEncodingFields, formURLEncodingFields, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + [self willChangeValueForKey:@"formURLEncodingFields"]; + + if (obj) { + [formURLEncodingFields setObject:obj forKey:key]; + } else { + [formURLEncodingFields removeObjectForKey:key]; + } + + [self didChangeValueForKey:@"formURLEncodingFields"]; + +} + +@end + @implementation IRWebAPIEngine (FormURLEncoding) + (IRWebAPIRequestContextTransformer) defaultFormURLEncodingTransformer { - return [[(^ (NSDictionary *inOriginalContext) { + return [(^ (IRWebAPIRequestContext *context) { - NSDictionary *formNamesToContents = [inOriginalContext objectForKey:kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey]; - - if (![formNamesToContents count]) - return inOriginalContext; - - NSMutableDictionary *returnedContext = [[inOriginalContext mutableCopy] autorelease]; - NSMutableDictionary *headerFields = [returnedContext objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - - if (!headerFields) { - headerFields = [NSMutableDictionary dictionary]; - [returnedContext setObject:headerFields forKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - } - - [headerFields setObject:@"8bit" forKey:@"Content-Transfer-Encoding"]; - [headerFields setObject:@"application/x-www-form-urlencoded" forKey:@"Content-Type"]; - - NSData *sentData = IRWebAPIEngineFormURLEncodedDataWithDictionary(formNamesToContents); + NSDictionary *formURLEncodingFields = context.formURLEncodingFields; + + if (![formURLEncodingFields count]) + return context; - [returnedContext setObject:sentData forKey:kIRWebAPIEngineRequestHTTPBody]; + [context setValue:@"8bit" forHeaderField:@"Content-Transfer-Encoding"]; + [context setValue:@"application/x-www-form-urlencoded" forHeaderField:@"Content-Type"]; - [returnedContext removeObjectForKey:kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey]; + [context setBody:IRWebAPIEngineFormURLEncodedDataWithDictionary(formURLEncodingFields)]; + [context removeAllFormURLEncodingFieldValues]; - [returnedContext setObject:@"POST" forKey:kIRWebAPIEngineRequestHTTPMethod]; + [context setMethod:@"POST"]; - return (NSDictionary *)returnedContext; + return context; - }) copy] autorelease]; + }) copy]; } diff --git a/IRWebAPIEngine+LocalCaching.h b/IRWebAPIEngine+LocalCaching.h index 1c0f04c..7c9b7ad 100644 --- a/IRWebAPIEngine+LocalCaching.h +++ b/IRWebAPIEngine+LocalCaching.h @@ -7,11 +7,15 @@ // #import "IRWebAPIEngine.h" +#import "IRWebAPIRequestContext.h" -#import +@interface IRWebAPIRequestContext (LocalCaching) +@property (nonatomic, readonly, copy) NSArray *cacheFileURLs; +- (void) removeAllCacheFileURLValues; +- (void) addCacheFileURL:(NSURL *)obj; -extern NSString * const kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey; +@end @interface IRWebAPIEngine (LocalCaching) diff --git a/IRWebAPIEngine+LocalCaching.m b/IRWebAPIEngine+LocalCaching.m index cfc0e37..9dc8b4d 100644 --- a/IRWebAPIEngine+LocalCaching.m +++ b/IRWebAPIEngine+LocalCaching.m @@ -11,12 +11,46 @@ #import "IRWebAPIEngine+LocalCaching.h" #import "IRWebAPIHelpers.h" +static NSString * const kCacheFileURLS = @"-[IRWebAPIRequestContext(LocalCaching) cacheFileURLs]"; -NSString * const kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey = @"kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey"; -NSString * const kIRWebAPIEngineLocallocalCacheDirectoryPath = @"kIRWebAPIEngineLocalCachingBasePath"; +@implementation IRWebAPIRequestContext (LocalCaching) +- (NSArray *) cacheFileURLs { + return [objc_getAssociatedObject(self, &kCacheFileURLS) copy]; +} + +- (void) removeAllCacheFileURLValues { + + [self willChangeValueForKey:@"cacheFileURLs"]; + objc_setAssociatedObject(self, &kCacheFileURLS, nil, OBJC_ASSOCIATION_ASSIGN); + [self didChangeValueForKey:@"cacheFileURLs"]; + +} + +- (void) addCacheFileURL:(NSURL *)obj { + + NSMutableArray *cacheFileURLs = objc_getAssociatedObject(self, &kCacheFileURLS); + + if (!cacheFileURLs) { + cacheFileURLs = [NSMutableArray array]; + objc_setAssociatedObject(self, &cacheFileURLs, cacheFileURLs, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + [self willChangeValueForKey:@"cacheFileURLs"]; + + if (obj) { + [cacheFileURLs addObject:obj]; + } else { + [cacheFileURLs removeObject:obj]; + } + + [self didChangeValueForKey:@"cacheFileURLs"]; + +} + +@end @implementation IRWebAPIEngine (LocalCaching) @@ -26,58 +60,37 @@ + (NSURL *) newTemporaryFileURL { NSString *applicationCacheDirectory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]; NSString *preferredCacheDirectoryPath = [applicationCacheDirectory stringByAppendingPathComponent:NSStringFromClass([self class])]; - NSError *error; - if (![[NSFileManager defaultManager] createDirectoryAtPath:preferredCacheDirectoryPath withIntermediateDirectories:YES attributes:nil error:&error]) { + if ([[NSFileManager defaultManager] createDirectoryAtPath:preferredCacheDirectoryPath withIntermediateDirectories:YES attributes:nil error:nil]) + return [NSURL fileURLWithPath:[preferredCacheDirectoryPath stringByAppendingPathComponent:IRWebAPIKitNonce()]]; - NSLog(@"Erorr occurred while assuring cache directory existence: %@", error); - return nil; - - }; - - NSURL *fileURL = [[NSURL fileURLWithPath:[preferredCacheDirectoryPath stringByAppendingPathComponent:IRWebAPIKitNonce()]] retain]; - return fileURL; + return nil; } + (BOOL) cleanUpTemporaryFileAtURL:(NSURL *)inTemporaryFileURL { - NSError *error; - - if (![[NSFileManager defaultManager] removeItemAtURL:inTemporaryFileURL error:&error]) { - - NSLog(@"Error removing file at URL %@: %@", inTemporaryFileURL, error); - return NO; - - } else { - - NSLog(@"Removed %@", inTemporaryFileURL); - - } - - return YES; + return [[NSFileManager defaultManager] removeItemAtURL:inTemporaryFileURL error:nil]; } + (IRWebAPIResponseContextTransformer) defaultCleanUpTemporaryFilesResponseTransformer { - return [[(^ (NSDictionary *inParsedResponse, NSDictionary *inResponseContext) { + return [(^ (NSDictionary *inParsedResponse, IRWebAPIRequestContext *inResponseContext) { - NSArray *cachedFileURLs = [[inResponseContext objectForKey:kIRWebAPIEngineResponseContextOriginalRequestContext] objectForKey:kIRWebAPIEngineRequestContextLocalCachingTemporaryFileURLsKey]; + NSArray *cachedFileURLs = inResponseContext.cacheFileURLs; - // DISPATCH_QUEUE_PRIORITY_BACKGROUND is unrecognized by LLVM 2.0 so we’re using the number it uses - dispatch_async(dispatch_get_global_queue(-2, 0), ^ { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^ { - if (cachedFileURLs) for (NSURL *aFileURL in cachedFileURLs) - [self cleanUpTemporaryFileAtURL:aFileURL]; + [self cleanUpTemporaryFileAtURL:aFileURL]; }); return inParsedResponse; - }) copy] autorelease]; + }) copy]; } diff --git a/IRWebAPIEngine+OperationFiring.h b/IRWebAPIEngine+OperationFiring.h new file mode 100644 index 0000000..5e5c493 --- /dev/null +++ b/IRWebAPIEngine+OperationFiring.h @@ -0,0 +1,27 @@ +// +// IRWebAPIEngine+OperationFiring.h +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import "IRWebAPIEngine.h" + +@interface IRWebAPIEngine (OperationFiring) + +- (void) fireAPIRequestNamed:(NSString *)methodName withArguments:(NSDictionary *)arguments options:(NSDictionary *)options validator:(IRWebAPIResponseValidator)validatorBlock successHandler:(IRWebAPICallback)successBlock failureHandler:(IRWebAPICallback)failureBlock; + +@end + +extern NSString * const kIRWebAPIEngineRequestHTTPBaseURL; +extern NSString * const kIRWebAPIEngineRequestHTTPHeaderFields; +extern NSString * const kIRWebAPIEngineRequestHTTPPOSTParameters; +extern NSString * const kIRWebAPIEngineRequestHTTPBody; +extern NSString * const kIRWebAPIEngineRequestHTTPQueryParameters; +extern NSString * const kIRWebAPIEngineRequestHTTPMethod; +extern NSString * const kIRWebAPIEngineParser; +extern NSString * const kIRWebAPIEngineResponseContextURLResponse; +extern NSString * const kIRWebAPIRequestTimeout; + +extern NSString * const kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey; diff --git a/IRWebAPIEngine+OperationFiring.m b/IRWebAPIEngine+OperationFiring.m new file mode 100644 index 0000000..f0a09ad --- /dev/null +++ b/IRWebAPIEngine+OperationFiring.m @@ -0,0 +1,73 @@ +// +// IRWebAPIEngine+OperationFiring.m +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import "IRWebAPIEngine+OperationFiring.h" +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIEngine+FormURLEncoding.h" +#import "IRWebAPIRequestOperation.h" +#import "IRWebAPIEngine+FormMultipart.h" + +NSString * const kIRWebAPIEngineRequestHTTPBaseURL = @"kIRWebAPIEngineRequestHTTPBaseURL"; +NSString * const kIRWebAPIEngineRequestHTTPHeaderFields = @"kIRWebAPIEngineRequestHTTPHeaderFields"; +NSString * const kIRWebAPIEngineRequestHTTPPOSTParameters = @"kIRWebAPIEngineRequestHTTPPOSTParameters"; +NSString * const kIRWebAPIEngineRequestHTTPBody = @"kIRWebAPIEngineRequestHTTPBody"; +NSString * const kIRWebAPIEngineRequestHTTPQueryParameters = @"kIRWebAPIEngineRequestHTTPQueryParameters"; +NSString * const kIRWebAPIEngineRequestHTTPMethod = @"kIRWebAPIEngineRequestHTTPMethod"; +NSString * const kIRWebAPIEngineParser = @"kIRWebAPIEngineParser"; +NSString * const kIRWebAPIEngineResponseContextURLResponse = @"kIRWebAPIEngineResponseContextURLResponse"; +NSString * const kIRWebAPIRequestTimeout = @"kIRWebAPIRequestTimeout"; + +NSString * const kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey = @"kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey"; + +@implementation IRWebAPIEngine (OperationFiring) + +- (void) fireAPIRequestNamed:(NSString *)methodName withArguments:(NSDictionary *)arguments options:(NSDictionary *)options validator:(IRWebAPIResponseValidator)validatorBlock successHandler:(IRWebAPICallback)successBlock failureHandler:(IRWebAPICallback)failureBlock { + + IRWebAPIRequestOperation *operation = [self operationForMethod:methodName arguments:arguments contextOverride:^(IRWebAPIRequestContext *context) { + + if ([options objectForKey:kIRWebAPIEngineRequestHTTPBaseURL]) + context.baseURL = [options objectForKey:kIRWebAPIEngineRequestHTTPBaseURL]; + + [[options objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [context setValue:obj forHeaderField:key]; + }]; + + if ([options objectForKey:kIRWebAPIEngineRequestHTTPBody]) + context.body = [options objectForKey:kIRWebAPIEngineRequestHTTPBody]; + + [[options objectForKey:kIRWebAPIEngineRequestHTTPQueryParameters] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [context setValue:key forQueryParam:key]; + }]; + + if ([options objectForKey:kIRWebAPIEngineRequestHTTPMethod]) + context.method = [options objectForKey:kIRWebAPIEngineRequestHTTPMethod]; + + if ([options objectForKey:kIRWebAPIEngineParser]) + context.parser = [options objectForKey:kIRWebAPIEngineParser]; + + if ([options objectForKey:kIRWebAPIEngineResponseContextURLResponse]) + context.urlResponse = [options objectForKey:kIRWebAPIEngineResponseContextURLResponse]; + + if ([options objectForKey:kIRWebAPIRequestTimeout]) + context.timeout = [[options objectForKey:kIRWebAPIRequestTimeout] doubleValue]; + + [[options objectForKey:kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [context setValue:obj forFormURLEncodingField:key]; + }]; + + [[options objectForKey:kIRWebAPIEngineRequestContextFormMultipartFieldsKey] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [context setValue:obj forFormMultipartField:key]; + }]; + + } validator:validatorBlock successBlock:successBlock failureBlock:failureBlock]; + + [self.queue addOperation:operation]; + +} + +@end diff --git a/IRWebAPIEngine.h b/IRWebAPIEngine.h index eef61b6..e047efa 100644 --- a/IRWebAPIEngine.h +++ b/IRWebAPIEngine.h @@ -7,21 +7,17 @@ // #import -#import "IRWebAPIKit.h" -extern NSString * const kIRWebAPIEngineResponseDictionaryIncomingData; -extern NSString * const kIRWebAPIEngineResponseDictionaryOutgoingContext; -extern NSString * const kIRWebAPIEngineAssociatedDataStore; -extern NSString * const kIRWebAPIEngineAssociatedResponseContext; -extern NSString * const kIRWebAPIEngineAssociatedSuccessHandler; -extern NSString * const kIRWebAPIEngineAssociatedFailureHandler; -extern NSString * const kIRWebAPIEngineUnderlyingError; +#import "IRWebAPIKitDefines.h" +@class IRWebAPIRequestOperation, IRWebAPIEngineContext; @interface IRWebAPIEngine : NSObject -@property (nonatomic, readwrite, copy) IRWebAPIResponseParser parser; -@property (nonatomic, readonly, retain) IRWebAPIContext *context; +- (id) initWithContext:(IRWebAPIEngineContext *)inContext; + +@property (nonatomic, readonly, strong) IRWebAPIEngineContext *context; +@property (nonatomic, readonly, strong) NSOperationQueue *queue; @property (nonatomic, readonly, retain) NSMutableArray *globalRequestPreTransformers; @property (nonatomic, readonly, retain) NSMutableDictionary *requestTransformers; @@ -31,28 +27,8 @@ extern NSString * const kIRWebAPIEngineUnderlyingError; @property (nonatomic, readonly, retain) NSMutableDictionary *responseTransformers; @property (nonatomic, readonly, retain) NSMutableArray *globalResponsePostTransformers; -- (id) initWithContext:(IRWebAPIContext *)inContext; - -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil validator:(IRWebAPIResposeValidator)inValidator successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler; - -- (NSMutableArray *) requestTransformersForMethodNamed:(NSString *)inMethodName; -- (NSMutableArray *) responseTransformersForMethodNamed:(NSString *)inMethodName; - -// Convenience. Putting them in a category does not assure compiler checking. +- (IRWebAPIRequestOperation *) operationForMethod:(NSString *)method arguments:(NSDictionary *)arguments validator:(IRWebAPIResponseValidator)validator successBlock:(IRWebAPICallback)successBlock failureBlock:(IRWebAPICallback)failureBlock; -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler; - -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler; +- (IRWebAPIRequestOperation *) operationForMethod:(NSString *)method arguments:(NSDictionary *)arguments contextOverride:(void(^)(IRWebAPIRequestContext *))overrideBlock validator:(IRWebAPIResponseValidator)validator successBlock:(IRWebAPICallback)successBlock failureBlock:(IRWebAPICallback)failureBlock; @end - - - - - -#import "IRWebAPIEngine+LocalCaching.h" -#import "IRWebAPIEngine+FormMultipart.h" - - - - diff --git a/IRWebAPIEngine.j b/IRWebAPIEngine.j deleted file mode 100644 index 9dc3f09..0000000 --- a/IRWebAPIEngine.j +++ /dev/null @@ -1,436 +0,0 @@ -// IRWebAPIEngine.j -// Evadne Wu at Iridia, 2010 - -@import - - - - - -var kIRWebAPIEngineSerializationSchemes = { - -// TODO: Reference http://www.w3.org/TR/html401/interact/forms.html - - "IRWebAPIEngineSerializationSchemeOrdinaryFlat": function (inDictionary) { - - var returnString = @"", - enumerator = [inDictionary keyEnumerator], - key = nil; - - while (key = [enumerator nextObject]) - returnString += @"&" + encodeURIComponent(key) + @"=" + encodeURIComponent([inDictionary objectForKey:key]); - - return returnString.replace(/^&/, ""); - - } - -}; - - - - - -var kIRWebAPIEngineConnectionTimeoutTimeIntervalUserInfoDictionaryKey = @"IRWebAPIEngineConnectionTimeoutTimeInterval", - kIRWebAPIEnginePrintDebuggingInfoDictionaryKey = @"IRWebAPIEnginePrintDebuggingInfo", - kIRWebAPIEngineSerializationSchemeKeyOrdinaryFlat = "IRWebAPIEngineSerializationSchemeOrdinaryFlat", - kIRWebAPIEngineConnectionDidReceiveDataNotification = @"IRWebAPIEngineConnectionDidReceiveDataNotification", - kIRWebAPIEngineConnectionDidFailNotification = @"IRWebAPIEngineConnectionDidFailNotification"; - - - - - -@class IRWebAPIContext; - - - - - -@implementation IRWebAPIEngine : CPObject { - - IRWebAPIContext context; - id delegate @accessors; - CPMutableSet aliveConnections; - - -// Note. The global transformations could be overriding points for authentication purposes, -// But if you want to do something XSLT’y, do them in argument / response transformations for every method involved. - - CPMutableArray globalArgumentTransformations; // Called on all outgoing method invocations - CPMutableDictionary requestArgumentTransformations; // Key is method name - CPMutableDictionary responseTransformations; // Key is method name - CPMutableArray globalResponseTransformations; // Called on all incoming responses - - CPMutableDictionary successHandlersForConnections; // Key is connection UID - CPMutableDictionary failureHandlersForConnections; // Key is connection UID - - CPMutableDictionary mockResponses; // Key is method name, contains mock JS Objects - - /* (CPString) */ IRWebAPIEngineSerializationSchemeKey serializationScheme @accessors; - - BOOL debugMode; - - Class connectionClass @accessors; - -} - - - - - -+ (IRProtocol) delegateProtocol { - - return [IRProtocol protocolWithSelectorsAndOptionalFlags: - - @selector(transformationForMethodCallNamed:engine:), true, - @selector(transformationForMethodFeedbackNamed:engine:), true - - ]; - -} - - - - - -+ (IRWebAPIEngine) engineWithContext:(IRWebAPIContext)inContext { - - self = [[self alloc] initWithContext:inContext]; if (self == nil) return nil; - - return self; - -} - - - - - -- (IRWebAPIEngine) initWithContext:(IRWebAPIContext)inContext { - - self = [super init]; if (self == nil) return nil; - - context = inContext; - serializationScheme = kIRWebAPIEngineSerializationSchemeKeyOrdinaryFlat; - - globalArgumentTransformations = [CPMutableArray array]; - requestArgumentTransformations = [CPMutableDictionary dictionary]; - - globalResponseTransformations = [CPMutableArray array]; - responseTransformations = [CPMutableDictionary dictionary]; - - successHandlersForConnections = [CPMutableDictionary dictionary]; - failureHandlersForConnections = [CPMutableDictionary dictionary]; - -// connectionClass = [IRJSONPMockConnection class]; - connectionClass = [CPJSONPConnection class]; - - mockResponses = [CPMutableDictionary dictionary]; - - debugMode = ([[[CPBundle bundleForClass:[[[CPApplication sharedApplication] delegate] class]] infoDictionary] objectForKey:kIRWebAPIEnginePrintDebuggingInfoDictionaryKey] || NO); - - return self; - -} - - - - - -- (void) enqueueGlobalArgumentTransformation:(Function)transformation { - - [globalArgumentTransformations addObject:transformation]; - -} - -- (void) enqueueArgumentTransformation:(Function)transformation forMethodNamed:(CPString)methodName { - - [requestArgumentTransformations setObject:transformation forKey:methodName]; - -} - - -- (CPDictionary) transformedArguments:(CPDictionary)inArguments forMethodNamed:(CPString)methodName { - - var requestObject = [inArguments mutableCopy] || [CPMutableDictionary dictionary]; - - [globalArgumentTransformations enumerate: function (inGlobalArgumentTransformation) { - - if (debugMode) CPLog(@"%@: Transforming request: %@", self, requestObject); - requestObject = inGlobalArgumentTransformation(requestObject); - if (debugMode) CPLog(@"%@: Transformed request: %@", self, requestObject); - - }]; - - var specificArgumentTransformation = [requestArgumentTransformations valueForKey:methodName]; - if (specificArgumentTransformation != nil) - requestObject = specificArgumentTransformation(requestObject); - - return requestObject; - -} - - - - - -- (void) enqueueGlobalResponseTransformation:(Function)transformation { - - [globalResponseTransformations addObject:transformation]; - -} - -- (void) enqueueResponseTransformation:(Function)transformation forMethodNamed:(CPString)methodName { - - [responseTransformations setObject:transformation forKey:methodName]; - -} - -- (CPDictionary) transformedResponse:(CPDictionary)inResponse forMethodNamed:(CPString)methodName { - - var responseObject = [inResponse mutableCopy] || [CPMutableDictionary dictionary]; - - [globalResponseTransformations enumerate: function (inGlobalResponseTransformation) { - - if (debugMode) CPLog(@"%@: Transforming response: %@", self, responseObject); - responseObject = inGlobalResponseTransformation(responseObject); - if (debugMode) CPLog(@"%@: Transformed response: %@", self, responseObject); - - }]; - - - - var specificResponseTransformation = [responseTransformations valueForKey:methodName]; - if (specificResponseTransformation != nil) - responseObject = specificResponseTransformation(responseObject); - - return responseObject; - -} - - - - - - - - - - -- (void) enqueueMockResponse:(Object)response forMethodNamed:(CPString)methodName { - - [mockResponses setObject:response forKey:methodName]; - -} - -- (id) mockResponseForMethodNamed:(CPString)methodName { - - return [mockResponses objectForKey:methodName]; - -} - - - - - - - - - - -- (void) fireAPIRequestNamed:(CPString)methodName withArguments:(CPDictionary)inArguments { - - [self fireAPIRequestNamed:methodName withArguments:inArguments onSuccess:nil failure:nil]; - -} - - - - - -- (void) fireAPIRequestNamed:(CPString)methodName withArguments:(CPDictionary)inArguments onSuccess:(Function)callbackOnSuccess failure:(Function)callbackOnFailure { - -// Obviously caching and delegate notifying are not there yet - - [self fireAPIRequestNamed:methodName withArguments:inArguments onSuccess:callbackOnSuccess failure:callbackOnFailure cacheResponse:NO notifyDelegate:NO]; - -} - - - - - -- (void) fireAPIRequestNamed:(CPString)methodName withArguments:(CPDictionary)inArguments onSuccess:(Function)callbackOnSuccess failure:(Function)callbackOnFailure cacheResponse:(BOOL)cacheResponse notifyDelegate:(BOOL)notifyDelegate { - - var argumentsToSend = [self transformedArguments:inArguments forMethodNamed:methodName], - serializer = kIRWebAPIEngineSerializationSchemes[serializationScheme], - isPOSTRequest = ([inArguments valueForKey:@"IRWebAPIKitPOST"] === YES); - - var serializedArguments = serializer(argumentsToSend) + "&callback=${JSONP_CALLBACK}"; - urlToCall = isPOSTRequest ? [context connectionURLForPOSTMethodNamed:methodName] : [context connectionURLForMethodNamed:methodName additions:serializedArguments], - request = [CPURLRequest requestWithURL:urlToCall]; - - if (isPOSTRequest) { - - [request setHTTPMethod:@"POST"]; - [request setValue:"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; - [request setHTTPBody:serializer(argumentsToSend)]; - - } - - if (debugMode) CPLog(@"%@: Using URL %@", self, urlToCall); - - - var connection = nil; - - if (isPOSTRequest){ - - connection = [[CPURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; - connection.irWebAPIEngineShallDeserializeResults = YES; - - } else { - - connection = [[connectionClass alloc] initWithRequest:request callback:nil delegate:self startImmediately:NO]; - - } - - connection.methodName = methodName; - - if (callbackOnSuccess != nil) - [successHandlersForConnections setObject:callbackOnSuccess forKey:[connection UID]]; - - if (callbackOnFailure != nil) - [failureHandlersForConnections setObject:callbackOnFailure forKey:[connection UID]]; - - - [self addConnectionToTheActiveSet:connection]; - - var mockResponseOrNil = [self mockResponseForMethodNamed:methodName]; - if (mockResponseOrNil != null) { - - [self connection:methodName didReceiveData:mockResponseOrNil]; - - return; - - } - - - [connection start]; - - var connectionTimeout /* (CPTimeinterval) */ = parseFloat( - - [[[CPBundle mainBundle] infoDictionary] objectForKey:kIRWebAPIEngineConnectionTimeoutTimeIntervalUserInfoDictionaryKey] - - ) || 10.0; - - [self performSelector:@selector(purgeConnectionAndSendFailureNotificationIfAppropriate:) withObject:connection afterDelay:connectionTimeout]; - -} - - - - - -- (void) connection:(id)connection didReceiveData:(Object)data { - - if (debugMode) CPLog(@"%@: Connection %@ did receive data %@", self, connection, data); - -// Since we might also grab stuff using POST… - if (connection.irWebAPIEngineShallDeserializeResults === YES) - data = [data objectFromJSON]; - - [self removeConnectionFromTheActiveSet:connection]; - - var transformedResponse = [self transformedResponse:[CPDictionary dictionaryWithJSObject:data recursively:YES] forMethodNamed:connection.methodName]; - - if (debugMode) CPLog(@"%@: Connection data is transformed to %@", self, transformedResponse); - - var successHandler = [successHandlersForConnections objectForKey:[connection UID]]; - - if (successHandler) { - - successHandler(transformedResponse); - [successHandlersForConnections removeObjectForKey:[connection UID]]; - - } else { - - [[CPNotificationCenter defaultCenter] postNotificationName:kIRWebAPIEngineConnectionDidReceiveDataNotification object:nil userInfo:transformedResponse]; - - } - -} - - - - - -- (void) connection:(CPJSONPConnection)connection didFailWithError:(CPString)error { - - if (debugMode) CPLog(@"%@: Connection %@ did fail with error %@.", self, connection, error); - - [self removeConnectionFromTheActiveSet:connection]; - - var failureHandler = [failureHandlersForConnections objectForKey:[connection UID]]; - - if (failureHandler) { - - failureHandler(error); - [failureHandlersForConnections removeObjectForKey:[connection UID]]; - - } else { - - [[CPNotificationCenter defaultCenter] postNotificationName:kIRWebAPIEngineConnectionDidFailNotification object:nil userInfo:nil]; - - } - -} - - - - - -- (void) addConnectionToTheActiveSet:(CPJSONPConnection)connection { - - if (aliveConnections == nil) - aliveConnections = [CPMutableSet set]; - - [aliveConnections addObject:connection]; - -} - - - - -- (void) removeConnectionFromTheActiveSet:(CPJSONPConnection)connection { - - [aliveConnections removeObject:connection]; - -} - - - - - -- (void) purgeConnectionAndSendFailureNotificationIfAppropriate:(CPJSONPConnection)connection { - -// If this connection is not in the active set, it has already finished, or failed - - if (![aliveConnections containsObject:connection]) return; - - if (debugMode) CPLog(@"%@: Purging connection %@.", self, connection); - -// Pose as the connection itself and send ourself a delegate message to clean up residue - - [connection cancel]; - [self connection:connection didFailWithError:null]; - -} - - - - - -@end - - - - diff --git a/IRWebAPIEngine.m b/IRWebAPIEngine.m index 4c68921..bb5ffce 100644 --- a/IRWebAPIEngine.m +++ b/IRWebAPIEngine.m @@ -8,29 +8,12 @@ #import #import "IRWebAPIEngine.h" - - - - - -NSString * const kIRWebAPIEngineResponseDictionaryIncomingData = @"kIRWebAPIEngineResponseDictionaryIncomingData"; -NSString * const kIRWebAPIEngineResponseDictionaryOutgoingContext = @"kIRWebAPIEngineResponseDictionaryOutgoingContext"; - -NSString * const kIRWebAPIEngineAssociatedDataStore = @"kIRWebAPIEngineAssociatedDataStore"; -NSString * const kIRWebAPIEngineAssociatedResponseContext = @"kIRWebAPIEngineAssociatedResponseContext"; -NSString * const kIRWebAPIEngineAssociatedSuccessHandler = @"kIRWebAPIEngineAssociatedSuccessHandler"; -NSString * const kIRWebAPIEngineAssociatedFailureHandler = @"kIRWebAPIEngineAssociatedFailureHandler"; - -NSString * const kIRWebAPIEngineUnderlyingError = @"kIRWebAPIEngineUnderlyingError"; - - - - +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIRequestOperation.h" +#import "IRWebAPIEngineContext.h" @interface IRWebAPIEngine () -@property (nonatomic, readwrite, retain) IRWebAPIContext *context; - @property (nonatomic, readwrite, retain) NSMutableArray *globalRequestPreTransformers; @property (nonatomic, readwrite, retain) NSMutableDictionary *requestTransformers; @property (nonatomic, readwrite, retain) NSMutableArray *globalRequestPostTransformers; @@ -39,69 +22,43 @@ @interface IRWebAPIEngine () @property (nonatomic, readwrite, retain) NSMutableDictionary *responseTransformers; @property (nonatomic, readwrite, retain) NSMutableArray *globalResponsePostTransformers; -@property (nonatomic, readwrite, assign) dispatch_queue_t sharedDispatchQueue; - - -- (void) setInternalDataStore:(NSMutableData *)inDataStore forConnection:(NSURLConnection *)inConnection; -- (NSMutableData *) internalDataStoreForConnection:(NSURLConnection *)inConnection; - -- (void) setInternalResponseContext:(NSMutableDictionary *)inResponseContext forConnection:(NSURLConnection *)inConnection; -- (NSMutableDictionary *) internalResponseContextForConnection:(NSURLConnection *)inConnection; - -- (void) setInternalSuccessHandler:(void (^)(NSData *inResponse))inSuccessHandler forConnection:(NSURLConnection *)inConnection; -- (void (^)(NSData *inResponse)) internalSuccessHandlerForConnection:(NSURLConnection *)inConnection; - -- (void) setInternalFailureHandler:(void (^)(void))inFailureHandler forConnection:(NSURLConnection *)inConnection; -- (void (^)(void)) internalFailureHandlerForConnection:(NSURLConnection *)inConnection; +- (IRWebAPIRequestContext *) requestContextByTransformingContext:(IRWebAPIRequestContext *)inContext forMethodNamed:(NSString *)inMethodName; - -- (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil validator:(IRWebAPIResposeValidator)inValidator successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler; - -- (void) ensureResponseParserExistence; - -- (NSDictionary *) baseRequestContextWithMethodName:(NSString *)inMethodName arguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil; -- (NSDictionary *) requestContextByTransformingContext:(NSDictionary *)inContext forMethodNamed:(NSString *)inMethodName; -- (NSURLRequest *) requestWithContext:(NSDictionary *)inContext; - -- (NSDictionary *) parsedResponseForData:(NSData *)inData withContext:(NSDictionary *)inContext; -- (void) handleUnparsableResponseForData:(NSData *)inData context:(NSDictionary *)inContext; - -- (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse withRequestContext:(NSDictionary *)inRequestContext forMethodNamed:(NSString *)inMethodName; - -- (void) cleanUpForConnection:(NSURLConnection *)inConnection; +- (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse withRequestContext:(IRWebAPIRequestContext *)inRequestContext forMethodNamed:(NSString *)inMethodName; @end - - - @implementation IRWebAPIEngine -@synthesize parser, context; -@synthesize globalRequestPreTransformers, requestTransformers, globalRequestPostTransformers; -@synthesize globalResponsePreTransformers, responseTransformers, globalResponsePostTransformers; -@synthesize sharedDispatchQueue; - -# pragma mark - -# pragma mark Initializationand Memory Management +@synthesize context = _context; +@synthesize queue = _queue; +@synthesize globalRequestPreTransformers = _globalRequestPreTransformers; +@synthesize requestTransformers = _requestTransformers; +@synthesize globalRequestPostTransformers = _globalRequestPostTransformers; +@synthesize globalResponsePreTransformers = _globalResponsePreTransformers; +@synthesize responseTransformers = _responseTransformers; +@synthesize globalResponsePostTransformers = _globalResponsePostTransformers; -- (id) initWithContext:(IRWebAPIContext *)inContext { +- (id) initWithContext:(IRWebAPIEngineContext *)inContext { - self = [super init]; if (!self) return nil; + self = [super init]; + if (!self) + return nil; - context = [inContext retain]; + _context = inContext; - self.globalRequestPreTransformers = [NSMutableArray array]; - self.requestTransformers = [NSMutableDictionary dictionary]; - self.globalRequestPostTransformers = [NSMutableArray array]; - - self.globalResponsePreTransformers = [NSMutableArray array]; - self.responseTransformers = [NSMutableDictionary dictionary]; - self.globalResponsePostTransformers = [NSMutableArray array]; + _queue = [[NSOperationQueue alloc] init]; + _queue.maxConcurrentOperationCount = 8; + + _globalRequestPreTransformers = [NSMutableArray array]; + _requestTransformers = [NSMutableDictionary dictionary]; + _globalRequestPostTransformers = [NSMutableArray array]; + + _globalResponsePreTransformers = [NSMutableArray array]; + _responseTransformers = [NSMutableDictionary dictionary]; + _globalResponsePostTransformers = [NSMutableArray array]; - self.sharedDispatchQueue = dispatch_queue_create("com.iridia.WebAPIEngine.queue.main", NULL); - return self; } @@ -112,375 +69,85 @@ - (id) init { } -- (void) dealloc { - - self.parser = nil; - self.context = nil; - - self.globalRequestPreTransformers = nil; - self.requestTransformers = nil; - self.globalRequestPostTransformers = nil; - - self.globalRequestPostTransformers = nil; - self.responseTransformers = nil; - self.globalRequestPostTransformers = nil; - - dispatch_release(self.sharedDispatchQueue); - self.sharedDispatchQueue = nil; - - [super dealloc]; - -} - - - +- (IRWebAPIRequestOperation *) operationForMethod:(NSString *)method arguments:(NSDictionary *)arguments validator:(IRWebAPIResponseValidator)validator successBlock:(IRWebAPICallback)successBlock failureBlock:(IRWebAPICallback)failureBlock { + return [self operationForMethod:method arguments:arguments contextOverride:nil validator:validator successBlock:successBlock failureBlock:failureBlock]; -# pragma mark - -# pragma mark Helpers - -- (void) ensureResponseParserExistence { - - if (self.parser) return; - - NSLog(@"Warning: IRWebAPIEngine is designed to work with a parser. Without one, the response will be sent as a default dictionary."); - self.parser = IRWebAPIResponseDefaultParserMake(); - } -- (NSDictionary *) parsedResponseForData:(NSData *)inData withContext:(NSDictionary *)inContext { - - IRWebAPIResponseParser parserBlock = [inContext objectForKey:kIRWebAPIEngineParser]; - - NSDictionary *parsedResponse = parserBlock(inData); - - if (parsedResponse) - return parsedResponse; - - [self handleUnparsableResponseForData:inData context:inContext]; - - return [NSDictionary dictionaryWithObjectsAndKeys: - - inData, kIRWebAPIEngineResponseDictionaryIncomingData, - inContext, kIRWebAPIEngineResponseDictionaryOutgoingContext, - - nil]; - -} +- (IRWebAPIRequestOperation *) operationForMethod:(NSString *)method arguments:(NSDictionary *)arguments contextOverride:(void(^)(IRWebAPIRequestContext *))overrideBlock validator:(IRWebAPIResponseValidator)validator successBlock:(IRWebAPICallback)successBlock failureBlock:(IRWebAPICallback)failureBlock { -- (void) handleUnparsableResponseForData:(NSData *)inData context:(NSDictionary *)inContext { + __weak IRWebAPIEngine *wSelf = self; - NSLog(@"%@ %s Warning: unparsable response. Resetting returned response to an empty dictionary.", self, __PRETTY_FUNCTION__); - - return; + IRWebAPIRequestContext *baseContext = [IRWebAPIRequestContext new]; + baseContext.baseURL = [self.context baseURLForMethodNamed:method]; + baseContext.engineMethod = method; - NSMutableDictionary *displayedContext = [inContext mutableCopy]; - [displayedContext setObject:@"< REMOVED> " forKey:kIRWebAPIEngineRequestHTTPBody]; - - NSLog(@"Context: %@", displayedContext); - -// This can potentially clog up the wirings -// IRWebAPIResponseParser defaultParser = IRWebAPIResponseDefaultParserMake(); -// NSDictionary *debugOutput = defaultParser(inData); -// NSLog(@"Default parser returns %@.", debugOutput ? (id)debugOutput : (id)@"- null -"); - -} - -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler { - - dispatch_async(self.sharedDispatchQueue, ^ { + [arguments enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [baseContext setValue:obj forQueryParam:key]; + }]; - dispatch_async(dispatch_get_current_queue(), [self executionBlockForAPIRequestNamed:inMethodName withArguments:inArgumentsOrNil options:nil validator:nil successHandler:inSuccessHandler failureHandler:inFailureHandler]); + if (overrideBlock) + overrideBlock(baseContext); - }); + IRWebAPIRequestContext *finalizedContext = [self requestContextByTransformingContext:baseContext forMethodNamed:method]; + IRWebAPIRequestOperation *operation = [[IRWebAPIRequestOperation alloc] initWithContext:finalizedContext]; -} - -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil validator:(IRWebAPIResposeValidator)inValidator successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler { - - dispatch_async(self.sharedDispatchQueue, ^ { + __weak IRWebAPIRequestOperation *wOperation = operation; - dispatch_async(dispatch_get_current_queue(), [self executionBlockForAPIRequestNamed:inMethodName withArguments:inArgumentsOrNil options:inOptionsOrNil validator:inValidator successHandler:inSuccessHandler failureHandler:inFailureHandler]); + [operation setCompletionBlock:^{ - }); - -} - -- (void) fireAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler { - - dispatch_async(self.sharedDispatchQueue, ^ { - - dispatch_async(dispatch_get_current_queue(), [self executionBlockForAPIRequestNamed:inMethodName withArguments:inArgumentsOrNil options:inOptionsOrNil validator:nil successHandler:inSuccessHandler failureHandler:inFailureHandler]); - - }); - -} - -- (void) enqueueAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler { - - dispatch_async(self.sharedDispatchQueue, ^ { - - dispatch_async(self.sharedDispatchQueue, [self executionBlockForAPIRequestNamed:inMethodName withArguments:inArgumentsOrNil options:inOptionsOrNil validator:nil successHandler:inSuccessHandler failureHandler:inFailureHandler]); - - }); - -} - - - - - - -# pragma mark - -# pragma mark Core - -- (IRWebAPIEngineExecutionBlock) executionBlockForAPIRequestNamed:(NSString *)inMethodName withArguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil validator:(IRWebAPIResposeValidator)inValidator successHandler:(IRWebAPICallback)inSuccessHandler failureHandler:(IRWebAPICallback)inFailureHandler { - - [self ensureResponseParserExistence]; - - void (^retryHandler)(void) = ^ { - - [self enqueueAPIRequestNamed:inMethodName withArguments:inArgumentsOrNil options:inOptionsOrNil successHandler:inSuccessHandler failureHandler:inFailureHandler]; - - }; - - void (^notifyDelegateHandler)(void) = ^ { - - NSLog(@"Notifying delegate of connection finalization"); - - }; - - NSDictionary *finalizedContext = [self requestContextByTransformingContext:[self baseRequestContextWithMethodName:inMethodName arguments:inArgumentsOrNil options:inOptionsOrNil] forMethodNamed:inMethodName]; - - NSURLRequest *request = [self requestWithContext:finalizedContext]; - - void (^returnedBlock) (void) = ^ { - - dispatch_async(dispatch_get_main_queue(), ^{ - - NSURLConnection *connection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease]; + IRWebAPIRequestState state = wOperation.state; + IRWebAPIRequestContext *context = wOperation.context; + NSDictionary *response = (NSDictionary *)wOperation.result; + + @try { + + NSCParameterAssert((state == IRWebAPIRequestStateSucceeded) || (state == IRWebAPIRequestStateFailed)); + NSCParameterAssert(!response || [response isKindOfClass:[NSDictionary class]]); + + NSDictionary *transformedResponse = [wSelf responseByTransformingResponse:response withRequestContext:context forMethodNamed:method]; - [self setInternalSuccessHandler: ^ (NSData *inResponse) { - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - BOOL shouldRetry = NO, notifyDelegate = NO; - - NSDictionary *responseContext = [self internalResponseContextForConnection:connection]; - NSDictionary *parsedResponse = [self parsedResponseForData:inResponse withContext:finalizedContext]; - NSDictionary *transformedResponse = [self responseByTransformingResponse:parsedResponse withRequestContext:responseContext forMethodNamed:inMethodName]; - - if ((inValidator != nil) && (!inValidator(transformedResponse, responseContext))) { - - if (inFailureHandler) - inFailureHandler(transformedResponse, responseContext, ¬ifyDelegate, &shouldRetry); - + if (state == IRWebAPIRequestStateSucceeded) { + + if ((validator != nil) && (!validator(transformedResponse, context))) { + + if (failureBlock) + failureBlock(transformedResponse, context); + } else { - - if (inSuccessHandler) - inSuccessHandler(transformedResponse, responseContext, ¬ifyDelegate, &shouldRetry); - + + if (successBlock) + successBlock(transformedResponse, context); + } - - if (shouldRetry) retryHandler(); - if (notifyDelegate) notifyDelegateHandler(); - - [self cleanUpForConnection:connection]; - - [pool drain]; - - } forConnection:connection]; - - - [self setInternalFailureHandler: ^ { - - BOOL shouldRetry = NO, notifyDelegate = NO; - NSMutableDictionary *responseContext = [self internalResponseContextForConnection:connection]; - NSDictionary *transformedResopnse = [self responseByTransformingResponse:[NSDictionary dictionary] withRequestContext:responseContext forMethodNamed:inMethodName]; - - if (inFailureHandler) - inFailureHandler(transformedResopnse, responseContext, ¬ifyDelegate, &shouldRetry); - - if (shouldRetry) retryHandler(); - if (notifyDelegate) notifyDelegateHandler(); - - [self cleanUpForConnection:connection]; - - } forConnection:connection]; - - - [self setInternalDataStore:[NSMutableData data] forConnection:connection]; - [self setInternalResponseContext:[NSMutableDictionary dictionaryWithObjectsAndKeys: - - finalizedContext, kIRWebAPIEngineResponseContextOriginalRequestContext, - - nil] forConnection:connection]; - - [connection start]; + + } else { + + if (failureBlock) + failureBlock(transformedResponse, context); + + } + + } @catch (NSException *exception) { + + if (failureBlock) + failureBlock(nil, context); + + } - }); - - }; - - return [[returnedBlock copy] autorelease]; - -} - - - - - -# pragma mark - -# pragma mark Connection Delegation - -- (void) connection:(NSURLConnection *)inConnection didReceiveData:(NSData *)inData { - - dispatch_async(self.sharedDispatchQueue, ^{ - - [[self internalDataStoreForConnection:inConnection] appendData:inData]; - - }); - -} - -- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { - - dispatch_async(self.sharedDispatchQueue, ^{ - - NSMutableDictionary *responseContext = [self internalResponseContextForConnection:connection]; - [responseContext setObject:response forKey:kIRWebAPIEngineResponseContextURLResponse]; + }]; - }); + return operation; } -- (void) connectionDidFinishLoading:(NSURLConnection *)inConnection { - - dispatch_async(self.sharedDispatchQueue, ^{ - - @try { - - [self internalSuccessHandlerForConnection:inConnection]([self internalDataStoreForConnection:inConnection]); - - } @catch (NSException *e) { - - NSLog(@"Handle Exception: %@ %@", e, inConnection); - - [self internalFailureHandlerForConnection:inConnection](); - - } - - }); - -} - -- (void) connection:(NSURLConnection *)inConnection didFailWithError:(NSError *)error { - - dispatch_async(self.sharedDispatchQueue, ^{ - - [[self internalResponseContextForConnection:inConnection] setObject:error forKey:kIRWebAPIEngineUnderlyingError]; - [self internalFailureHandlerForConnection:inConnection](); - - }); - -} - -- (BOOL) connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { - - return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; - -} - -- (void) connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { - - if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) - if ([[self.context.baseURL host] isEqualToString:challenge.protectionSpace.host]) - [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; - - [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; - -} - - - - - -# pragma mark - -# pragma mark Associated Objects - -// Notice that blocks are made on the stack so they must be copied before being stored away - - -- (void) setInternalSuccessHandler:(void (^)(NSData *inResponse))inSuccessHandler forConnection:(NSURLConnection *)inConnection { - - objc_setAssociatedObject(inConnection, kIRWebAPIEngineAssociatedSuccessHandler, inSuccessHandler, OBJC_ASSOCIATION_COPY); - -} - -- (void (^)(NSData *inResponse)) internalSuccessHandlerForConnection:(NSURLConnection *)inConnection { - - return objc_getAssociatedObject(inConnection, kIRWebAPIEngineAssociatedSuccessHandler); - -} - -- (void) setInternalFailureHandler:(void (^)(void))inFailureHandler forConnection:(NSURLConnection *)inConnection { - - objc_setAssociatedObject(inConnection, kIRWebAPIEngineAssociatedFailureHandler, inFailureHandler, OBJC_ASSOCIATION_COPY); - -} - -- (void (^)(void)) internalFailureHandlerForConnection:(NSURLConnection *)inConnection { - - return objc_getAssociatedObject(inConnection, kIRWebAPIEngineAssociatedFailureHandler); - -} - -- (void) setInternalDataStore:(NSMutableData *)inDataStore forConnection:(NSURLConnection *)inConnection { - - objc_setAssociatedObject(inConnection, kIRWebAPIEngineAssociatedDataStore, inDataStore, OBJC_ASSOCIATION_RETAIN); - -} - -- (NSMutableData *) internalDataStoreForConnection:(NSURLConnection *)inConnection { - - return objc_getAssociatedObject(inConnection, kIRWebAPIEngineAssociatedDataStore); - -} - -- (void) setInternalResponseContext:(NSMutableDictionary *)inResponseContext forConnection:(NSURLConnection *)inConnection { - - objc_setAssociatedObject(inConnection, kIRWebAPIEngineAssociatedResponseContext, inResponseContext, OBJC_ASSOCIATION_RETAIN); - -} - -- (NSMutableDictionary *) internalResponseContextForConnection:(NSURLConnection *)inConnection { - - return objc_getAssociatedObject(inConnection, kIRWebAPIEngineAssociatedResponseContext); - -} - -- (void) cleanUpForConnection:(NSURLConnection *)inConnection { - - dispatch_async(dispatch_get_main_queue(), ^{ - - objc_removeAssociatedObjects(inConnection); - - }); - -} - - - - - - - - - - - (NSMutableArray *) requestTransformersForMethodNamed:(NSString *)inMethodName { - NSMutableArray *returnedArray = [self.requestTransformers objectForKey:inMethodName]; + NSMutableArray *returnedArray = nil; + + @synchronized(self.requestTransformers) { + returnedArray = [self.requestTransformers objectForKey:inMethodName]; if (!returnedArray) { @@ -488,14 +155,18 @@ - (NSMutableArray *) requestTransformersForMethodNamed:(NSString *)inMethodName [self.requestTransformers setObject:returnedArray forKey:inMethodName]; } + } - return returnedArray; + return returnedArray; } - (NSMutableArray *) responseTransformersForMethodNamed:(NSString *)inMethodName { - NSMutableArray *returnedArray = [self.responseTransformers objectForKey:inMethodName]; + NSMutableArray *returnedArray = nil; + + @synchronized(self.responseTransformers) { + returnedArray = [self.responseTransformers objectForKey:inMethodName]; if (!returnedArray) { @@ -503,99 +174,35 @@ - (NSMutableArray *) responseTransformersForMethodNamed:(NSString *)inMethodName [self.responseTransformers setObject:returnedArray forKey:inMethodName]; } + } - return returnedArray; - -} - - - - - -- (NSDictionary *) baseRequestContextWithMethodName:(NSString *)inMethodName arguments:(NSDictionary *)inArgumentsOrNil options:(NSDictionary *)inOptionsOrNil { - - NSMutableDictionary *arguments = [NSMutableDictionary dictionary]; - - if (inArgumentsOrNil) for (id argumentKey in [inArgumentsOrNil keysOfEntriesPassingTest:^(id key, id object, BOOL *stop) { - - if ([object isEqual:@""]) return NO; - if ([object isEqual:[NSNull null]]) return NO; - - return YES; - - }]) [arguments setObject:[inArgumentsOrNil objectForKey:argumentKey] forKey:argumentKey]; - - - NSURL *baseURL = [inOptionsOrNil objectForKey:kIRWebAPIEngineRequestHTTPBaseURL]; - baseURL = baseURL ? baseURL : [self.context baseURLForMethodNamed:inMethodName]; - - NSMutableDictionary *headerFields = [inOptionsOrNil objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - headerFields = headerFields ? [[headerFields mutableCopy] autorelease] : [NSMutableDictionary dictionary]; - - id httpBody = [inOptionsOrNil objectForKey:kIRWebAPIEngineRequestHTTPBody]; - httpBody = httpBody ? httpBody : [NSNull null]; - - NSString *httpMethod = [inOptionsOrNil objectForKey:kIRWebAPIEngineRequestHTTPMethod]; - httpMethod = httpMethod ? [[httpMethod copy] autorelease] : @"GET"; - - IRWebAPIResponseParser responseParser = [inOptionsOrNil objectForKey:kIRWebAPIEngineParser]; - responseParser = responseParser ? responseParser : self.parser; - - NSNumber *timeoutValue = [inOptionsOrNil objectForKey:kIRWebAPIRequestTimeout]; - timeoutValue = timeoutValue ? timeoutValue : [NSNumber numberWithDouble:60.0]; - - NSMutableDictionary *transformedContext = [NSMutableDictionary dictionaryWithObjectsAndKeys: - - baseURL, kIRWebAPIEngineRequestHTTPBaseURL, - headerFields, kIRWebAPIEngineRequestHTTPHeaderFields, - arguments, kIRWebAPIEngineRequestHTTPQueryParameters, - httpBody, kIRWebAPIEngineRequestHTTPBody, - httpMethod, kIRWebAPIEngineRequestHTTPMethod, - responseParser, kIRWebAPIEngineParser, - inMethodName, kIRWebAPIEngineIncomingMethodName, - timeoutValue, kIRWebAPIRequestTimeout, - - nil]; - - - for (id optionValueKey in inOptionsOrNil) - [transformedContext setValue:[inOptionsOrNil valueForKey:optionValueKey] forKey:optionValueKey]; - - return [[transformedContext copy] autorelease]; + return returnedArray; } -- (NSDictionary *) requestContextByTransformingContext:(NSDictionary *)inContext forMethodNamed:(NSString *)inMethodName { - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; +- (IRWebAPIRequestContext *) requestContextByTransformingContext:(IRWebAPIRequestContext *)inContext forMethodNamed:(NSString *)inMethodName { NSMutableArray *allTransformers = [NSMutableArray array]; [allTransformers addObjectsFromArray:self.globalRequestPreTransformers]; NSArray *methodSpecificTransformers = [self requestTransformersForMethodNamed:inMethodName]; - if (methodSpecificTransformers) { [allTransformers addObjectsFromArray:methodSpecificTransformers]; } [allTransformers addObjectsFromArray:self.globalRequestPostTransformers]; - NSDictionary *currentContext = inContext; + IRWebAPIRequestContext *currentContext = inContext; for (IRWebAPIRequestContextTransformer aTransformer in allTransformers) currentContext = aTransformer(currentContext); - [currentContext retain]; - [pool drain]; - - return [currentContext autorelease]; + return currentContext; } -- (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse withRequestContext:(NSDictionary *)inRequestContext forMethodNamed:(NSString *)inMethodName { - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; +- (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse withRequestContext:(IRWebAPIRequestContext *)inRequestContext forMethodNamed:(NSString *)inMethodName { NSMutableArray *allTransformers = [NSMutableArray array]; [allTransformers addObjectsFromArray:self.globalResponsePreTransformers]; @@ -607,50 +214,8 @@ - (NSDictionary *) responseByTransformingResponse:(NSDictionary *)inResponse wit for (IRWebAPIResponseContextTransformer aTransformer in allTransformers) currentResponse = aTransformer(currentResponse, inRequestContext); - [currentResponse retain]; - [pool drain]; - - return [currentResponse autorelease]; - -} - - - - - -- (NSURLRequest *) requestWithContext:(NSDictionary *)inContext { - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:IRWebAPIRequestURLWithQueryParameters( - - (NSURL *)[inContext objectForKey:kIRWebAPIEngineRequestHTTPBaseURL], - [inContext objectForKey:kIRWebAPIEngineRequestHTTPQueryParameters] - - ) cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:[[inContext objectForKey:kIRWebAPIRequestTimeout] doubleValue]]; - - [request setHTTPShouldHandleCookies:NO]; - - NSDictionary *headerFields; - if ((headerFields = [inContext objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields])) - for (NSString *headerFieldKey in headerFields) - [request setValue:[headerFields objectForKey:headerFieldKey] forHTTPHeaderField:headerFieldKey]; - - NSData *httpBody = [inContext objectForKey:kIRWebAPIEngineRequestHTTPBody]; - if (![httpBody isEqual:[NSNull null]]) - [request setHTTPBody:httpBody]; - - [request setHTTPMethod:[inContext objectForKey:kIRWebAPIEngineRequestHTTPMethod]]; - - NSURLRequest *returnedRequest = [request copy]; - [pool drain]; - - return [returnedRequest autorelease]; + return currentResponse; } - - - - @end diff --git a/IRWebAPIContext.h b/IRWebAPIEngineContext.h similarity index 57% rename from IRWebAPIContext.h rename to IRWebAPIEngineContext.h index 0edfd1d..5f0658f 100644 --- a/IRWebAPIContext.h +++ b/IRWebAPIEngineContext.h @@ -9,27 +9,19 @@ #import +@interface IRWebAPIEngineContext : NSObject - - -@interface IRWebAPIContext : NSObject { - - NSURL *baseURL; - -} - -@property (nonatomic, retain, readwrite) NSURL *baseURL; +@property (nonatomic, readonly, copy) NSURL *baseURL; - (id) initWithBaseURL:(NSURL *)inBaseURL; - (NSURL *) baseURLForMethodNamed:(NSString *)inMethodName; - - - - @end +@interface IRWebAPIEngineMutableContext : IRWebAPIEngineContext +@property (nonatomic, readwrite, copy) NSURL *baseURL; +@end diff --git a/IRWebAPIContext.m b/IRWebAPIEngineContext.m similarity index 53% rename from IRWebAPIContext.m rename to IRWebAPIEngineContext.m index b61d91a..079270a 100644 --- a/IRWebAPIContext.m +++ b/IRWebAPIEngineContext.m @@ -6,21 +6,25 @@ // Copyright 2010 Iridia Productions. All rights reserved. // -#import "IRWebAPIContext.h" - +#import "IRWebAPIEngineContext.h" +@interface IRWebAPIEngineContext () +@property (nonatomic, readwrite, copy) NSURL *baseURL; +@end -@implementation IRWebAPIContext -@synthesize baseURL; +@implementation IRWebAPIEngineContext +@synthesize baseURL = _baseURL; - (id) initWithBaseURL:(NSURL *)inBaseURL { - self = [super init]; if (!self) return nil; + self = [super init]; + if (!self) + return nil; - baseURL = [inBaseURL retain]; + _baseURL = [inBaseURL copy]; return self; @@ -32,10 +36,6 @@ - (id) init { } - - - - - (NSURL *) baseURLForMethodNamed:(NSString *)inMethodName { return [NSURL URLWithString:inMethodName relativeToURL:self.baseURL]; @@ -45,5 +45,7 @@ - (NSURL *) baseURLForMethodNamed:(NSString *)inMethodName { @end +@implementation IRWebAPIEngineMutableContext : IRWebAPIEngineContext +@dynamic baseURL; - +@end diff --git a/IRWebAPIGoogleReaderAuthenticator.h b/IRWebAPIGoogleReaderAuthenticator.h deleted file mode 100644 index 0a5215d..0000000 --- a/IRWebAPIGoogleReaderAuthenticator.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// IRWebAPIGoogleReaderAuthenticator.h -// IRWebAPIKit -// -// Created by Evadne Wu on 11/21/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -@class IRWebAPIAuthenticator; -@interface IRWebAPIGoogleReaderAuthenticator : IRWebAPIAuthenticator { - - NSString *authToken; - -} - -- (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess:(IRWebAPIAuthenticatorCallback)successHandler onFailure:(IRWebAPIAuthenticatorCallback)failureHandler; - -@end diff --git a/IRWebAPIGoogleReaderAuthenticator.m b/IRWebAPIGoogleReaderAuthenticator.m deleted file mode 100644 index 5be24d1..0000000 --- a/IRWebAPIGoogleReaderAuthenticator.m +++ /dev/null @@ -1,106 +0,0 @@ -// -// IRWebAPIGoogleReaderAuthenticator.m -// IRWebAPIKit -// -// Created by Evadne Wu on 11/21/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIKit.h" -#import "IRWebAPIGoogleReaderAuthenticator.h" - -@interface IRWebAPIGoogleReaderAuthenticator () - -@property (nonatomic, retain, readwrite) NSString *authToken; - -@end - - -@implementation IRWebAPIGoogleReaderAuthenticator - -@synthesize authToken; - -- (void) createTransformerBlocks { - - self.globalRequestPreTransformerBlock = [[^ (NSDictionary *inOriginalContext) { - - if (!self.currentCredentials) return inOriginalContext; - if (!self.authToken) return inOriginalContext; - - NSMutableDictionary *transformedContext = [[inOriginalContext mutableCopy] autorelease]; - volatile NSMutableDictionary *headerFields = [transformedContext valueForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - headerFields = headerFields ? [[headerFields mutableCopy] autorelease] : [NSMutableDictionary dictionary]; - [transformedContext setObject:headerFields forKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - [headerFields setObject:[NSString stringWithFormat:@"GoogleLogin auth=%@", self.authToken] forKey:@"Authorization"]; - - return (NSDictionary *)transformedContext; - - } copy] autorelease]; - - self.globalResponsePreTransformerBlock = [[^ (NSDictionary *inParsedResponse, NSDictionary *inResponseContext) { - - return inParsedResponse; - - } copy] autorelease]; - -} - -- (void) associateWithEngine:(IRWebAPIEngine *)inEngine { - - [self disassociateEngine]; - - self.authToken = nil; - self.engine = inEngine; - - [super associateWithEngine:inEngine]; - -} - -- (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess:(IRWebAPIAuthenticatorCallback)successHandler onFailure:(IRWebAPIAuthenticatorCallback)failureHandler { - - [self.engine fireAPIRequestNamed:@"accounts/ClientLogin" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - -// Does not quite work -// @"HOSTED_OR_GOOGLE", @"accountType", - - @"reader", @"service", - inCredentials.identifier, @"Email", - inCredentials.qualifier, @"Passwd", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIResponseQueryResponseParserMake(), kIRWebAPIEngineParser, - @"POST", kIRWebAPIEngineRequestHTTPMethod, - [NSDictionary dictionaryWithObjectsAndKeys:@"application/x-www-form-urlencoded", @"Content-type", nil], kIRWebAPIEngineRequestHTTPHeaderFields, - - nil] validator: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - if ([inResponseOrNil valueForKey:@"Auth"] == nil) - return NO; - - if ([inResponseOrNil valueForKey:@"Error"]) - return NO; - - return YES; - - } successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - self.authToken = [inResponseOrNil valueForKey:@"Auth"]; - self.currentCredentials = inCredentials; - self.currentCredentials.authenticated = YES; - - if (successHandler) - successHandler(self, YES, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - *outShouldRetry = NO; - - if (failureHandler) - failureHandler(self, NO, outShouldRetry); - - }]; - -} - -@end diff --git a/IRWebAPIGoogleReaderInterface.h b/IRWebAPIGoogleReaderInterface.h deleted file mode 100644 index fd661bc..0000000 --- a/IRWebAPIGoogleReaderInterface.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// IRWebAPIGoogleReaderInterface.h -// IRWebAPIKit -// -// Created by Evadne Wu on 12/1/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIKit.h" - -@interface IRWebAPIGoogleReaderInterface : IRWebAPIInterface - -@property (nonatomic, readwrite, assign) NSUInteger batchSize; - -- (void) retrieveCurrentUserInfoWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveSubscribedFeedsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveFeedsWithUnreadItemsUsingSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveTagsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveItemsOfFeed:(NSURL *)feedURL crawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveItemsWithLabel:(NSString *)aLabelName crawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveReadingListItemsCrawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveStarredItemsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; -- (void) retrieveSharedItemsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; -- (void) retrieveNotesWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrievePreferencesWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -@end diff --git a/IRWebAPIGoogleReaderInterface.m b/IRWebAPIGoogleReaderInterface.m deleted file mode 100644 index cd0349a..0000000 --- a/IRWebAPIGoogleReaderInterface.m +++ /dev/null @@ -1,220 +0,0 @@ -// -// IRWebAPIGoogleReaderInterface.m -// IRWebAPIKit -// -// Created by Evadne Wu on 12/1/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIGoogleReaderInterface.h" - - -NSString * const kIRWebAPIGoogleReaderInterfaceBatchSize = @"n"; - - - - - -@interface IRWebAPIGoogleReaderInterface () - -- (NSString *) exclusionStringFromArray:(NSArray *)excludedItemsOrStates; - -@end - -@implementation IRWebAPIGoogleReaderInterface - -@synthesize batchSize; - -- (id) init { - - IRWebAPIContext *googleReaderContext = [[[IRWebAPIContext alloc] initWithBaseURL:[NSURL URLWithString:@"https://www.google.com"]] autorelease]; - IRWebAPIEngine *googleReaderEngine = [[[IRWebAPIEngine alloc] initWithContext:googleReaderContext] autorelease]; - IRWebAPIAuthenticator *googleReaderAuthenticator = [[[IRWebAPIGoogleReaderAuthenticator alloc] initWithEngine:googleReaderEngine] autorelease]; - - googleReaderEngine.parser = IRWebAPIResponseDefaultJSONParserMake(); - - self = [self initWithEngine:googleReaderEngine authenticator:googleReaderAuthenticator]; - if (!self) return nil; - - self.batchSize = 200; - - - [self.engine.globalRequestPreTransformers addObject:[[ ^ (NSDictionary *inOriginalContext) { - - NSMutableDictionary *transformedContext = [[inOriginalContext mutableCopy] autorelease]; - NSMutableDictionary *queryParameters = [transformedContext objectForKey:kIRWebAPIEngineRequestHTTPQueryParameters]; - - if (!queryParameters) { - - queryParameters = [NSMutableDictionary dictionary]; - [transformedContext setObject:queryParameters forKey:kIRWebAPIEngineRequestHTTPQueryParameters]; - - } - - [queryParameters setObject:@"IRWebAPIKit" forKey:@"client"]; - [queryParameters setObject:[NSNumber numberWithDouble:floor([[NSDate date] timeIntervalSince1970])] forKey:@"ck"]; - [queryParameters setObject:@"json" forKey:@"output"]; - - return (NSDictionary *)transformedContext; - - } copy] autorelease]]; - - - return self; - -} - -- (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess:(IRWebAPIAuthenticatorCallback)successHandler onFailure:(IRWebAPIAuthenticatorCallback)failureHandler { - - [self.authenticator authenticateCredentials:inCredentials onSuccess: ^ (IRWebAPIAuthenticator *inAuthenticator, BOOL isAuthenticated, BOOL *inShouldRetry) { - - if (!isAuthenticated) { - - *inShouldRetry = YES; - return; - - } - - if (successHandler) - successHandler(inAuthenticator, isAuthenticated, inShouldRetry); - - } onFailure:failureHandler]; - -} - -- (void) retrieveCurrentUserInfoWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"reader/api/0/user-info" withArguments:nil options:nil validator: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - for (id aKey in [NSArray arrayWithObjects:@"userEmail", @"userId", @"userName", nil]) - if ([inResponseOrNil objectForKey:aKey] == nil) - return NO; - - return YES; - - } successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -- (void) retrieveSubscribedFeedsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"reader/api/0/subscription/list" withArguments:nil options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"reader/api/0/subscription/list %@", inResponseOrNil); - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -- (void) retrieveFeedsWithUnreadItemsUsingSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveTagsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveItemsOfFeed:(NSURL *)feedURL crawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:[@"reader/api/0/stream/contents/feed/" stringByAppendingString:[feedURL absoluteString]] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithInt:self.batchSize], kIRWebAPIGoogleReaderInterfaceBatchSize, - [self exclusionStringFromArray:itemsOrStates], @"xt", - @"d", @"r", - - nil] options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -- (void) retrieveItemsWithLabel:(NSString *)aLabelName crawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveReadingListItemsCrawledAfterDate:(NSDate *)crawledDate excluding:(NSArray *)itemsOrStates successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveStarredItemsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveSharedItemsWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrieveNotesWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(NO, @"Implement %s", __PRETTY_FUNCTION__); - -} - -- (void) retrievePreferencesWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"reader/api/0/preference/stream/list" withArguments:nil options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - - -} - - - - - -- (NSString *) exclusionStringFromArray:(NSArray *)excludedItemsOrStates { - - NSLog(@"Implement %s !", __PRETTY_FUNCTION__); - - return @""; - -} - -@end diff --git a/IRWebAPIHelpers.h b/IRWebAPIHelpers.h index a4e59fc..691b228 100644 --- a/IRWebAPIHelpers.h +++ b/IRWebAPIHelpers.h @@ -24,8 +24,6 @@ extern BOOL IRWebAPIKitValidResponse (id inObject); extern NSString * IRWebAPIKitStringValue (id inObject); -extern id IRWebAPIKitWrapNil(id inObjectOrNil); -extern id IRWebAPIKitNumberOrNull (NSNumber *aNumber); # pragma mark Encoding, Decoding and Conversion diff --git a/IRWebAPIHelpers.m b/IRWebAPIHelpers.m index 57b161e..3cfc2dd 100644 --- a/IRWebAPIHelpers.m +++ b/IRWebAPIHelpers.m @@ -23,8 +23,8 @@ if ([inObject isKindOfClass:[NSString class]]) return (NSString *)inObject; - if ([inObject respondsToSelector:@selector(stringValue)]) - return IRWebAPIKitStringValue([inObject performSelector:@selector(stringValue)]); + if ([inObject isKindOfClass:[NSValue class]]) + return [inObject performSelector:@selector(stringValue)]; return [inObject description]; @@ -38,24 +38,6 @@ BOOL IRWebAPIKitValidResponse (id inObject) { } -id IRWebAPIKitWrapNil(id inObjectOrNil) { - - if (inObjectOrNil == nil) - return [NSNull null]; - - return inObjectOrNil; - -} - -id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { - - if (!(BOOL)[aNumber boolValue]) - return [NSNull null]; - - return aNumber; - -}; - @@ -70,7 +52,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { // From Google’s GData Toolkit // http://oauth.net/core/1.0a/#encoding_parameters - CFStringRef originalString = (CFStringRef)inString; + CFStringRef originalString = (__bridge CFStringRef)inString; CFStringRef leaveUnescaped = CFSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-._~"); CFStringRef forceEscaped = CFSTR("%!$&'()*+,/:;=?@"); @@ -81,11 +63,9 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { escapedStr = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, originalString, leaveUnescaped, forceEscaped, kCFStringEncodingUTF8); - [(id)CFMakeCollectable(escapedStr) autorelease]; - } - return (NSString *)escapedStr; + return (NSString *)CFBridgingRelease(escapedStr); } @@ -93,22 +73,13 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { NSString *inString = IRWebAPIKitStringValue(inObject); -// From Google’s GData Toolkit -// http://oauth.net/core/1.0a/#encoding_parameters - - CFStringRef originalString = (CFStringRef)inString; - - CFStringRef unescapedStr = NULL; - - if (inString) { - - unescapedStr = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, originalString, CFSTR(""), kCFStringEncodingUTF8); - - [(id)CFMakeCollectable(unescapedStr) autorelease]; - - } + if (!inString) + return nil; + + // From Google’s GData Toolkit + // http://oauth.net/core/1.0a/#encoding_parameters - return (NSString *)unescapedStr; + return (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (__bridge CFStringRef)inString, CFSTR(""), kCFStringEncodingUTF8)); } @@ -153,7 +124,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { } - return [[[NSString alloc] initWithData:buffer encoding:NSASCIIStringEncoding] autorelease]; + return [[NSString alloc] initWithData:buffer encoding:NSASCIIStringEncoding]; } @@ -174,7 +145,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { [scanner setCharactersToBeSkipped:nil]; - entityNamesToNumbers = entityNamesToNumbers ? entityNamesToNumbers : [IRWebAPIKitXMLEntityNumbersFromNames() retain]; + entityNamesToNumbers = entityNamesToNumbers ? entityNamesToNumbers : IRWebAPIKitXMLEntityNumbersFromNames(); NSString* (^scanEntityNumber) (NSScanner **inScanner) = ^ (NSScanner **inScanner) { @@ -200,8 +171,6 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { NSString *unknownEntity = @""; [scanner scanUpToCharactersFromSet:boundaryCharacterSet intoString:&unknownEntity]; - IRWebAPIKitLog(@"Expected numeric character entity but got &#%@%@;", xForHex, unknownEntity); - return (NSString *)[NSString stringWithFormat:@"&#%@%@", xForHex, unknownEntity]; }; @@ -262,7 +231,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault); if (!theUUID) return nil; - uuid = [(NSString *)CFUUIDCreateString(kCFAllocatorDefault, theUUID) autorelease]; + uuid = (NSString *)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, theUUID)); CFRelease(theUUID); return [NSString stringWithFormat:@"%@-%@", IRWebAPIKitTimestamp(), uuid]; @@ -278,8 +247,6 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { NSString * IRWebAPIKitOAuthSignatureBaseStringMake (NSString *inHTTPMethod, NSURL *inBaseURL, NSDictionary *inQueryParameters) { - IRWebAPIKitLog(@"IRWebAPIKitOAuthSignatureBaseStringMake -> %@ %@ %@", inHTTPMethod, inBaseURL, inQueryParameters); - NSString * (^uriEncode) (NSString *) = ^ NSString * (NSString *inString) { return IRWebAPIKitRFC3986EncodedStringMake(inString); @@ -315,45 +282,27 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { } - IRWebAPIKitLog(@"IRWebAPIKitOAuthSignatureBaseStringMake -> %@", returnedString); - return returnedString; } NSString * IRWebAPIKitHMACSHA1 (NSString *inConsumerSecret, NSString *inTokenSecret, NSString *inPayload) { - IRWebAPIKitLog(@"IRWebAPIKitHMACSHA1 -> %@ %@ %@", inConsumerSecret, inTokenSecret, inPayload); - -// From Google’s GData Toolkit + // From Google’s GData Toolkit NSString *encodedConsumerSecret = IRWebAPIKitRFC3986EncodedStringMake(inConsumerSecret); + if (!encodedConsumerSecret) + encodedConsumerSecret = @""; + NSString *encodedTokenSecret = IRWebAPIKitRFC3986EncodedStringMake(inTokenSecret); + if (!encodedTokenSecret) + encodedTokenSecret = @""; - NSString *key = [NSString stringWithFormat:@"%@&%@", - - encodedConsumerSecret ? encodedConsumerSecret : @"", - encodedTokenSecret ? encodedTokenSecret : @"" - - ]; - + NSString *key = [NSString stringWithFormat:@"%@&%@", encodedConsumerSecret, encodedTokenSecret]; NSMutableData *sigData = [NSMutableData dataWithLength:CC_SHA1_DIGEST_LENGTH]; - CCHmac( - - kCCHmacAlgSHA1, - - [key UTF8String], [key length], - [inPayload UTF8String], [inPayload length], - [sigData mutableBytes] - - ); - - NSString *returnedString = IRWebAPIKitBase64StringFromNSDataMake(sigData); - - IRWebAPIKitLog(@"IRWebAPIKitHMACSHA1 -> %@", returnedString); - - return returnedString; + CCHmac(kCCHmacAlgSHA1, [key UTF8String], [key length], [inPayload UTF8String], [inPayload length], [sigData mutableBytes]); + return IRWebAPIKitBase64StringFromNSDataMake(sigData); } @@ -369,7 +318,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { if (!inExtension) return nil; - CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)inExtension, NULL); + CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)CFBridgingRetain(inExtension), NULL); if(!UTI) return nil; @@ -380,7 +329,7 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { if (!registeredType) return nil; - return [(NSString *)registeredType autorelease]; + return (NSString *)CFBridgingRelease(registeredType); } @@ -437,8 +386,8 @@ id IRWebAPIKitNumberOrNull (NSNumber *aNumber) { [queryPairExpression enumerateMatchesInString:query options:0 range:queryFullRange usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { - __block NSString *currentArgumentName = nil; - __block NSString *currentArgumentValue = nil; + NSString *currentArgumentName = nil; + NSString *currentArgumentValue = nil; NSUInteger numberOfRanges = result.numberOfRanges; if (!numberOfRanges) diff --git a/IRWebAPIInterceptor.h b/IRWebAPIInterceptor.h new file mode 100644 index 0000000..a2fc036 --- /dev/null +++ b/IRWebAPIInterceptor.h @@ -0,0 +1,15 @@ +// +// IRWebAPIInterceptor.h +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import + +@interface IRWebAPIInterceptor : NSObject + +@property (nonatomic, readwrite, weak) id receiver; + +@end diff --git a/IRWebAPIInterceptor.m b/IRWebAPIInterceptor.m new file mode 100644 index 0000000..38a1847 --- /dev/null +++ b/IRWebAPIInterceptor.m @@ -0,0 +1,32 @@ +// +// IRWebAPIInterceptor.m +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import "IRWebAPIInterceptor.h" + +@implementation IRWebAPIInterceptor +@synthesize receiver = _receiver; + +- (id) forwardingTargetForSelector:(SEL)aSelector { + + if ([_receiver respondsToSelector:aSelector]) + return _receiver; + + return [super forwardingTargetForSelector:aSelector]; + +} + +- (BOOL) respondsToSelector:(SEL)aSelector { + + if ([_receiver respondsToSelector:aSelector]) + return YES; + + return [super respondsToSelector:aSelector]; + +} + +@end diff --git a/IRWebAPIInterface+Validators.h b/IRWebAPIInterface+Validators.h index 7626792..a4cd195 100644 --- a/IRWebAPIInterface+Validators.h +++ b/IRWebAPIInterface+Validators.h @@ -12,6 +12,6 @@ @interface IRWebAPIInterface (Validators) -+ (IRWebAPIResposeValidator) defaultNoErrorValidator; ++ (IRWebAPIResponseValidator) defaultNoErrorValidator; @end diff --git a/IRWebAPIInterface+Validators.m b/IRWebAPIInterface+Validators.m index 005f535..6e0319c 100644 --- a/IRWebAPIInterface+Validators.m +++ b/IRWebAPIInterface+Validators.m @@ -11,38 +11,13 @@ @implementation IRWebAPIInterface (Validators) -+ (IRWebAPIResposeValidator) defaultNoErrorValidator { ++ (IRWebAPIResponseValidator) defaultNoErrorValidator { - return [[(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { + return [(^ (NSDictionary *response, IRWebAPIRequestContext *context) { - NSHTTPURLResponse *response = (NSHTTPURLResponse *)[inResponseContext objectForKey:kIRWebAPIEngineResponseContextURLResponse]; + return (context.urlResponse.statusCode == 200); - BOOL noError = ([response statusCode] == 200); - - if (!noError) { - - IRWebAPIKitLog(@"Error: %x %@", [response statusCode], [[response class] localizedStringForStatusCode:[response statusCode]]); - - if ([inResponseOrNil isEqual:[NSNull null]]) { - - return NO; - - } - - id errorContent = nil; - if ((errorContent = [inResponseOrNil valueForKeyPath:@"error"])) { - - IRWebAPIKitLog(@"Error from Server: %@", errorContent); - - } - - return NO; - - } - - return YES; - - }) copy] autorelease]; + }) copy]; } diff --git a/IRWebAPIInterface.h b/IRWebAPIInterface.h index 317be8b..d0aa90a 100644 --- a/IRWebAPIInterface.h +++ b/IRWebAPIInterface.h @@ -8,7 +8,7 @@ #import -@class IRWebAPIEngine, IRWebAPIAuthenticator, IRWebAPIContext; +@class IRWebAPIEngine, IRWebAPIAuthenticator, IRWebAPIEngineContext; @interface IRWebAPIInterface : NSObject diff --git a/IRWebAPIInterface.m b/IRWebAPIInterface.m index 7d9879c..7307012 100644 --- a/IRWebAPIInterface.m +++ b/IRWebAPIInterface.m @@ -8,29 +8,27 @@ #import "IRWebAPIKit.h" - - - - @implementation IRWebAPIInterface -@synthesize engine, authenticator; - -- (id) init { - - return [self initWithEngine:nil authenticator:nil]; - -} +@synthesize engine = _engine, authenticator = _authenticator; - (id) initWithEngine:(IRWebAPIEngine *)inEngine authenticator:(IRWebAPIAuthenticator *)inAuthenticator { - self = [super init]; if (!self) return nil; + self = [super init]; + if (!self) + return nil; - engine = [inEngine retain]; - authenticator = [inAuthenticator retain]; + _engine = inEngine; + _authenticator = inAuthenticator; return self; } +- (id) init { + + return [self initWithEngine:nil authenticator:nil]; + +} + @end diff --git a/IRWebAPIKit.h b/IRWebAPIKit.h index bb9e63c..f8c37dd 100644 --- a/IRWebAPIKit.h +++ b/IRWebAPIKit.h @@ -7,23 +7,6 @@ // - - - -#if 0 && defined(DEBUG) - - #define IRWebAPIKitLog( s, ... ) NSLog( @"<%s : (%d)> %@",__FUNCTION__, __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] ) - -#else - - #define IRWebAPIKitLog( s, ... ) - -#endif - - - - - #import "IRWebAPIKitDefines.h" #import "IRWebAPIResponseParser.h" @@ -31,7 +14,13 @@ #import "IRWebAPIHelpers.h" #import "IRWebAPIEngine.h" -#import "IRWebAPIContext.h" +#import "IRWebAPIEngineContext.h" + +#import "IRWebAPIEngine+OperationFiring.h" +#import "IRWebAPIEngine+FormMultipart.h" +#import "IRWebAPIEngine+FormURLEncoding.h" +#import "IRWebAPIEngine+LocalCaching.h" + #import "IRWebAPIAuthenticator.h" #import "IRWebAPICredentials.h" #import "IRWebAPIInterface.h" @@ -42,18 +31,14 @@ #import "IRWebAPIInterfaceURLShortening.h" -#import "IRWebAPIGoogleReaderAuthenticator.h" #import "IRWebAPIXOAuthAuthenticator.h" -#import "IRWebAPITwitterInterface.h" -#import "IRWebAPIGoogleReaderInterface.h" - #import "IRWebAPIImageStorageProvider.h" -#import "IRWebAPITwitPicInterface.h" #import "IRRemoteResourcesManager.h" - +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIRequestOperation.h" diff --git a/IRWebAPIKit.j b/IRWebAPIKit.j deleted file mode 100644 index 57e9e3b..0000000 --- a/IRWebAPIKit.j +++ /dev/null @@ -1,34 +0,0 @@ -// IRWebAPIKit.j -// Evadne Wu at Iridia, 2010' - - - - - - @import - @import - @import - - @import "IRWebAPIEngine.j" - @import "IRWebAPIContext.j" - -// Working on… - @import "IRSiteReachability.j" - -// Mock! - @import "IRWebAPIMockJSONPConnection.j" - - - - - - // Time to talk about how this tool works: - // - // 1. Be flat in what you send, be three-dimensional in what you get. - // 2. Give JSON, take JSON. Give Objects, take Objects. - // 3. Register transformations in your initializer. Don’t do ad-hoc transformations. - - - - - \ No newline at end of file diff --git a/IRWebAPIKit.xcodeproj/project.pbxproj b/IRWebAPIKit.xcodeproj/project.pbxproj index 609d1e3..0239bea 100644 --- a/IRWebAPIKit.xcodeproj/project.pbxproj +++ b/IRWebAPIKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 130EFA1115E2205400254163 /* JSONKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 130EFA1015E2205400254163 /* JSONKit.h */; }; FF0D4C0B12ED96E500D9B97D /* IRWebAPIHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = FF0D4C0A12ED96E500D9B97D /* IRWebAPIHelpers.m */; }; FF0E874112B9F41C00DF571E /* IRWebAPIInterfaceURLShortening.h in Headers */ = {isa = PBXBuildFile; fileRef = FF0E874012B9F41C00DF571E /* IRWebAPIInterfaceURLShortening.h */; }; FF0E93E9132BB07000A316E1 /* IRRemoteResourcesManager.h in Headers */ = {isa = PBXBuildFile; fileRef = FF0E93E7132BB07000A316E1 /* IRRemoteResourcesManager.h */; }; @@ -17,16 +18,11 @@ FF25FA301299406200975BE3 /* IRWebAPICredentials.m in Sources */ = {isa = PBXBuildFile; fileRef = FF25FA2E1299406200975BE3 /* IRWebAPICredentials.m */; }; FF25FA331299406800975BE3 /* IRWebAPIAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = FF25FA311299406800975BE3 /* IRWebAPIAuthenticator.h */; }; FF25FA341299406800975BE3 /* IRWebAPIAuthenticator.m in Sources */ = {isa = PBXBuildFile; fileRef = FF25FA321299406800975BE3 /* IRWebAPIAuthenticator.m */; }; - FF25FA7F129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = FF25FA7D129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.h */; }; - FF25FA80129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.m in Sources */ = {isa = PBXBuildFile; fileRef = FF25FA7E129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.m */; }; FF25FCCA12996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.h in Headers */ = {isa = PBXBuildFile; fileRef = FF25FCC812996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.h */; }; FF25FCCB12996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.m in Sources */ = {isa = PBXBuildFile; fileRef = FF25FCC912996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.m */; }; FF25FD7E129971EC00975BE3 /* IRWebAPIHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = FF25FD7D129971EC00975BE3 /* IRWebAPIHelpers.h */; }; FF32C80B150F3A4200A9FE52 /* IRWebAPIKitTest.h in Headers */ = {isa = PBXBuildFile; fileRef = FF32C809150F3A4200A9FE52 /* IRWebAPIKitTest.h */; }; FF32C80C150F3A4200A9FE52 /* IRWebAPIKitTest.m in Sources */ = {isa = PBXBuildFile; fileRef = FF32C80A150F3A4200A9FE52 /* IRWebAPIKitTest.m */; }; - FF32C80F150F3C5E00A9FE52 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF32C80E150F3C5E00A9FE52 /* MobileCoreServices.framework */; }; - FF3DD7BA1348839D000C6380 /* IRWebAPITwitterInterface+Friendships.h in Headers */ = {isa = PBXBuildFile; fileRef = FF3DD7B81348839D000C6380 /* IRWebAPITwitterInterface+Friendships.h */; }; - FF3DD7BB1348839D000C6380 /* IRWebAPITwitterInterface+Friendships.m in Sources */ = {isa = PBXBuildFile; fileRef = FF3DD7B91348839D000C6380 /* IRWebAPITwitterInterface+Friendships.m */; }; FF45629312D057D6000239DC /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF45629212D057D6000239DC /* SenTestingKit.framework */; }; FF45629712D057F1000239DC /* libIRWebAPIKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FF7408241296A8D200571D46 /* libIRWebAPIKit.a */; }; FF45635B12D06A46000239DC /* IRWebAPIKitEntityDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = FF45635A12D06A46000239DC /* IRWebAPIKitEntityDefines.h */; }; @@ -36,15 +32,11 @@ FF460D09149CF80B00DB7F0B /* IRWebAPIEngine+ExternalTransforms.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF5AC731470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m */; }; FF460DB4149CFF3F00DB7F0B /* IRRemoteResourceDownloadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = FFB882B514234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h */; }; FF47A29B12A6486900AF729F /* IRWebAPIInterfaceAuthenticating.h in Headers */ = {isa = PBXBuildFile; fileRef = FF47A29A12A6486900AF729F /* IRWebAPIInterfaceAuthenticating.h */; }; - FF48661612A6329900B75591 /* IRWebAPIGoogleReaderInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = FF48661412A6329900B75591 /* IRWebAPIGoogleReaderInterface.h */; }; - FF48661712A6329900B75591 /* IRWebAPIGoogleReaderInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = FF48661512A6329900B75591 /* IRWebAPIGoogleReaderInterface.m */; }; FF4FCC6212F4637F0037F33C /* IRWebAPIResponseParser.m in Sources */ = {isa = PBXBuildFile; fileRef = FF4FCC6112F4637F0037F33C /* IRWebAPIResponseParser.m */; }; - FF5147BE12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.h in Headers */ = {isa = PBXBuildFile; fileRef = FF5147BC12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.h */; }; - FF5147BF12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m in Sources */ = {isa = PBXBuildFile; fileRef = FF5147BD12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m */; }; FF59A39B1441C94500BB1FDC /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF59A3571441C8B600BB1FDC /* Cocoa.framework */; }; FF59A3A11441C94500BB1FDC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FF59A39F1441C94500BB1FDC /* InfoPlist.strings */; }; FF59A3B11441C9C800BB1FDC /* IRWebAPIKitDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */; }; - FF59A3B21441C9CD00BB1FDC /* IRWebAPIContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408981296B06F00571D46 /* IRWebAPIContext.m */; }; + FF59A3B21441C9CD00BB1FDC /* IRWebAPIEngineContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408981296B06F00571D46 /* IRWebAPIEngineContext.m */; }; FF59A3B31441C9CD00BB1FDC /* IRWebAPIEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408461296A94900571D46 /* IRWebAPIEngine.m */; }; FF59A3B41441C9D100BB1FDC /* IRWebAPIEngine+LocalCaching.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */; }; FF59A3B51441C9D100BB1FDC /* IRWebAPIEngine+FormMultipart.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB7212EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m */; }; @@ -57,19 +49,15 @@ FF59A3BC1441C9F400BB1FDC /* IRRemoteResourceDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = FFB882B614234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m */; }; FF59A3BD1441C9F400BB1FDC /* IRWebAPIInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = FF896A6A12A5666D00AE2AF3 /* IRWebAPIInterface.m */; }; FF59A3BE1441C9F400BB1FDC /* IRWebAPIInterface+Validators.m in Sources */ = {isa = PBXBuildFile; fileRef = FF1B23CC12F3400F00B30B99 /* IRWebAPIInterface+Validators.m */; }; - FF609D1F12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = FF609D1D12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.h */; }; - FF609D2012E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = FF609D1E12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.m */; }; FF74082B1296A8E000571D46 /* IRWebAPIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7408291296A8E000571D46 /* IRWebAPIKit.h */; }; FF7408471296A94900571D46 /* IRWebAPIEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7408451296A94900571D46 /* IRWebAPIEngine.h */; }; FF7408481296A94900571D46 /* IRWebAPIEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408461296A94900571D46 /* IRWebAPIEngine.m */; }; - FF7408991296B06F00571D46 /* IRWebAPIContext.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7408971296B06F00571D46 /* IRWebAPIContext.h */; }; - FF74089A1296B06F00571D46 /* IRWebAPIContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408981296B06F00571D46 /* IRWebAPIContext.m */; }; + FF7408991296B06F00571D46 /* IRWebAPIEngineContext.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7408971296B06F00571D46 /* IRWebAPIEngineContext.h */; }; + FF74089A1296B06F00571D46 /* IRWebAPIEngineContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7408981296B06F00571D46 /* IRWebAPIEngineContext.m */; }; FF740CAA1296EB0C00571D46 /* IRWebAPIResponseParser.h in Headers */ = {isa = PBXBuildFile; fileRef = FF740CA91296EB0C00571D46 /* IRWebAPIResponseParser.h */; }; FF7EB68A1467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7EB6881467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h */; }; FF7EB68B1467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7EB6891467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m */; }; FF7F44A712EDB36E00DC1628 /* IRWebAPIInterfaceOAuthEchoReliance.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7F44A612EDB36E00DC1628 /* IRWebAPIInterfaceOAuthEchoReliance.h */; }; - FF7F44B712EDB44400DC1628 /* IRWebAPITwitPicInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7F44B512EDB44400DC1628 /* IRWebAPITwitPicInterface.h */; }; - FF7F44B812EDB44400DC1628 /* IRWebAPITwitPicInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = FF7F44B612EDB44400DC1628 /* IRWebAPITwitPicInterface.m */; }; FF7F44C412EDB52800DC1628 /* IRWebAPIImageStorageProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = FF7F44C312EDB52800DC1628 /* IRWebAPIImageStorageProvider.h */; }; FF7F44E112EDB74F00DC1628 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF7F44E012EDB74F00DC1628 /* CoreFoundation.framework */; }; FF7F44E312EDB74F00DC1628 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF7F44E212EDB74F00DC1628 /* Foundation.framework */; }; @@ -77,9 +65,13 @@ FF7F44E912EDB74F00DC1628 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF7F44E812EDB74F00DC1628 /* SystemConfiguration.framework */; }; FF896A6B12A5666D00AE2AF3 /* IRWebAPIInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = FF896A6912A5666D00AE2AF3 /* IRWebAPIInterface.h */; }; FF896A6C12A5666D00AE2AF3 /* IRWebAPIInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = FF896A6A12A5666D00AE2AF3 /* IRWebAPIInterface.m */; }; - FF896DD512A567FA00AE2AF3 /* IRWebAPITwitterInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = FF896DD312A567FA00AE2AF3 /* IRWebAPITwitterInterface.h */; }; - FF896DD612A567FA00AE2AF3 /* IRWebAPITwitterInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = FF896DD412A567FA00AE2AF3 /* IRWebAPITwitterInterface.m */; }; FF8974E212A57F3800AE2AF3 /* IRWebAPIInterfaceXOAuthAuthenticating.h in Headers */ = {isa = PBXBuildFile; fileRef = FF8974E112A57F3800AE2AF3 /* IRWebAPIInterfaceXOAuthAuthenticating.h */; }; + FF9838A31598313D00CFF2DF /* IRWebAPIRequestContext.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9838A11598313D00CFF2DF /* IRWebAPIRequestContext.h */; }; + FF9838A41598313D00CFF2DF /* IRWebAPIRequestContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838A21598313D00CFF2DF /* IRWebAPIRequestContext.m */; }; + FF9838A815984A4A00CFF2DF /* IRWebAPIRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9838A615984A4A00CFF2DF /* IRWebAPIRequestOperation.h */; }; + FF9838A915984A4A00CFF2DF /* IRWebAPIRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838A715984A4A00CFF2DF /* IRWebAPIRequestOperation.m */; }; + FF9838AC1598502B00CFF2DF /* IRWebAPIInterceptor.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9838AA1598502B00CFF2DF /* IRWebAPIInterceptor.h */; }; + FF9838AD1598502B00CFF2DF /* IRWebAPIInterceptor.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838AB1598502B00CFF2DF /* IRWebAPIInterceptor.m */; }; FF9AFB4212EC59040037E930 /* IRWebAPIEngine+LocalCaching.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9AFB4012EC59040037E930 /* IRWebAPIEngine+LocalCaching.h */; }; FF9AFB4312EC59040037E930 /* IRWebAPIEngine+LocalCaching.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */; }; FF9AFB4C12EC597C0037E930 /* IRWebAPIKitDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9AFB4B12EC597C0037E930 /* IRWebAPIKitDefines.h */; }; @@ -87,25 +79,19 @@ FF9AFB7412EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB7212EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m */; }; FF9AFB8012EC5CB80037E930 /* IRWebAPIKitDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */; }; FF9AFBF312EC5E9F0037E930 /* IRWebAPIKitDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */; }; - FFAA4351134A8CA600341FAE /* IRWebAPITwitterInterface+User.h in Headers */ = {isa = PBXBuildFile; fileRef = FFAA434F134A8CA600341FAE /* IRWebAPITwitterInterface+User.h */; }; - FFAA4352134A8CA600341FAE /* IRWebAPITwitterInterface+User.m in Sources */ = {isa = PBXBuildFile; fileRef = FFAA4350134A8CA600341FAE /* IRWebAPITwitterInterface+User.m */; }; FFB882B714234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = FFB882B514234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h */; }; FFB882B814234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = FFB882B614234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m */; }; - FFC41B9112B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.h in Headers */ = {isa = PBXBuildFile; fileRef = FFC41B8F12B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.h */; }; - FFC41B9212B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m in Sources */ = {isa = PBXBuildFile; fileRef = FFC41B9012B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m */; }; - FFDA9D0A13278C4500546B66 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFDA9D0913278C4500546B66 /* MobileCoreServices.framework */; }; + FFBEE72E15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.h in Headers */ = {isa = PBXBuildFile; fileRef = FFBEE72C15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.h */; }; + FFBEE72F15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m in Sources */ = {isa = PBXBuildFile; fileRef = FFBEE72D15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m */; }; + FFDB8EFD15943C7800FA7E9B /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */; }; + FFDB8EFE15943C8100FA7E9B /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */; }; + FFDE51EC159AEF870086F9B0 /* IRWebAPIRequestContext.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838A21598313D00CFF2DF /* IRWebAPIRequestContext.m */; }; + FFDE51EE159AEF940086F9B0 /* IRWebAPIRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838A715984A4A00CFF2DF /* IRWebAPIRequestOperation.m */; }; + FFDE51EF159AEFA90086F9B0 /* IRWebAPIInterceptor.m in Sources */ = {isa = PBXBuildFile; fileRef = FF9838AB1598502B00CFF2DF /* IRWebAPIInterceptor.m */; }; + FFDE51FF159AF8F10086F9B0 /* IRWebAPIEngine+FormMultipart.h in Headers */ = {isa = PBXBuildFile; fileRef = FF9AFB7112EC5C060037E930 /* IRWebAPIEngine+FormMultipart.h */; }; + FFDE5200159AF9030086F9B0 /* IRWebAPIEngine+OperationFiring.m in Sources */ = {isa = PBXBuildFile; fileRef = FFBEE72D15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m */; }; FFF5AC741470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h in Headers */ = {isa = PBXBuildFile; fileRef = FFF5AC721470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h */; }; FFF5AC751470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF5AC731470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m */; }; - FFF90E1C12E3805D00464897 /* IRWebAPITwitterInterface+Lists.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF90C9512E3768C00464897 /* IRWebAPITwitterInterface+Lists.m */; }; - FFF90E1D12E3805D00464897 /* IRWebAPITwitterInterface+Validators.m in Sources */ = {isa = PBXBuildFile; fileRef = FFF90D0A12E37D0400464897 /* IRWebAPITwitterInterface+Validators.m */; }; - FFF90E1E12E3807700464897 /* IRWebAPITwitterInterface+Validators.h in Headers */ = {isa = PBXBuildFile; fileRef = FFF90D0912E37D0400464897 /* IRWebAPITwitterInterface+Validators.h */; }; - FFF90E1F12E3807700464897 /* IRWebAPITwitterInterface+Validators.m in Headers */ = {isa = PBXBuildFile; fileRef = FFF90D0A12E37D0400464897 /* IRWebAPITwitterInterface+Validators.m */; }; - FFF90E2012E3807700464897 /* IRWebAPITwitterInterface.m in Headers */ = {isa = PBXBuildFile; fileRef = FF896DD412A567FA00AE2AF3 /* IRWebAPITwitterInterface.m */; }; - FFF90E2112E3807700464897 /* IRWebAPITwitterInterface+Timeline.m in Headers */ = {isa = PBXBuildFile; fileRef = FF5147BD12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m */; }; - FFF90E2212E3807700464897 /* IRWebAPITwitterInterface+Lists.h in Headers */ = {isa = PBXBuildFile; fileRef = FFF90C9412E3768C00464897 /* IRWebAPITwitterInterface+Lists.h */; }; - FFF90E2312E3807700464897 /* IRWebAPITwitterInterface+Lists.m in Headers */ = {isa = PBXBuildFile; fileRef = FFF90C9512E3768C00464897 /* IRWebAPITwitterInterface+Lists.m */; }; - FFF90E2412E3807700464897 /* IRWebAPITwitterInterface+Geo.m in Headers */ = {isa = PBXBuildFile; fileRef = FFC41B9012B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m */; }; - FFF90E2512E3807700464897 /* IRWebAPIGoogleReaderInterface.m in Headers */ = {isa = PBXBuildFile; fileRef = FF48661512A6329900B75591 /* IRWebAPIGoogleReaderInterface.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -119,6 +105,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 130EFA1015E2205400254163 /* JSONKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONKit.h; sourceTree = ""; }; FF0D4C0A12ED96E500D9B97D /* IRWebAPIHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIHelpers.m; sourceTree = ""; }; FF0E874012B9F41C00DF571E /* IRWebAPIInterfaceURLShortening.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterfaceURLShortening.h; sourceTree = ""; }; FF0E93E7132BB07000A316E1 /* IRRemoteResourcesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRRemoteResourcesManager.h; sourceTree = ""; }; @@ -129,16 +116,11 @@ FF25FA2E1299406200975BE3 /* IRWebAPICredentials.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPICredentials.m; sourceTree = ""; }; FF25FA311299406800975BE3 /* IRWebAPIAuthenticator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIAuthenticator.h; sourceTree = ""; }; FF25FA321299406800975BE3 /* IRWebAPIAuthenticator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIAuthenticator.m; sourceTree = ""; }; - FF25FA7D129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIGoogleReaderAuthenticator.h; sourceTree = ""; }; - FF25FA7E129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIGoogleReaderAuthenticator.m; sourceTree = ""; }; FF25FCC812996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIXOAuthAuthenticator.h; sourceTree = ""; }; FF25FCC912996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIXOAuthAuthenticator.m; sourceTree = ""; }; FF25FD7D129971EC00975BE3 /* IRWebAPIHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIHelpers.h; sourceTree = ""; }; FF32C809150F3A4200A9FE52 /* IRWebAPIKitTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIKitTest.h; sourceTree = ""; }; FF32C80A150F3A4200A9FE52 /* IRWebAPIKitTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIKitTest.m; sourceTree = ""; }; - FF32C80E150F3C5E00A9FE52 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; - FF3DD7B81348839D000C6380 /* IRWebAPITwitterInterface+Friendships.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+Friendships.h"; sourceTree = ""; }; - FF3DD7B91348839D000C6380 /* IRWebAPITwitterInterface+Friendships.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+Friendships.m"; sourceTree = ""; }; FF45627812D05708000239DC /* IRWebAPIKitTest.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IRWebAPIKitTest.octest; sourceTree = BUILT_PRODUCTS_DIR; }; FF45627912D05708000239DC /* IRWebAPIKitTest-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "IRWebAPIKitTest-Info.plist"; sourceTree = ""; }; FF45629212D057D6000239DC /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; @@ -146,11 +128,7 @@ FF45635C12D06A50000239DC /* IRWebAPIKitEntityDefinesHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIKitEntityDefinesHeader.h; sourceTree = ""; }; FF45637712D07653000239DC /* IRWebAPIKitEntityDefinesFooter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIKitEntityDefinesFooter.h; sourceTree = ""; }; FF47A29A12A6486900AF729F /* IRWebAPIInterfaceAuthenticating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterfaceAuthenticating.h; sourceTree = ""; }; - FF48661412A6329900B75591 /* IRWebAPIGoogleReaderInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIGoogleReaderInterface.h; sourceTree = ""; }; - FF48661512A6329900B75591 /* IRWebAPIGoogleReaderInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIGoogleReaderInterface.m; sourceTree = ""; }; FF4FCC6112F4637F0037F33C /* IRWebAPIResponseParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIResponseParser.m; sourceTree = ""; }; - FF5147BC12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+Timeline.h"; sourceTree = ""; }; - FF5147BD12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+Timeline.m"; sourceTree = ""; }; FF59A3571441C8B600BB1FDC /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; FF59A35A1441C8B600BB1FDC /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; FF59A35B1441C8B600BB1FDC /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; @@ -159,26 +137,16 @@ FF59A39E1441C94500BB1FDC /* IRWebAPIKitX-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "IRWebAPIKitX-Info.plist"; sourceTree = ""; }; FF59A3A01441C94500BB1FDC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; FF59A3A21441C94500BB1FDC /* IRWebAPIKitX-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIKitX-Prefix.pch"; sourceTree = ""; }; - FF609D1D12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+DirectMessages.h"; sourceTree = ""; }; - FF609D1E12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+DirectMessages.m"; sourceTree = ""; }; - FF74081A1296A89500571D46 /* IRSiteReachability.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRSiteReachability.j; sourceTree = ""; }; - FF74081B1296A89500571D46 /* IRWebAPIContext.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRWebAPIContext.j; sourceTree = ""; }; - FF74081C1296A89500571D46 /* IRWebAPIEngine.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRWebAPIEngine.j; sourceTree = ""; }; - FF74081D1296A89500571D46 /* IRWebAPIKit.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRWebAPIKit.j; sourceTree = ""; }; - FF74081E1296A89500571D46 /* IRWebAPIMockJSONPConnection.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRWebAPIMockJSONPConnection.j; sourceTree = ""; }; - FF74081F1296A89500571D46 /* IRWebAPIModel.j */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = IRWebAPIModel.j; sourceTree = ""; }; FF7408241296A8D200571D46 /* libIRWebAPIKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libIRWebAPIKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; FF7408291296A8E000571D46 /* IRWebAPIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIKit.h; sourceTree = ""; }; FF7408451296A94900571D46 /* IRWebAPIEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIEngine.h; sourceTree = ""; }; FF7408461296A94900571D46 /* IRWebAPIEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIEngine.m; sourceTree = ""; }; - FF7408971296B06F00571D46 /* IRWebAPIContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIContext.h; sourceTree = ""; }; - FF7408981296B06F00571D46 /* IRWebAPIContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIContext.m; sourceTree = ""; }; + FF7408971296B06F00571D46 /* IRWebAPIEngineContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIEngineContext.h; sourceTree = ""; }; + FF7408981296B06F00571D46 /* IRWebAPIEngineContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIEngineContext.m; sourceTree = ""; }; FF740CA91296EB0C00571D46 /* IRWebAPIResponseParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIResponseParser.h; sourceTree = ""; }; FF7EB6881467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+FormURLEncoding.h"; sourceTree = ""; }; FF7EB6891467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPIEngine+FormURLEncoding.m"; sourceTree = ""; }; FF7F44A612EDB36E00DC1628 /* IRWebAPIInterfaceOAuthEchoReliance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterfaceOAuthEchoReliance.h; sourceTree = ""; }; - FF7F44B512EDB44400DC1628 /* IRWebAPITwitPicInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPITwitPicInterface.h; sourceTree = ""; }; - FF7F44B612EDB44400DC1628 /* IRWebAPITwitPicInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPITwitPicInterface.m; sourceTree = ""; }; FF7F44C312EDB52800DC1628 /* IRWebAPIImageStorageProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIImageStorageProvider.h; sourceTree = ""; }; FF7F44E012EDB74F00DC1628 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; FF7F44E212EDB74F00DC1628 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -186,29 +154,27 @@ FF7F44E812EDB74F00DC1628 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; FF896A6912A5666D00AE2AF3 /* IRWebAPIInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterface.h; sourceTree = ""; }; FF896A6A12A5666D00AE2AF3 /* IRWebAPIInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIInterface.m; sourceTree = ""; }; - FF896DD312A567FA00AE2AF3 /* IRWebAPITwitterInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPITwitterInterface.h; sourceTree = ""; }; - FF896DD412A567FA00AE2AF3 /* IRWebAPITwitterInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPITwitterInterface.m; sourceTree = ""; }; FF8974E112A57F3800AE2AF3 /* IRWebAPIInterfaceXOAuthAuthenticating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterfaceXOAuthAuthenticating.h; sourceTree = ""; }; + FF9838A11598313D00CFF2DF /* IRWebAPIRequestContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIRequestContext.h; sourceTree = ""; }; + FF9838A21598313D00CFF2DF /* IRWebAPIRequestContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIRequestContext.m; sourceTree = ""; }; + FF9838A615984A4A00CFF2DF /* IRWebAPIRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIRequestOperation.h; sourceTree = ""; }; + FF9838A715984A4A00CFF2DF /* IRWebAPIRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIRequestOperation.m; sourceTree = ""; }; + FF9838AA1598502B00CFF2DF /* IRWebAPIInterceptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIInterceptor.h; sourceTree = ""; }; + FF9838AB1598502B00CFF2DF /* IRWebAPIInterceptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIInterceptor.m; sourceTree = ""; }; FF9AFB4012EC59040037E930 /* IRWebAPIEngine+LocalCaching.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+LocalCaching.h"; sourceTree = ""; }; FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPIEngine+LocalCaching.m"; sourceTree = ""; }; FF9AFB4B12EC597C0037E930 /* IRWebAPIKitDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRWebAPIKitDefines.h; sourceTree = ""; }; FF9AFB7112EC5C060037E930 /* IRWebAPIEngine+FormMultipart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+FormMultipart.h"; sourceTree = ""; }; FF9AFB7212EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPIEngine+FormMultipart.m"; sourceTree = ""; }; FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRWebAPIKitDefines.m; sourceTree = ""; }; - FFAA434F134A8CA600341FAE /* IRWebAPITwitterInterface+User.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+User.h"; sourceTree = ""; }; - FFAA4350134A8CA600341FAE /* IRWebAPITwitterInterface+User.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+User.m"; sourceTree = ""; }; FFB882B514234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRRemoteResourceDownloadOperation.h; sourceTree = ""; }; FFB882B614234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRRemoteResourceDownloadOperation.m; sourceTree = ""; }; - FFC41B8F12B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+Geo.h"; sourceTree = ""; }; - FFC41B9012B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+Geo.m"; sourceTree = ""; }; - FFDA9D0913278C4500546B66 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; + FFBEE72C15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+OperationFiring.h"; sourceTree = ""; }; + FFBEE72D15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPIEngine+OperationFiring.m"; sourceTree = ""; }; + FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; FFE2607212D084CB001AF1AF /* IRWebAPIKitEntityDefinesGenerator.rb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.ruby; path = IRWebAPIKitEntityDefinesGenerator.rb; sourceTree = ""; }; FFF5AC721470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPIEngine+ExternalTransforms.h"; sourceTree = ""; }; FFF5AC731470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPIEngine+ExternalTransforms.m"; sourceTree = ""; }; - FFF90C9412E3768C00464897 /* IRWebAPITwitterInterface+Lists.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+Lists.h"; sourceTree = ""; }; - FFF90C9512E3768C00464897 /* IRWebAPITwitterInterface+Lists.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+Lists.m"; sourceTree = ""; }; - FFF90D0912E37D0400464897 /* IRWebAPITwitterInterface+Validators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IRWebAPITwitterInterface+Validators.h"; sourceTree = ""; }; - FFF90D0A12E37D0400464897 /* IRWebAPITwitterInterface+Validators.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IRWebAPITwitterInterface+Validators.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -218,7 +184,7 @@ files = ( FF45629712D057F1000239DC /* libIRWebAPIKit.a in Frameworks */, FF45629312D057D6000239DC /* SenTestingKit.framework in Frameworks */, - FF32C80F150F3C5E00A9FE52 /* MobileCoreServices.framework in Frameworks */, + FFDB8EFE15943C8100FA7E9B /* MobileCoreServices.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -234,11 +200,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - FFDA9D0A13278C4500546B66 /* MobileCoreServices.framework in Frameworks */, FF7F44E112EDB74F00DC1628 /* CoreFoundation.framework in Frameworks */, FF7F44E312EDB74F00DC1628 /* Foundation.framework in Frameworks */, FF7F44E712EDB74F00DC1628 /* Security.framework in Frameworks */, FF7F44E912EDB74F00DC1628 /* SystemConfiguration.framework in Frameworks */, + FFDB8EFD15943C7800FA7E9B /* MobileCoreServices.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -250,10 +216,10 @@ children = ( FF7F44E012EDB74F00DC1628 /* CoreFoundation.framework */, FF7F44E212EDB74F00DC1628 /* Foundation.framework */, - FFDA9D0913278C4500546B66 /* MobileCoreServices.framework */, FF7F44E612EDB74F00DC1628 /* Security.framework */, FF7F44E812EDB74F00DC1628 /* SystemConfiguration.framework */, FF59A3571441C8B600BB1FDC /* Cocoa.framework */, + FFDB8EFC15943C7800FA7E9B /* MobileCoreServices.framework */, FF59A3591441C8B600BB1FDC /* Other Frameworks */, ); name = Frameworks; @@ -298,26 +264,30 @@ FF25FA7B129944C200975BE3 /* Engine & Foundation */ = { isa = PBXGroup; children = ( - FF7408971296B06F00571D46 /* IRWebAPIContext.h */, - FF7408981296B06F00571D46 /* IRWebAPIContext.m */, + FF7408971296B06F00571D46 /* IRWebAPIEngineContext.h */, + FF7408981296B06F00571D46 /* IRWebAPIEngineContext.m */, FF7408451296A94900571D46 /* IRWebAPIEngine.h */, FF7408461296A94900571D46 /* IRWebAPIEngine.m */, - FF9AFB5B12EC5A560037E930 /* IRWebAPIEngine Additions */, + FFBEE72C15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.h */, + FFBEE72D15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m */, + FF9838A11598313D00CFF2DF /* IRWebAPIRequestContext.h */, + FF9838A21598313D00CFF2DF /* IRWebAPIRequestContext.m */, + FF9838A615984A4A00CFF2DF /* IRWebAPIRequestOperation.h */, + FF9838A715984A4A00CFF2DF /* IRWebAPIRequestOperation.m */, + FF9838AA1598502B00CFF2DF /* IRWebAPIInterceptor.h */, + FF9838AB1598502B00CFF2DF /* IRWebAPIInterceptor.m */, + FF9AFB4012EC59040037E930 /* IRWebAPIEngine+LocalCaching.h */, + FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */, + FF9AFB7112EC5C060037E930 /* IRWebAPIEngine+FormMultipart.h */, + FF9AFB7212EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m */, + FF7EB6881467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h */, + FF7EB6891467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m */, + FFF5AC721470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h */, + FFF5AC731470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m */, ); name = "Engine & Foundation"; sourceTree = ""; }; - FF25FA7C129944D000975BE3 /* Google Reader */ = { - isa = PBXGroup; - children = ( - FF25FA7D129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.h */, - FF25FA7E129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.m */, - FF48661412A6329900B75591 /* IRWebAPIGoogleReaderInterface.h */, - FF48661512A6329900B75591 /* IRWebAPIGoogleReaderInterface.m */, - ); - name = "Google Reader"; - sourceTree = ""; - }; FF45628512D05732000239DC /* Test */ = { isa = PBXGroup; children = ( @@ -360,7 +330,7 @@ FF74080C1296A88400571D46 = { isa = PBXGroup; children = ( - FF32C80E150F3C5E00A9FE52 /* MobileCoreServices.framework */, + 130EFA1015E2205400254163 /* JSONKit.h */, FF9AFB4B12EC597C0037E930 /* IRWebAPIKitDefines.h */, FF9AFB7F12EC5CB80037E930 /* IRWebAPIKitDefines.m */, FF7408291296A8E000571D46 /* IRWebAPIKit.h */, @@ -370,26 +340,12 @@ FF0E93DE132BAFA200A316E1 /* Remote Resources Handling */, FF896B5812A5667A00AE2AF3 /* Interfacing Wrapper */, FF45628512D05732000239DC /* Test */, - FF7408191296A88B00571D46 /* Cappuccino */, FF59A39C1441C94500BB1FDC /* IRWebAPIKitX */, FF0E93DD132BAF9200A316E1 /* Frameworks */, FF7408251296A8D200571D46 /* Products */, ); sourceTree = ""; }; - FF7408191296A88B00571D46 /* Cappuccino */ = { - isa = PBXGroup; - children = ( - FF74081A1296A89500571D46 /* IRSiteReachability.j */, - FF74081B1296A89500571D46 /* IRWebAPIContext.j */, - FF74081C1296A89500571D46 /* IRWebAPIEngine.j */, - FF74081D1296A89500571D46 /* IRWebAPIKit.j */, - FF74081E1296A89500571D46 /* IRWebAPIMockJSONPConnection.j */, - FF74081F1296A89500571D46 /* IRWebAPIModel.j */, - ); - name = Cappuccino; - sourceTree = ""; - }; FF7408251296A8D200571D46 /* Products */ = { isa = PBXGroup; children = ( @@ -400,15 +356,6 @@ name = Products; sourceTree = ""; }; - FF7F44D512EDB66500DC1628 /* TwitPic */ = { - isa = PBXGroup; - children = ( - FF7F44B512EDB44400DC1628 /* IRWebAPITwitPicInterface.h */, - FF7F44B612EDB44400DC1628 /* IRWebAPITwitPicInterface.m */, - ); - name = TwitPic; - sourceTree = ""; - }; FF896B5812A5667A00AE2AF3 /* Interfacing Wrapper */ = { isa = PBXGroup; children = ( @@ -421,51 +368,10 @@ FF8974E112A57F3800AE2AF3 /* IRWebAPIInterfaceXOAuthAuthenticating.h */, FF0E874012B9F41C00DF571E /* IRWebAPIInterfaceURLShortening.h */, FF7F44C312EDB52800DC1628 /* IRWebAPIImageStorageProvider.h */, - FF896DD212A567ED00AE2AF3 /* Twitter */, - FF25FA7C129944D000975BE3 /* Google Reader */, - FF7F44D512EDB66500DC1628 /* TwitPic */, ); name = "Interfacing Wrapper"; sourceTree = ""; }; - FF896DD212A567ED00AE2AF3 /* Twitter */ = { - isa = PBXGroup; - children = ( - FF896DD312A567FA00AE2AF3 /* IRWebAPITwitterInterface.h */, - FF896DD412A567FA00AE2AF3 /* IRWebAPITwitterInterface.m */, - FFF90D0912E37D0400464897 /* IRWebAPITwitterInterface+Validators.h */, - FFF90D0A12E37D0400464897 /* IRWebAPITwitterInterface+Validators.m */, - FF5147BC12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.h */, - FF5147BD12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m */, - FF609D1D12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.h */, - FF609D1E12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.m */, - FFF90C9412E3768C00464897 /* IRWebAPITwitterInterface+Lists.h */, - FFF90C9512E3768C00464897 /* IRWebAPITwitterInterface+Lists.m */, - FFAA434F134A8CA600341FAE /* IRWebAPITwitterInterface+User.h */, - FFAA4350134A8CA600341FAE /* IRWebAPITwitterInterface+User.m */, - FF3DD7B81348839D000C6380 /* IRWebAPITwitterInterface+Friendships.h */, - FF3DD7B91348839D000C6380 /* IRWebAPITwitterInterface+Friendships.m */, - FFC41B8F12B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.h */, - FFC41B9012B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m */, - ); - name = Twitter; - sourceTree = ""; - }; - FF9AFB5B12EC5A560037E930 /* IRWebAPIEngine Additions */ = { - isa = PBXGroup; - children = ( - FF9AFB4012EC59040037E930 /* IRWebAPIEngine+LocalCaching.h */, - FF9AFB4112EC59040037E930 /* IRWebAPIEngine+LocalCaching.m */, - FF9AFB7112EC5C060037E930 /* IRWebAPIEngine+FormMultipart.h */, - FF9AFB7212EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m */, - FF7EB6881467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h */, - FF7EB6891467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m */, - FFF5AC721470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h */, - FFF5AC731470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m */, - ); - name = "IRWebAPIEngine Additions "; - sourceTree = ""; - }; FFE2607C12D0858A001AF1AF /* XML Entity Definitions */ = { isa = PBXGroup; children = ( @@ -485,6 +391,7 @@ buildActionMask = 2147483647; files = ( FF460DB4149CFF3F00DB7F0B /* IRRemoteResourceDownloadOperation.h in Headers */, + FFDE51FF159AF8F10086F9B0 /* IRWebAPIEngine+FormMultipart.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -494,11 +401,10 @@ files = ( FF74082B1296A8E000571D46 /* IRWebAPIKit.h in Headers */, FF7408471296A94900571D46 /* IRWebAPIEngine.h in Headers */, - FF7408991296B06F00571D46 /* IRWebAPIContext.h in Headers */, + FF7408991296B06F00571D46 /* IRWebAPIEngineContext.h in Headers */, FF740CAA1296EB0C00571D46 /* IRWebAPIResponseParser.h in Headers */, FF25FA2F1299406200975BE3 /* IRWebAPICredentials.h in Headers */, FF25FA331299406800975BE3 /* IRWebAPIAuthenticator.h in Headers */, - FF25FA7F129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.h in Headers */, FF25FCCA12996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.h in Headers */, FF25FD7E129971EC00975BE3 /* IRWebAPIHelpers.h in Headers */, FF896A6B12A5666D00AE2AF3 /* IRWebAPIInterface.h in Headers */, @@ -508,32 +414,21 @@ FF45635B12D06A46000239DC /* IRWebAPIKitEntityDefines.h in Headers */, FF45635D12D06A50000239DC /* IRWebAPIKitEntityDefinesHeader.h in Headers */, FF45637812D07653000239DC /* IRWebAPIKitEntityDefinesFooter.h in Headers */, - FF896DD512A567FA00AE2AF3 /* IRWebAPITwitterInterface.h in Headers */, - FFF90E1E12E3807700464897 /* IRWebAPITwitterInterface+Validators.h in Headers */, - FFF90E1F12E3807700464897 /* IRWebAPITwitterInterface+Validators.m in Headers */, - FFF90E2012E3807700464897 /* IRWebAPITwitterInterface.m in Headers */, - FF5147BE12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.h in Headers */, - FFF90E2112E3807700464897 /* IRWebAPITwitterInterface+Timeline.m in Headers */, - FFF90E2212E3807700464897 /* IRWebAPITwitterInterface+Lists.h in Headers */, - FFF90E2312E3807700464897 /* IRWebAPITwitterInterface+Lists.m in Headers */, - FFC41B9112B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.h in Headers */, - FFF90E2412E3807700464897 /* IRWebAPITwitterInterface+Geo.m in Headers */, - FF48661612A6329900B75591 /* IRWebAPIGoogleReaderInterface.h in Headers */, - FFF90E2512E3807700464897 /* IRWebAPIGoogleReaderInterface.m in Headers */, - FF609D1F12E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.h in Headers */, FF9AFB4212EC59040037E930 /* IRWebAPIEngine+LocalCaching.h in Headers */, FF9AFB4C12EC597C0037E930 /* IRWebAPIKitDefines.h in Headers */, FF9AFB7312EC5C060037E930 /* IRWebAPIEngine+FormMultipart.h in Headers */, FF7F44A712EDB36E00DC1628 /* IRWebAPIInterfaceOAuthEchoReliance.h in Headers */, - FF7F44B712EDB44400DC1628 /* IRWebAPITwitPicInterface.h in Headers */, FF7F44C412EDB52800DC1628 /* IRWebAPIImageStorageProvider.h in Headers */, FF1B23CD12F3400F00B30B99 /* IRWebAPIInterface+Validators.h in Headers */, FF0E93E9132BB07000A316E1 /* IRRemoteResourcesManager.h in Headers */, - FF3DD7BA1348839D000C6380 /* IRWebAPITwitterInterface+Friendships.h in Headers */, - FFAA4351134A8CA600341FAE /* IRWebAPITwitterInterface+User.h in Headers */, FFB882B714234CBF00DA2876 /* IRRemoteResourceDownloadOperation.h in Headers */, FF7EB68A1467B876002718DC /* IRWebAPIEngine+FormURLEncoding.h in Headers */, FFF5AC741470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.h in Headers */, + FF9838A31598313D00CFF2DF /* IRWebAPIRequestContext.h in Headers */, + FF9838A815984A4A00CFF2DF /* IRWebAPIRequestOperation.h in Headers */, + FF9838AC1598502B00CFF2DF /* IRWebAPIInterceptor.h in Headers */, + FFBEE72E15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.h in Headers */, + 130EFA1115E2205400254163 /* JSONKit.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -672,7 +567,7 @@ buildActionMask = 2147483647; files = ( FF59A3B11441C9C800BB1FDC /* IRWebAPIKitDefines.m in Sources */, - FF59A3B21441C9CD00BB1FDC /* IRWebAPIContext.m in Sources */, + FF59A3B21441C9CD00BB1FDC /* IRWebAPIEngineContext.m in Sources */, FF59A3B31441C9CD00BB1FDC /* IRWebAPIEngine.m in Sources */, FF59A3B41441C9D100BB1FDC /* IRWebAPIEngine+LocalCaching.m in Sources */, FF59A3B51441C9D100BB1FDC /* IRWebAPIEngine+FormMultipart.m in Sources */, @@ -687,6 +582,10 @@ FF59A3BE1441C9F400BB1FDC /* IRWebAPIInterface+Validators.m in Sources */, FF460D07149CF80600DB7F0B /* IRWebAPIEngine+FormURLEncoding.m in Sources */, FF460D09149CF80B00DB7F0B /* IRWebAPIEngine+ExternalTransforms.m in Sources */, + FFDE51EC159AEF870086F9B0 /* IRWebAPIRequestContext.m in Sources */, + FFDE51EE159AEF940086F9B0 /* IRWebAPIRequestOperation.m in Sources */, + FFDE51EF159AEFA90086F9B0 /* IRWebAPIInterceptor.m in Sources */, + FFDE5200159AF9030086F9B0 /* IRWebAPIEngine+OperationFiring.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -696,31 +595,24 @@ files = ( FF9AFBF312EC5E9F0037E930 /* IRWebAPIKitDefines.m in Sources */, FF896A6C12A5666D00AE2AF3 /* IRWebAPIInterface.m in Sources */, - FF74089A1296B06F00571D46 /* IRWebAPIContext.m in Sources */, - FF896DD612A567FA00AE2AF3 /* IRWebAPITwitterInterface.m in Sources */, + FF74089A1296B06F00571D46 /* IRWebAPIEngineContext.m in Sources */, FF25FA341299406800975BE3 /* IRWebAPIAuthenticator.m in Sources */, FF25FA301299406200975BE3 /* IRWebAPICredentials.m in Sources */, - FF25FA80129944E800975BE3 /* IRWebAPIGoogleReaderAuthenticator.m in Sources */, FF25FCCB12996A5600975BE3 /* IRWebAPIXOAuthAuthenticator.m in Sources */, FF7408481296A94900571D46 /* IRWebAPIEngine.m in Sources */, - FF48661712A6329900B75591 /* IRWebAPIGoogleReaderInterface.m in Sources */, - FFC41B9212B8C59B008EF3D4 /* IRWebAPITwitterInterface+Geo.m in Sources */, - FF5147BF12BBBBC000F7424F /* IRWebAPITwitterInterface+Timeline.m in Sources */, - FFF90E1C12E3805D00464897 /* IRWebAPITwitterInterface+Lists.m in Sources */, - FFF90E1D12E3805D00464897 /* IRWebAPITwitterInterface+Validators.m in Sources */, - FF609D2012E4A13E00CD61EB /* IRWebAPITwitterInterface+DirectMessages.m in Sources */, FF9AFB4312EC59040037E930 /* IRWebAPIEngine+LocalCaching.m in Sources */, FF9AFB7412EC5C060037E930 /* IRWebAPIEngine+FormMultipart.m in Sources */, FF0D4C0B12ED96E500D9B97D /* IRWebAPIHelpers.m in Sources */, - FF7F44B812EDB44400DC1628 /* IRWebAPITwitPicInterface.m in Sources */, FF1B23CE12F3400F00B30B99 /* IRWebAPIInterface+Validators.m in Sources */, FF4FCC6212F4637F0037F33C /* IRWebAPIResponseParser.m in Sources */, FF0E93EA132BB07000A316E1 /* IRRemoteResourcesManager.m in Sources */, - FF3DD7BB1348839D000C6380 /* IRWebAPITwitterInterface+Friendships.m in Sources */, - FFAA4352134A8CA600341FAE /* IRWebAPITwitterInterface+User.m in Sources */, FFB882B814234CBF00DA2876 /* IRRemoteResourceDownloadOperation.m in Sources */, FF7EB68B1467B876002718DC /* IRWebAPIEngine+FormURLEncoding.m in Sources */, FFF5AC751470FFC600512775 /* IRWebAPIEngine+ExternalTransforms.m in Sources */, + FF9838A41598313D00CFF2DF /* IRWebAPIRequestContext.m in Sources */, + FF9838A915984A4A00CFF2DF /* IRWebAPIRequestOperation.m in Sources */, + FF9838AD1598502B00CFF2DF /* IRWebAPIInterceptor.m in Sources */, + FFBEE72F15986BB40057BEA0 /* IRWebAPIEngine+OperationFiring.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -756,6 +648,7 @@ "\"$(SDKROOT)/Developer/Library/Frameworks\"", "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", "\"$(SDKROOT)$(DEVELOPER_FRAMEWORKS_DIR)\"", + "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks\"", ); GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; @@ -790,6 +683,7 @@ FRAMEWORK_SEARCH_PATHS = ( "\"$(SDKROOT)/Developer/Library/Frameworks\"", "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", + "\"$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks\"", ); GCC_ENABLE_OBJC_EXCEPTIONS = YES; INFOPLIST_FILE = "IRWebAPIKitTest-Info.plist"; @@ -874,6 +768,9 @@ FF74080F1296A88400571D46 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = c99; GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; @@ -887,6 +784,9 @@ FF7408101296A88400571D46 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; GCC_C_LANGUAGE_STANDARD = c99; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; @@ -904,6 +804,7 @@ COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = IRWebAPIKit; SDKROOT = iphoneos; }; @@ -917,6 +818,7 @@ COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_OPTIMIZATION_LEVEL = 0; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = IRWebAPIKit; SDKROOT = iphoneos; ZERO_LINK = NO; diff --git a/IRWebAPIKitDefines.h b/IRWebAPIKitDefines.h index 0d0d624..a6ad666 100644 --- a/IRWebAPIKitDefines.h +++ b/IRWebAPIKitDefines.h @@ -8,153 +8,16 @@ #import - - - - -#ifndef __IRWebAPIKitDefines__ -#define __IRWebAPIKitDefines__ - -typedef enum { - - IRWebAPIInterfaceCallbackStyleConcatenatedCallback, // if writing framework, use this one - IRWebAPIInterfaceCallbackStyleManyCallbacks // app code and proof of concepts can use this - -} IRWebAPIInterfaceCallbackStyle; - -#endif - - - - - @class IRWebAPIEngine; -@class IRWebAPIContext; +@class IRWebAPIEngineContext; @class IRWebAPIAuthenticator; @class IRWebAPIInterface; - - - - - -#pragma mark Blocks +@class IRWebAPIRequestContext; typedef NSDictionary * (^IRWebAPIResponseParser) (NSData *inData); - -// The parser makes a dictionary from a NSData. - - -typedef NSDictionary * (^IRWebAPIRequestContextTransformer) (NSDictionary *inOriginalContext); - -// The transformer returns a transformed context dictionary. - - -typedef NSDictionary * (^IRWebAPIResponseContextTransformer) (NSDictionary *inParsedResponse, NSDictionary *inResponseContext); - -// The transformer returns a transformed context dictionary, and is given a change to reference the response context. -// The latter is not mutable. - - -typedef BOOL (^IRWebAPIResposeValidator) (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext); - -// The validator returns a BOOL regarding to the parsed and transformed response. - - -typedef void (^IRWebAPICallback) (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry); - -// The callback takes an engine and a response, then optionally tells the engine whether to notify its delegate or retry. -// inResponseContext contains lower-level objects, like NSURLResponse. -// *&outNotifyDelegate defaults to YES -// *&outShouldRetry defaults to NO - - -typedef void (^IRWebAPIAuthenticatorCallback) (IRWebAPIAuthenticator *inAuthenticator, BOOL isAuthenticated, BOOL *inShouldRetry); - -// The authenticator callback takes an authenticator, and its authentication status. -// If necessary, the block works with the authenticator and can tell it to retry authenticating. - - -typedef void (^IRWebAPIInterfaceCallback) (NSDictionary *inResponseOrNil, BOOL *outNotifyDelegate, BOOL *outShouldRetry); - -// The callback takes the response, then optionally tells the interface whether to notify its delegate or retry. - - -typedef void (^IRWebAPIEngineExecutionBlock) (void); - -// Internal. - - - - - -#pragma mark IRWebAPITransformer Context Dictionary Keys - -extern NSString * const kIRWebAPIEngineRequestHTTPBaseURL; - -// Expected to be a NSURL, and well it should be there - - -extern NSString * const kIRWebAPIEngineRequestHTTPHeaderFields; - -// Expected to be a dictionary - - -extern NSString * const kIRWebAPIEngineRequestHTTPPOSTParameters; - -// Expected to be a dictionary, that contains NSString / NSData objects. Everything is in utf-8 or octet. -// If not blank, IRWebAPIEngine makes the HTTP body from the parameters. -// Notice that to use POST parameters, a new transformer block that grabs the correct stuff under this key from the context and adds it to the - - -extern NSString * const kIRWebAPIEngineRequestHTTPBody; - -// Expected to be NSData, or [NSNull null] for custom HTTP body handling. -// If used with IRWebAPIEngineRequestHTTPPOSTParameters, an exception will be thrown. - - -extern NSString * const kIRWebAPIEngineRequestHTTPQueryParameters; - -// Expected to be a dictionary - - -extern NSString * const kIRWebAPIEngineRequestHTTPMethod; - -// Expected to be POST, GET, whatever. Must be POST if IRWebAPIEngineHTTPPOSTParameters is defined. - - -extern NSString * const kIRWebAPIEngineParser; - -// Expected to be a IRWebAPIResponseParser. Exposed to allow custom response parsing for “some methods”. - - -extern NSString * const kIRWebAPIEngineIncomingMethodName; - -// The string that was passed to -fireMethodNamed: - - -extern NSString * const kIRWebAPIRequestTimeout; - -// +[NSNumber numberWithDouble:]. Default is 60. - - - - - - -#pragma mark IRWebAPIEngine Response Context Dictionary Keys - -extern NSString * const kIRWebAPIEngineResponseContextURLResponse; -extern NSString * const kIRWebAPIEngineResponseContextURLResponseName DEPRECATED_ATTRIBUTE; - -// We send a response context to IRWebAPICallback blocks. -// This contains the vanilla NSURLResponse object. - - -extern NSString * const kIRWebAPIEngineResponseContextOriginalRequestContext; -extern NSString * const kIRWebAPIEngineResponseContextOriginalRequestContextName DEPRECATED_ATTRIBUTE; - -// This key gets the original request context. - - - - +typedef IRWebAPIRequestContext * (^IRWebAPIRequestContextTransformer) (IRWebAPIRequestContext *context); +typedef NSDictionary * (^IRWebAPIResponseContextTransformer) (NSDictionary *inParsedResponse, IRWebAPIRequestContext *inResponseContext); +typedef BOOL (^IRWebAPIResponseValidator) (NSDictionary *inResponseOrNil, IRWebAPIRequestContext *inResponseContext); +typedef void (^IRWebAPICallback) (NSDictionary *response, IRWebAPIRequestContext *context); +typedef void (^IRWebAPIAuthenticatorCallback) (IRWebAPIAuthenticator *inAuthenticator, BOOL isAuthenticated); +typedef void (^IRWebAPIInterfaceCallback) (NSDictionary *inResponseOrNil); diff --git a/IRWebAPIKitDefines.m b/IRWebAPIKitDefines.m index aec099d..6eac395 100644 --- a/IRWebAPIKitDefines.m +++ b/IRWebAPIKitDefines.m @@ -7,17 +7,3 @@ // #import "IRWebAPIKitDefines.h" - -NSString * const kIRWebAPIEngineRequestHTTPBaseURL = @"kIRWebAPIEngineRequestHTTPBaseURL"; -NSString * const kIRWebAPIEngineRequestHTTPHeaderFields = @"kIRWebAPIEngineRequestHTTPHeaderFields"; -NSString * const kIRWebAPIEngineRequestHTTPPOSTParameters = @"kIRWebAPIEngineRequestHTTPPOSTParameters"; -NSString * const kIRWebAPIEngineRequestHTTPBody = @"kIRWebAPIEngineRequestHTTPBody"; -NSString * const kIRWebAPIEngineRequestHTTPQueryParameters = @"kIRWebAPIEngineRequestHTTPQueryParameters"; -NSString * const kIRWebAPIEngineRequestHTTPMethod = @"kIRWebAPIEngineRequestHTTPMethod"; -NSString * const kIRWebAPIEngineParser = @"kIRWebAPIEngineParser"; -NSString * const kIRWebAPIEngineIncomingMethodName = @"kIRWebAPIEngineIncomingMethodName"; -NSString * const kIRWebAPIEngineResponseContextURLResponse = @"kIRWebAPIEngineResponseContextURLResponse"; -NSString * const kIRWebAPIEngineResponseContextURLResponseName = @"kIRWebAPIEngineResponseContextURLResponse"; -NSString * const kIRWebAPIEngineResponseContextOriginalRequestContext = @"kIRWebAPIEngineResponseContextOriginalRequestContext"; -NSString * const kIRWebAPIEngineResponseContextOriginalRequestContextName = @"kIRWebAPIEngineResponseContextOriginalRequestContext"; -NSString * const kIRWebAPIRequestTimeout = @"kIRWebAPIRequestTimeout"; diff --git a/IRWebAPIMockJSONPConnection.j b/IRWebAPIMockJSONPConnection.j deleted file mode 100644 index eecc2a6..0000000 --- a/IRWebAPIMockJSONPConnection.j +++ /dev/null @@ -1,115 +0,0 @@ -// IRWebAPIMockJSONPConnection.j -// Evadne Wu at Iridia, 2010 - -@import - -kIRWebAPIMockEndpointGeneralException = @"IRWebAPIMockEndpointGeneralException"; - - - - - -// Notice that we also will probably set a different timeout tolerance for the API engine. -// The timeout here is set for mockup purposes only. - -var kIRJSONPMockConnectionTimeoutDefaultTimeInterval = 15.0, - kIRJSONPMockConnectionTimeoutTimeIntervalInfoDictionaryKey = @"IRJSONPMockConnectionTimeoutDefaultTimeInterval", - kIRJSONPMockConnectionTimeoutDefaultProbability = 0.05, - kIRJSONPMockConnectionTimeoutProbabilityInfoDictionaryKey = @"IRJSONPMockConnectionTimeoutProbability"; - - - - - -@implementation IRJSONPMockConnection : CPJSONPConnection { - - CPMutableDictionary requestHandlers; - - -// Simulated timeout - - CPTimeInterval simulatedTimeoutInterval; - float simulatedTimeoutProbability; - - -// Simulated error - Object simulatedErroneousResponse; - float simulatedErroneousResponseProbability; - -} - - - - - -- (IRWebAPIMockJSONPConnection) initWithRequest:(CPURLRequest)aRequest callback:(CPString)aString delegate:(id)aDelegate startImmediately:(BOOL)shouldStartImmediately { - - if (shouldStartImmediately) - [CPException raise:kIRWebAPIMockEndpointGeneralException reason:[CPString stringWithFormat:@"To use a mocked connection, startImmediately must be set to false because it works with the monkey-patched connection.methodName property."]]; - - self = [super initWithRequest:aRequest callback:aString delegate:aDelegate startImmediately:NO]; - - - var infoDict = [[CPBundle mainBundle] infoDictionary]; - - simulatedTimeoutInterval = [infoDict objectForKey:kIRJSONPMockConnectionTimeoutTimeIntervalInfoDictionaryKey] || kIRJSONPMockConnectionTimeoutDefaultTimeInterval; - - simulatedTimeoutProbability = [infoDict objectForKey:kIRJSONPMockConnectionTimeoutProbabilityInfoDictionaryKey] || kIRJSONPMockConnectionTimeoutDefaultProbability; - - return self; -} - - - - - -- (void) start { - - CPLog(@"self.methodName is %@", self.methodName); - - if ([self shouldSimulateFailure]) { - - CPLog(@"Simulating a connection failure"); - - } else { - - CPLog(@"Simulating a successful connection"); - - } - -} - - - - - -- (void) mockRequestNamed:(CPString)requestName withHandler:(Function)handler { - - if ([requestHandlers objectForKey:requestName] !== nil) - [CPException raise:kIRWebAPIMockEndpointGeneralException reason:[CPString stringWithFormat:@"Mock handler for request named %@ already exists", requestName]]; - - [requestHandlers addObject:handler forKey:requestName]; - -} - - - - - -- (BOOL) shouldSimulateFailure { - - if (Math.random() < simulatedTimeoutProbability) return YES; - - return NO; - -} - - - - - -@end - - - - diff --git a/IRWebAPIModel.j b/IRWebAPIModel.j deleted file mode 100644 index af957cf..0000000 --- a/IRWebAPIModel.j +++ /dev/null @@ -1,87 +0,0 @@ -// IRWebAPIModel.j -// Evadne Wu at Iridia, 2010 - - - - - -@implementation IRWebAPIModel : CPObject { - - BOOL loading; - - id delegate @accessors; - -} - - - - - -+ (IRProtocol) irDelegateProtocol { - - return [IRProtocol protocolWithSelectorsAndOptionalFlags: - - @selector(model:didFinishLoadingWithData:), false, - @selector(model:didFailLoadingWithError:), false, - @selector(model:shouldReloadFromCachedData:), true - - ]; - -} - - - - - -+ (CPString) methodName { - - return nil; - -} - -+ (Function) argumentTransformation { - - return nil; - -} - -+ (Function) responseTransformation { - - return nil; - -} - - - - - -- (IRWebAPIModel) init { - - self = [super init]; if (self == nil) return nil; - - loading = NO; - - return self; - -} - - - - - -- (void) reloadData { - - return; - -} - - - - - - - - - - -@end \ No newline at end of file diff --git a/IRWebAPIOperation.h b/IRWebAPIOperation.h new file mode 100644 index 0000000..5b5ce7d --- /dev/null +++ b/IRWebAPIOperation.h @@ -0,0 +1,13 @@ +// +// IRWebAPIOperation.h +// IRWebAPIKit +// +// Created by Evadne Wu on 6/22/12. +// +// + +#import + +@interface IRWebAPIOperation : NSOperation + +@end diff --git a/IRWebAPIOperation.m b/IRWebAPIOperation.m new file mode 100644 index 0000000..7c2cf59 --- /dev/null +++ b/IRWebAPIOperation.m @@ -0,0 +1,13 @@ +// +// IRWebAPIOperation.m +// IRWebAPIKit +// +// Created by Evadne Wu on 6/22/12. +// +// + +#import "IRWebAPIOperation.h" + +@implementation IRWebAPIOperation + +@end diff --git a/IRWebAPIRequestContext.h b/IRWebAPIRequestContext.h new file mode 100644 index 0000000..480ec50 --- /dev/null +++ b/IRWebAPIRequestContext.h @@ -0,0 +1,38 @@ +// +// IRWebAPIRequestContext.h +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import + +#import "IRWebAPIKitDefines.h" + +@interface IRWebAPIRequestContext : NSObject + +@property (nonatomic, readwrite, copy) NSURL *baseURL; +@property (nonatomic, readwrite, copy) NSString *method; +@property (nonatomic, readwrite, copy) NSString *engineMethod; +@property (nonatomic, readwrite, copy) IRWebAPIResponseParser parser; + +@property (nonatomic, readwrite, copy) NSData *body; +@property (nonatomic, readwrite, assign) NSTimeInterval timeout; + +@property (nonatomic, readonly, copy) NSDictionary *headerFields; +- (void) removeAllHeaderFieldValues; +- (void) setValue:(id)obj forHeaderField:(NSString *)key; + +@property (nonatomic, readonly, copy) NSDictionary *queryParams; +- (void) removeAllQueryParamValues; +- (void) setValue:(id)obj forQueryParam:(NSString *)key; + +@property (nonatomic, readonly, copy) NSDictionary *userInfo; +- (void) removeAllUserInfoValues; +- (void) setValue:(id)obj forUserInfo:(NSString *)key; + +@property (nonatomic, readwrite, strong) NSHTTPURLResponse *urlResponse; +@property (nonatomic, readwrite, strong) NSError *error; + +@end diff --git a/IRWebAPIRequestContext.m b/IRWebAPIRequestContext.m new file mode 100644 index 0000000..27cf5c2 --- /dev/null +++ b/IRWebAPIRequestContext.m @@ -0,0 +1,142 @@ +// +// IRWebAPIRequestContext.m +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIResponseParser.h" + +static NSString * const kHeaderFields = @"headerFields"; +static NSString * const kQueryParams = @"queryParams"; +static NSString * const kUserInfo = @"userInfo"; + +@implementation IRWebAPIRequestContext { +@package + NSMutableDictionary *_headerFields; + NSMutableDictionary *_queryParams; + NSMutableDictionary *_userInfo; +} + +@synthesize baseURL = _baseURL; +@synthesize method = _method; +@synthesize engineMethod = _engineMethod; +@synthesize parser = _parser; +@synthesize body = _body; +@synthesize timeout = _timeout; +@synthesize urlResponse = _urlResponse; +@synthesize error = _error; + +- (id) init { + + self = [super init]; + if (!self) + return nil; + + _method = @"GET"; + + _timeout = 60.0f; + + _headerFields = [NSMutableDictionary dictionary]; + _queryParams = [NSMutableDictionary dictionary]; + _userInfo = [NSMutableDictionary dictionary]; + + _parser = [IRWebAPIResponseDefaultJSONParserMake() copy]; + + return self; + +} + +- (void) setBody:(NSData *)body { + + _body = body; + +} + +- (NSDictionary *) headerFields { + + return [_headerFields copy]; + +} + +- (void) removeAllHeaderFieldValues { + + [self willChangeValueForKey:kHeaderFields]; + [_headerFields removeAllObjects]; + [self didChangeValueForKey:kHeaderFields]; + +} + +- (void) setValue:(id)obj forHeaderField:(NSString *)key { + + [self willChangeValueForKey:kHeaderFields]; + + if (obj) { + [_headerFields setObject:obj forKey:key]; + } else { + [_headerFields removeObjectForKey:key]; + } + + [self didChangeValueForKey:kHeaderFields]; + +} + +- (NSDictionary *) queryParams { + + return [_queryParams copy]; + +} + +- (void) removeAllQueryParamValues { + + [self willChangeValueForKey:kQueryParams]; + [_queryParams removeAllObjects]; + [self didChangeValueForKey:kQueryParams]; + +} + +- (void) setValue:(id)obj forQueryParam:(NSString *)key { + + [self willChangeValueForKey:kQueryParams]; + + if (obj) { + [_queryParams setObject:obj forKey:key]; + } else { + [_queryParams removeObjectForKey:key]; + } + + [self didChangeValueForKey:kQueryParams]; + +} + +- (NSDictionary *) userInfo { + + return [_userInfo copy]; + +} + +- (void) removeAllUserInfoValues { + + [self willChangeValueForKey:kUserInfo]; + [_userInfo removeAllObjects]; + [self didChangeValueForKey:kUserInfo]; + +} + +- (void) setValue:(id)obj forUserInfo:(NSString *)key { + + [self willChangeValueForKey:kUserInfo]; + + if (obj) { + [_userInfo setObject:obj forKey:key]; + } else { + [_userInfo removeObjectForKey:key]; + } + + [self didChangeValueForKey:kUserInfo]; + +} + +@end diff --git a/IRWebAPIRequestOperation.h b/IRWebAPIRequestOperation.h new file mode 100644 index 0000000..d81411d --- /dev/null +++ b/IRWebAPIRequestOperation.h @@ -0,0 +1,32 @@ +// +// IRWebAPIRequestOperation.h +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import + +enum { + + IRWebAPIRequestStateEnqueued = 0, + IRWebAPIRequestStateRunning, + IRWebAPIRequestStateSucceeded, + IRWebAPIRequestStateFailed + +}; typedef NSUInteger IRWebAPIRequestState; + + +@class IRWebAPIRequestContext; +@interface IRWebAPIRequestOperation : NSOperation + +- (id) initWithContext:(IRWebAPIRequestContext *)context; + +@property (nonatomic, readonly, strong) IRWebAPIRequestContext *context; +@property (nonatomic, readonly, assign) IRWebAPIRequestState state; +@property (nonatomic, readonly, strong) NSURLRequest *request; +@property (nonatomic, readonly, strong) NSURLConnection *connection; +@property (nonatomic, readonly, strong) id result; + +@end diff --git a/IRWebAPIRequestOperation.m b/IRWebAPIRequestOperation.m new file mode 100644 index 0000000..b700659 --- /dev/null +++ b/IRWebAPIRequestOperation.m @@ -0,0 +1,197 @@ +// +// IRWebAPIRequestOperation.m +// IRWebAPIKit +// +// Created by Evadne Wu on 6/25/12. +// +// + +#import "IRWebAPIRequestOperation.h" +#import "IRWebAPIRequestContext.h" +#import "IRWebAPIInterceptor.h" +#import "IRWebAPIHelpers.h" + +@interface IRWebAPIRequestOperation () { + BOOL _isExecuting; + BOOL _isFinished; +} +@property (nonatomic, readwrite, assign) IRWebAPIRequestState state; +@property (nonatomic, readwrite, strong) NSURLConnection *connection; +@property (nonatomic, readonly, strong) NSMutableData *data; +@property (nonatomic, readonly, strong) IRWebAPIInterceptor *interceptor; +@end + + +@implementation IRWebAPIRequestOperation +@synthesize context = _context; +@synthesize request = _request; +@synthesize connection = _connection; +@synthesize state = _state; +@synthesize result = _result; +@synthesize data = _data; +@synthesize interceptor = _interceptor; + +- (id) initWithContext:(IRWebAPIRequestContext *)context { + + self = [super init]; + if (!self) + return nil; + + _context = context; + + _isExecuting = NO; + _isFinished = NO; + + _state = IRWebAPIRequestStateEnqueued; + + return self; + +} + +- (void) start { + + if (![NSThread isMainThread]) { + [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO]; + return; + } + + [self willChangeValueForKey:@"isExecuting"]; + _isExecuting = YES; + [self didChangeValueForKey:@"isExecuting"]; + + _data = [NSMutableData data]; + + _interceptor = [IRWebAPIInterceptor new]; + _interceptor.receiver = self; + + self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:(id)_interceptor]; + self.state = IRWebAPIRequestStateRunning; + + if (!_connection) { + self.state = IRWebAPIRequestStateFailed; + [self finish]; + } + +} + +- (void) cancel { + + [_connection cancel]; + _interceptor.receiver = nil; + + [super cancel]; + + self.state = IRWebAPIRequestStateFailed; + +} + +- (void) finish { + + _connection = nil; + + if (self.data) + _result = self.context.parser(self.data); + + [self willChangeValueForKey:@"isExecuting"]; + [self willChangeValueForKey:@"isFinished"]; + + _isExecuting = NO; + _isFinished = YES; + + [self didChangeValueForKey:@"isExecuting"]; + [self didChangeValueForKey:@"isFinished"]; + +} + +- (BOOL) isExecuting { + + return _isExecuting; + +} + +- (BOOL) isFinished { + + return _isFinished; + +} + +- (NSURLRequest *) request { + + if (!_request) { + + NSURL *url = IRWebAPIRequestURLWithQueryParameters(self.context.baseURL, self.context.queryParams); + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:self.context.timeout]; + + [self.context.headerFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [request setValue:obj forHTTPHeaderField:key]; + }]; + + if (self.context.body) + [request setHTTPBody:self.context.body]; + + [request setHTTPMethod:self.context.method]; + [request setHTTPShouldHandleCookies:NO]; + + _request = request; + + } + + return _request; + +} + +- (void) connection:(NSURLConnection *)inConnection didReceiveData:(NSData *)inData { + + [self.data appendData:inData]; + +} + +- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { + + NSCParameterAssert([response isKindOfClass:[NSHTTPURLResponse class]]); + self.context.urlResponse = (NSHTTPURLResponse *)response; + + [self.data setLength:0]; + +} + +- (void) connectionDidFinishLoading:(NSURLConnection *)inConnection { + + self.state = IRWebAPIRequestStateSucceeded; + + [self finish]; + +} + +- (void) connection:(NSURLConnection *)inConnection didFailWithError:(NSError *)error { + + self.context.error = error; + self.state = IRWebAPIRequestStateFailed; + + [self finish]; + +} + +- (BOOL) connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { + + return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; + +} + +- (void) connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { + + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) + if ([[self.context.baseURL host] isEqualToString:challenge.protectionSpace.host]) + [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; + + [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; + +} + +- (NSString *) description { + + return [NSString stringWithFormat:@"<%@: %p { %@ %@ %@ }>", NSStringFromClass([self class]), self, self.context.engineMethod, self.context.method, self.context.baseURL]; + +} + +@end diff --git a/IRWebAPIResponseParser.m b/IRWebAPIResponseParser.m index 7145f85..6f4f7dc 100644 --- a/IRWebAPIResponseParser.m +++ b/IRWebAPIResponseParser.m @@ -7,8 +7,21 @@ // #import "IRWebAPIResponseParser.h" +#import "JSONKit.h" +NSDictionary * IRWebAPIResponseDictionarize (id incomingObject); +NSDictionary * IRWebAPIResponseDictionarize (id incomingObject) { + + if (!incomingObject) + return (id)nil; + + if (![incomingObject isKindOfClass:[NSDictionary class]]) + return [NSDictionary dictionaryWithObject:incomingObject forKey:@"response"]; + + return (id)incomingObject; + +} @@ -21,13 +34,13 @@ IRWebAPIResponseParser IRWebAPIResponseDefaultParserMake () { return [NSDictionary dictionaryWithObjectsAndKeys: inData, @"response", - [[[NSString alloc] initWithData:inData encoding:NSUTF8StringEncoding] autorelease], @"responseText", + [[NSString alloc] initWithData:inData encoding:NSUTF8StringEncoding], @"responseText", nil]; }; - return [[defaultParser copy] autorelease]; + return [defaultParser copy]; } @@ -37,205 +50,74 @@ IRWebAPIResponseParser IRWebAPIResponseDefaultParserMake () { IRWebAPIResponseParser IRWebAPIResponseQueryResponseParserMake () { -// Parses UTF8 String Data Like: -// -// Key=URL_Encoded_Value -// Another_Key=Another_Encoded_Value - - NSDictionary * (^queryResponseParser) (NSData *) = ^ NSDictionary * (NSData *inData) { - - NSString *responseString = [[[NSString alloc] initWithData:inData encoding:NSUTF8StringEncoding] autorelease]; - - NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"([^=&\n\r]+)=([^=&\n\r]+)[\n\r&]?" options:NSRegularExpressionCaseInsensitive error:nil]; - - NSMutableDictionary *returnedResponse = [NSMutableDictionary dictionary]; + // Parses UTF8 String Data Like: + // + // Key=URL_Encoded_Value + // Another_Key=Another_Encoded_Value + + static IRWebAPIResponseParser parserBlock = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ - @try { + parserBlock = [^ NSDictionary * (NSData *inData) { - [expression enumerateMatchesInString:responseString options:0 range:NSMakeRange(0, [responseString length]) usingBlock: ^ (NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { + NSString *responseString = [[NSString alloc] initWithData:inData encoding:NSUTF8StringEncoding]; - [returnedResponse setObject:[responseString substringWithRange:[result rangeAtIndex:2]] forKey:[responseString substringWithRange:[result rangeAtIndex:1]]]; + NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:@"([^=&\n\r]+)=([^=&\n\r]+)[\n\r&]?" options:NSRegularExpressionCaseInsensitive error:nil]; - }]; - - } @catch (NSException * e) { + NSMutableDictionary *returnedResponse = [NSMutableDictionary dictionary]; - NSLog(@"IRWebAPIResponseQueryResponseParser encountered an exception while parsing response. Returning empty dictionary."); + @try { - return [NSDictionary dictionary]; + [expression enumerateMatchesInString:responseString options:0 range:NSMakeRange(0, [responseString length]) usingBlock: ^ (NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { + + [returnedResponse setObject:[responseString substringWithRange:[result rangeAtIndex:2]] forKey:[responseString substringWithRange:[result rangeAtIndex:1]]]; + + }]; - } + } @catch (NSException * e) { + + NSLog(@"IRWebAPIResponseQueryResponseParser encountered an exception while parsing response. Returning empty dictionary."); + + return [NSDictionary dictionary]; + + } - return returnedResponse; - - }; + return returnedResponse; + + } copy]; + + }); - return [[queryResponseParser copy] autorelease]; + return parserBlock; } - - - IRWebAPIResponseParser IRWebAPIResponseDefaultJSONParserMake () { - static id parserInstance = nil; static IRWebAPIResponseParser parserBlock = nil; + static dispatch_once_t onceToken; - if (parserBlock) - return parserBlock; - - NSDictionary * (^dictionarize)(id) = ^ (id incomingObject) { - - if (!incomingObject) - return (id)nil; - - if (![incomingObject isKindOfClass:[NSDictionary class]]) - return [NSDictionary dictionaryWithObject:incomingObject forKey:@"response"]; - - return (id)incomingObject; - - }; - - Class classJSONKit = NSClassFromString(@"JSONDecoder"); - if (classJSONKit) { - - parserInstance = [classJSONKit performSelector:@selector(decoder)]; - [parserInstance retain]; - - parserBlock = (IRWebAPIResponseParser)[[^ (NSData *incomingData) { - return dictionarize([parserInstance performSelector:@selector(objectWithData:) withObject:incomingData]); - } copy] autorelease]; + dispatch_once(&onceToken, ^{ - return parserBlock; + parserBlock = [^ (NSData *incomingData) { - } - - Class classTouchJSON = NSClassFromString(@"CJSONDeserializer"); - if (classTouchJSON) { - - parserInstance = [classTouchJSON performSelector:@selector(deserializer)]; - [parserInstance retain]; - - parserBlock = (IRWebAPIResponseParser)[[^ (NSData *incomingData) { - - SEL selDeserialize = @selector(deserialize:error:); - id incomingObject; - - NSError *error = nil; - NSError **errorPointer = &error; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[parserInstance methodSignatureForSelector:selDeserialize]]; - - [invocation setTarget:parserInstance]; - [invocation setSelector:selDeserialize]; - [invocation setArgument:&incomingData atIndex:2]; - [invocation setArgument:&errorPointer atIndex:3]; - [invocation invoke]; - [invocation getReturnValue:&incomingObject]; - - return dictionarize(incomingObject); - - } copy] autorelease]; - - return parserBlock; - - } - - return IRWebAPIResponseDefaultParserMake(); - -} - -IRWebAPIResponseParser IRWebAPIResponseDefaultXMLParserMake () { + NSError *error = nil; + // sometimes the response from cloud contains invalid utf-8 characters, + // so we deserialize it with loosely restriction + id results = [incomingData objectFromJSONDataWithParseOptions:JKParseOptionLooseUnicode error:&error]; - static IRWebAPIResponseParser parserBlock = nil; - - if (parserBlock) - return parserBlock; - - // __block NSDictionary * (^dictionarize)(id); - // dictionarize = [[^ (id incomingObject) { - // - // if (!incomingObject) - // return (NSDictionary *)nil; - // - // NSArray *children = [incomingObject performSelector:@selector(children)]; - // NSArray *attributes = [incomingObject respondsToSelector:@selector(attributes)] ? [incomingObject performSelector:@selector(attributes)] : nil; - // - // NSMutableDictionary *returnedDictionary = [NSMutableDictionary dictionary]; - // - // [returnedDictionary setObject:[incomingObject performSelector:@selector(name)] forKey:@"name"]; - // - // if ([children count]) { - // - // NSMutableArray *childrenDictionaries = [NSMutableArray array]; - // - // for (id element in children) - // [childrenDictionaries addObject:dictionarize(element)]; - // - // [returnedDictionary setObject:childrenDictionaries forKey:@"children"]; - // - // } - // - // if ([attributes count]) { - // - // NSMutableArray *attributesDictionaries = [NSMutableArray array]; - // - // for (id element in attributes) - // [attributesDictionaries addObject:dictionarize(element)]; - // - // [returnedDictionary setObject:attributesDictionaries forKey:@"attributes"]; - // - // } - // - // [returnedDictionary setObject:[incomingObject performSelector:@selector(stringValue)] forKey:@"value"]; - // - // return returnedDictionary; - // - // } copy] autorelease]; - // - // [dictionarize retain]; - - Class classTouchXMLDocument = NSClassFromString(@"CXMLDocument"); - if (classTouchXMLDocument) { - - parserBlock = (IRWebAPIResponseParser)[[^ (NSData *incomingData) { - - SEL selInstantiate = @selector(initWithData:encoding:options:error:); - id incomingObject = nil; + if (error && [incomingData length] != 0) { + NSLog(@"Unable to parse JSON response, error:%@", error); + } - NSError *error = nil; - NSError **errorPointer = &error; + return IRWebAPIResponseDictionarize(results); - id parserInstance = [classTouchXMLDocument performSelector:@selector(alloc)]; - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[parserInstance methodSignatureForSelector:selInstantiate]]; - - NSStringEncoding stringEncoding = NSUTF8StringEncoding; - NSUInteger options = 0; - - [invocation setTarget:parserInstance]; - [invocation setSelector:selInstantiate]; - [invocation setArgument:&incomingData atIndex:2]; - [invocation setArgument:&stringEncoding atIndex:3]; - [invocation setArgument:&options atIndex:4]; - [invocation setArgument:&errorPointer atIndex:5]; - [invocation invoke]; - [invocation getReturnValue:&incomingObject]; - - return [NSDictionary dictionaryWithObjectsAndKeys: - - incomingObject, @"object", - incomingData, @"data", - // dictionarize([incomingObject performSelector:@selector(rootElement)]), @"interpretation", + } copy]; - nil]; + }); - } copy] autorelease]; - - return parserBlock; - - } + return parserBlock; - return IRWebAPIResponseDefaultParserMake(); - } diff --git a/IRWebAPITwitPicInterface.h b/IRWebAPITwitPicInterface.h deleted file mode 100644 index c7f163a..0000000 --- a/IRWebAPITwitPicInterface.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// IRWebAPITwitPicInterface.h -// IRWebAPIKit -// -// Created by Evadne Wu on 1/24/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIKit.h" - - -@interface IRWebAPITwitPicInterface : IRWebAPIInterface - -@property (nonatomic, readwrite, retain) NSString *apiKey; - -@end diff --git a/IRWebAPITwitPicInterface.m b/IRWebAPITwitPicInterface.m deleted file mode 100644 index 579e958..0000000 --- a/IRWebAPITwitPicInterface.m +++ /dev/null @@ -1,154 +0,0 @@ -// -// IRWebAPITwitPicInterface.m -// IRWebAPIKit -// -// Created by Evadne Wu on 1/24/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitPicInterface.h" - -#import -#import -#import - - -@interface IRWebAPITwitPicInterface () - -- (void) uploadCachedImageAtURL:(NSURL *)inCachedImageURL onProgress:(void(^)(float inProgressRatio))inProgressCallback onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback; - -// The reason why we pile other methods here is because we want a method that cleans up after itself, so we use a cached URL. The cached image is deleted once the method call returns. - -@end - -@implementation IRWebAPITwitPicInterface - -@synthesize apiKey, authenticatingInterface; - -- (id) init { - - IRWebAPIContext *twitPicContext = [[[IRWebAPIContext alloc] initWithBaseURL:[NSURL URLWithString:@"http://api.twitpic.com/"]] autorelease]; - IRWebAPIEngine *twitPicEngine = [[[IRWebAPIEngine alloc] initWithContext:twitPicContext] autorelease]; - - twitPicEngine.parser = IRWebAPIResponseDefaultJSONParserMake(); - - self = [self initWithEngine:twitPicEngine authenticator:nil]; - - [twitPicEngine.globalRequestPreTransformers addObject:[[twitPicEngine class] defaultFormMultipartTransformer]]; - [twitPicEngine.globalResponsePostTransformers addObject:[[twitPicEngine class] defaultCleanUpTemporaryFilesResponseTransformer]]; - - if (!self) return nil; - - return self; - -} - -- (void) uploadImage:(UIImage *)inImage onProgress:(void(^)(float inProgressRatio))inProgressCallback onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSData *imageDataOrNil = UIImagePNGRepresentation(inImage); - - if (!imageDataOrNil) { - - IRWebAPIKitLog(@"The incoming image can’t be turned to a PNG representation — it might be corrupted or garbled"); - - if (inFailureCallback) - inFailureCallback(nil, NO, NO); - - return; - - } - - NSURL *cachingFileURL = [[[self.engine class] newTemporaryFileURL] autorelease]; - - [imageDataOrNil writeToURL:cachingFileURL atomically:YES]; - - [self uploadCachedImageAtURL:cachingFileURL onProgress:inProgressCallback onSuccess:inSuccessCallback onFailure:inFailureCallback]; - -} - -- (void) uploadImageAtURL:(NSURL *)inImageURL onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSURL *cachingFileURL = [[[self.engine class] newTemporaryFileURL] autorelease]; - - NSError *error = nil; - - if (![[NSFileManager defaultManager] copyItemAtURL:inImageURL toURL:cachingFileURL error:&error]) { - - IRWebAPIKitLog(@"Can’t copy item at %@ to %@ — aborting, calling failure handler.", inImageURL, cachingFileURL); - - if (inFailureCallback) - inFailureCallback(nil, NO, NO); - - return; - - } - - [self uploadCachedImageAtURL:cachingFileURL onProgress:nil onSuccess:inSuccessCallback onFailure:inFailureCallback]; - -} - -- (void) uploadCachedImageAtURL:(NSURL *)inCachedImageURL onProgress:(void(^)(float inProgressRatio))inProgressCallback onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback { - - - NSAssert(self.apiKey, @"%@ needs an API key.", self); - NSAssert(self.authenticatingInterface, @"%@ needs an authenticating interface so oAuth Echo works.", self); - NSAssert([self.authenticatingInterface.authenticator isKindOfClass:[IRWebAPIXOAuthAuthenticator class]], @"Authenticator needs to be of class %@.", NSStringFromClass([IRWebAPIXOAuthAuthenticator class])); - NSAssert(self.authenticatingInterface.authenticator.currentCredentials.authenticated, @"%@ needs an authenticating interface with already authenticated credentials to work correctly.", self); - - -// Abstraction leaks at this line - NSURL *xoAuthEchoBaseURL = [NSURL URLWithString:@"1/account/verify_credentials.json" relativeToURL:self.authenticatingInterface.engine.context.baseURL]; - - [self.engine fireAPIRequestNamed:@"/2/upload.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - self.apiKey, @"key", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSMutableDictionary dictionaryWithObjectsAndKeys: - - self.apiKey, @"key", - inCachedImageURL, @"media", - @"", @"message", - - nil], kIRWebAPIEngineRequestContextFormMultipartFieldsKey, - - [NSMutableDictionary dictionaryWithObjectsAndKeys: - - [((IRWebAPIXOAuthAuthenticator *)self.authenticatingInterface.authenticator) oAuthHeaderValueForHTTPMethod:@"GET" baseURL:xoAuthEchoBaseURL arguments:nil], @"X-Verify-Credentials-Authorization", - - [xoAuthEchoBaseURL absoluteString], @"X-Auth-Service-Provider", - - nil], kIRWebAPIEngineRequestHTTPHeaderFields, - - nil] validator: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - NSHTTPURLResponse *response = (NSHTTPURLResponse *)[inResponseContext objectForKey:kIRWebAPIEngineResponseContextURLResponse]; - - if ([inResponseOrNil objectForKey:@"url"] == nil) { - - NSLog(@"Warning: No valid response (%x %@).", [response statusCode], [[response class] localizedStringForStatusCode:[response statusCode]]); - - return NO; - - } - - return YES; - - } successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - *outShouldRetry = YES; - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -@end diff --git a/IRWebAPITwitterInterface+DirectMessages.h b/IRWebAPITwitterInterface+DirectMessages.h deleted file mode 100644 index d4cc093..0000000 --- a/IRWebAPITwitterInterface+DirectMessages.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// IRWebAPITwitterInterface+DirectMessages.h -// IRWebAPIKit -// -// Created by Evadne Wu on 1/18/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - - - - - -@interface IRWebAPITwitterInterface (DirectMessages) - -- (void) retrieveIncomingDirectMessagesWithRange:(IRWebAPITwitterDirectMessageIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveOutgoingDirectMessagesWithRange:(IRWebAPITwitterDirectMessageIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) sendDirectMessageToUser:(IRWebAPITwitterUserID)inUserID withContents:(NSString *)inContents successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) deleteDirectMessageWithID:(IRWebAPITwitterDirectMessageID)inMessageID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -@end diff --git a/IRWebAPITwitterInterface+DirectMessages.m b/IRWebAPITwitterInterface+DirectMessages.m deleted file mode 100644 index e8d8d0b..0000000 --- a/IRWebAPITwitterInterface+DirectMessages.m +++ /dev/null @@ -1,123 +0,0 @@ -// -// IRWebAPITwitterInterface+DirectMessages.m -// IRWebAPIKit -// -// Created by Evadne Wu on 1/18/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+DirectMessages.h" - - -@implementation IRWebAPITwitterInterface (DirectMessages) - -- (void) retrieveIncomingDirectMessagesWithRange:(IRWebAPITwitterDirectMessageIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/direct_messages.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:self.defaultBatchSize], @"count", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveOutgoingDirectMessagesWithRange:(IRWebAPITwitterDirectMessageIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/direct_messages/sent.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:self.defaultBatchSize], @"count", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) sendDirectMessageToUser:(IRWebAPITwitterUserID)inUserID withContents:(NSString *)inContents successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/direct_messages/new.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithUnsignedLongLong:inUserID], @"user_id", - inContents, @"text", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) deleteDirectMessageWithID:(IRWebAPITwitterDirectMessageID)inMessageID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/direct_messages/destroy/%llu.json", inMessageID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithUnsignedLongLong:inMessageID], @"id", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -@end diff --git a/IRWebAPITwitterInterface+Friendships.h b/IRWebAPITwitterInterface+Friendships.h deleted file mode 100644 index d5b5eb6..0000000 --- a/IRWebAPITwitterInterface+Friendships.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// IRWebAPITwitterInterface+Friendships.h -// IRWebAPIKit -// -// Created by Evadne Wu on 4/3/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - -@interface IRWebAPITwitterInterface (Friendships) - -// Actually unsure whether concatenated invocation (big, single-shot) or repeated invocation works better -// So, wrote both to try them out separately - -// Note that the response is seldom written to a file in real world cases; instead it is mostly used to work other backing stores -// I believe that many callbacks + a exhaustion check might (read: can, but possibly as in quadruple-alpha) work a lot more better in this case for most use cases - -+ (BOOL) repeatedlyCalledSuccessHandlerResponseExhausted:(NSDictionary *)response; - -// returns YES if the engine agrees that the success handler is not going to be called any more in the same context - - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withConcatenatedSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -// Stitches everything in memory and return a large chunk - - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withRepeatedlyCalledSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -// Thought of integrating response, and found that way is not sustainable on mobile devices, and generally just bad -// A nil-response success callback is fired again when things are really done - - - - - -// Primitives - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withCallbackStyle:(IRWebAPIInterfaceCallbackStyle)style successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withCursor:(unsigned long long)cursorID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; // the primitive one - -@end diff --git a/IRWebAPITwitterInterface+Friendships.m b/IRWebAPITwitterInterface+Friendships.m deleted file mode 100644 index 4caf471..0000000 --- a/IRWebAPITwitterInterface+Friendships.m +++ /dev/null @@ -1,144 +0,0 @@ -// -// IRWebAPITwitterInterface+Friendships.m -// IRWebAPIKit -// -// Created by Evadne Wu on 4/3/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+Friendships.h" - - -@implementation IRWebAPITwitterInterface (Friendships) - -+ (BOOL) repeatedlyCalledSuccessHandlerResponseExhausted:(NSDictionary *)response { - - if (!response || ![[response objectForKey:@"ids"] count]) - return YES; - - if ([[response objectForKey:@"next_cursor"] isEqual:[response objectForKey:@"previous_cursor"]]) - return YES; - - return NO; - -} - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withConcatenatedSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self retrieveFriendsOfUser:userID withCallbackStyle:IRWebAPIInterfaceCallbackStyleConcatenatedCallback successHandler:inSuccessCallback failureHandler:inFailureCallback]; - -} - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withRepeatedlyCalledSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self retrieveFriendsOfUser:userID withCallbackStyle:IRWebAPIInterfaceCallbackStyleManyCallbacks successHandler:inSuccessCallback failureHandler:inFailureCallback]; - -} - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withCallbackStyle:(IRWebAPIInterfaceCallbackStyle)style successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSMutableDictionary *actualResponseOrNil = [NSMutableDictionary dictionary]; // Get everything - - void (^enqueueIdentifiersFromResponse)(NSDictionary *response) = ^ (NSDictionary *response) { - - NSMutableArray *actualIDs = [actualResponseOrNil objectForKey:@"ids"]; - - if (![actualIDs isKindOfClass:[NSMutableArray class]]) { - - actualIDs = [[actualIDs mutableCopy] autorelease]; - [actualResponseOrNil setObject:actualIDs forKey:@"ids"]; - - } - - [actualIDs addObjectsFromArray:[response objectForKey:@"ids"]]; - - }; - - BOOL (^responseExhausted)(NSDictionary *responseBody) = ^ (NSDictionary *responseBody) { return [[self class] repeatedlyCalledSuccessHandlerResponseExhausted:responseBody]; }; - - __block void (^workingBlock)(unsigned long long queuedCursorID); - - workingBlock = ^ (unsigned long long queuedCursorID) { - - [self retrieveFriendsOfUser:userID withCursor:queuedCursorID successHandler: ^ (NSDictionary *inResponseOrNil, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - switch (style) { - - case IRWebAPIInterfaceCallbackStyleConcatenatedCallback: { - - enqueueIdentifiersFromResponse(inResponseOrNil); - - if (responseExhausted(inResponseOrNil)) { - - if (inSuccessCallback) - inSuccessCallback(actualResponseOrNil, outNotifyDelegate, outShouldRetry); - - return; - - } - - break; - - } - - case IRWebAPIInterfaceCallbackStyleManyCallbacks : { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - if (responseExhausted(inResponseOrNil)) { - - return; - - } - - break; - - } - - default: { - - NSParameterAssert(NO); - - } - - } - - workingBlock([[inResponseOrNil objectForKey:@"next_cursor"] unsignedLongLongValue]); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"FAIL %@", inResponseOrNil); - - }]; - - }; - - workingBlock(-1); // -1 starts pagination, and the cursor defaults to -1 per official docs - -} - -- (void) retrieveFriendsOfUser:(IRWebAPITwitterUserID)userID withCursor:(unsigned long long)cursorID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/friends/ids.json"] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:cursorID]), @"cursor", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:userID]), @"user_id", - - nil] options:nil validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -@end diff --git a/IRWebAPITwitterInterface+Geo.h b/IRWebAPITwitterInterface+Geo.h deleted file mode 100644 index b8be769..0000000 --- a/IRWebAPITwitterInterface+Geo.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// IRWebAPITwitterInterface+Geo.h -// IRWebAPIKit -// -// Created by Evadne Wu on 12/15/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" -#import - -@interface IRWebAPITwitterInterface (Geo) - -- (void) reverseGeocodeWithLocation:(CLLocation *)inLocation userinfo:(NSDictionary *)inUserInfo onSuccess:(IRWebAPICallback)inSuccessCallback onFailure:(IRWebAPICallback)inFailureCallback; - -@end diff --git a/IRWebAPITwitterInterface+Geo.m b/IRWebAPITwitterInterface+Geo.m deleted file mode 100644 index 79bab0c..0000000 --- a/IRWebAPITwitterInterface+Geo.m +++ /dev/null @@ -1,72 +0,0 @@ -// -// IRWebAPITwitterInterface+Geo.m -// IRWebAPIKit -// -// Created by Evadne Wu on 12/15/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+Geo.h" - - - - - -@implementation IRWebAPITwitterInterface (Geo) - - - - - -- (void) reverseGeocodeWithLocation:(CLLocation *)inLocation userinfo:(NSDictionary *)inUserInfo onSuccess:(IRWebAPICallback)inSuccessCallback onFailure:(IRWebAPICallback)inFailureCallback { - - IRWebAPIContext *googleMapsContext = [[[IRWebAPIContext alloc] initWithBaseURL:[NSURL URLWithString:@"http://maps.googleapis.com/maps/api/"]] autorelease]; - IRWebAPIEngine *googleMapsEngine = [[[IRWebAPIEngine alloc] initWithContext:googleMapsContext] autorelease]; - googleMapsEngine.parser = IRWebAPIResponseDefaultJSONParserMake(); - - [googleMapsEngine fireAPIRequestNamed:@"geocode/json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSString stringWithFormat:@"%f,%f", inLocation.coordinate.latitude, inLocation.coordinate.longitude], @"latlng", - @"true", @"sensor", - - nil] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"google success"); - - if (![[inResponseOrNil valueForKey:@"status"] isEqual:@"OK"]) { - - inFailureCallback(inResponseOrNil, inResponseContext, outNotifyDelegate, outShouldRetry); - return; - - } - - NSDictionary *resultArray = [inResponseOrNil valueForKey:@"results"]; - for (NSDictionary *resultObject in resultArray) { - - NSString *formattedAddress = [resultObject valueForKeyPath:@"formatted_address"]; - - if ([formattedAddress isEqual:[NSNull null]]) - continue; - - inSuccessCallback([NSDictionary dictionaryWithObject:formattedAddress forKey:@"displayString"], inResponseContext, outNotifyDelegate, outShouldRetry); - return; - - } - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - inFailureCallback(inResponseOrNil, inResponseContext, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -@end - - - - diff --git a/IRWebAPITwitterInterface+Lists.h b/IRWebAPITwitterInterface+Lists.h deleted file mode 100644 index 883f2af..0000000 --- a/IRWebAPITwitterInterface+Lists.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// IRWebAPITwitterInterface+Lists.h -// IRWebAPIKit -// -// Created by Evadne Wu on 1/17/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - - - - - -#ifndef __IRWebAPIInterface__Lists__ -#define __IRWebAPIInterface__Lists__ - -typedef enum { - - IRWebAPITwitterListsMadeByUser, - IRWebAPITwitterListsIncludingUser, - IRWebAPITwitterListsSubscribedByUser - -} IRWebAPITwitterListsType; - -#endif - - - - - -@interface IRWebAPITwitterInterface (Lists) - -- (void) retrieveListsOfType:(IRWebAPITwitterListsType)inListType successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveStatusesFromList:(IRWebAPITwitterListID)inListID withRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -// - (void) createOrUpdateList:(IRWebAPITwitterListID)inListID withName:(NSString *)inPromisedListName becomingPrivate:(BOOL)inListBecomesPrivate successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) createListWithName:(NSString *)inName description:(NSString *)inDescription becomingPrivate:(BOOL)inListBecomesPrivate successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) updateList:(IRWebAPITwitterListID)inListID withName:(NSString *)inName description:(NSString *)inDescription becomingPrivate:(BOOL)inListBecomesPrivate successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) deleteList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - - -- (void) retrieveMembersOfList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) removeMember:(IRWebAPITwitterUserID)inUserID fromList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) addMember:(IRWebAPITwitterUserID)inUserID toList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -@end diff --git a/IRWebAPITwitterInterface+Lists.m b/IRWebAPITwitterInterface+Lists.m deleted file mode 100644 index d20aaaa..0000000 --- a/IRWebAPITwitterInterface+Lists.m +++ /dev/null @@ -1,251 +0,0 @@ -// -// IRWebAPITwitterInterface+Lists.m -// IRWebAPIKit -// -// Created by Evadne Wu on 1/17/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+Lists.h" - - -@implementation IRWebAPITwitterInterface (Lists) - -- (void) retrieveListsOfType:(IRWebAPITwitterListsType)inListType successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/lists%@.json", self.authenticator.currentCredentials.identifier, ((^{ - - switch (inListType) { - case IRWebAPITwitterListsMadeByUser: return @""; - case IRWebAPITwitterListsIncludingUser: return @"/memberships"; - case IRWebAPITwitterListsSubscribedByUser: return @"/subscriptions"; - } - - })())] withArguments:nil options:nil validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveStatusesFromList:(IRWebAPITwitterListID)inListID withRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/lists/%llu/statuses.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:self.defaultBatchSize], @"count", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) createListWithName:(NSString *)inName description:(NSString *)inDescription becomingPrivate:(BOOL)inListBecomesPrivate successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/lists/.json", self.authenticator.currentCredentials.identifier] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - inName, @"name", - (inListBecomesPrivate ? @"private" : @"public"), @"mode", - inDescription, @"description", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) updateList:(IRWebAPITwitterListID)inListID withName:(NSString *)inName description:(NSString *)inDescription becomingPrivate:(BOOL)inListBecomesPrivate successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/lists/%llu.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - inName, @"name", - (inListBecomesPrivate ? @"private" : @"public"), @"mode", - inDescription, @"description", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) deleteList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/lists/%llu.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - @"DELETE", @"_method", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveMembersOfList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/%llu/members.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSString stringWithFormat:@"%llu", inListID], @"id", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) removeMember:(IRWebAPITwitterUserID)inUserID fromList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/%llu/members.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - @"DELETE", @"_method", - [NSString stringWithFormat:@"%llu", inUserID], @"id", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) addMember:(IRWebAPITwitterUserID)inUserID toList:(IRWebAPITwitterListID)inListID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSAssert(self.authenticator.currentCredentials.identifier, @"Error: %s requires that the current credentials be present.", __PRETTY_FUNCTION__); - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/%@/%llu/members.json", self.authenticator.currentCredentials.identifier, inListID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSString stringWithFormat:@"%llu", inUserID], @"id", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -@end \ No newline at end of file diff --git a/IRWebAPITwitterInterface+Timeline.h b/IRWebAPITwitterInterface+Timeline.h deleted file mode 100644 index aff23ee..0000000 --- a/IRWebAPITwitterInterface+Timeline.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// IRWebAPITwitterInterface+Timeline.h -// IRWebAPIKit -// -// Created by Evadne Wu on 12/17/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - - - - - -#ifndef __IRWebAPIInterface__Timeline__ -#define __IRWebAPIInterface__Timeline__ - -typedef enum { - -// IRWebAPITwitterTimelinePublic, - IRWebAPITwitterTimelineHome, - IRWebAPITwitterTimelineUser - -} IRWebAPITwitterTimelineType; - -typedef enum { - - IRWebAPITwitterRetweetByUser, // Retweets retweeted by current user - IRWebAPITwitterRetweetByFollowers, // Retweets retweeted by other people - IRWebAPITwitterRetweetOfUser // Retweets from other people, that are tweets by current user - -} IRWebAPITwitterRetweetType; - -#endif - - - - - -@interface IRWebAPITwitterInterface (Timeline) - -- (void) retrieveStatusesFromTimeline:(IRWebAPITwitterTimelineType)inTimelineType withRange:(IRWebAPITwitterStatusIDRange)range successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveMentionsWithRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveRetweetsOfType:(IRWebAPITwitterRetweetType)inType withRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveFavoritesWithRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) setStatus:(IRWebAPITwitterStatusID)inID asFavorited:(BOOL)inBecomesFavorited successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retweetStatus:(IRWebAPITwitterStatusID)inID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) retrieveStatusWithIdentifier:(IRWebAPITwitterStatusID)inID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback; - -@end diff --git a/IRWebAPITwitterInterface+Timeline.m b/IRWebAPITwitterInterface+Timeline.m deleted file mode 100644 index 6d20112..0000000 --- a/IRWebAPITwitterInterface+Timeline.m +++ /dev/null @@ -1,231 +0,0 @@ -// -// IRWebAPITwitterInterface+Timeline.m -// IRWebAPIKit -// -// Created by Evadne Wu on 12/17/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+Timeline.h" -#import "IRWebAPITwitterInterface+Validators.h" - -@implementation IRWebAPITwitterInterface (Timeline) - -- (void) retrieveStatusesFromTimeline:(IRWebAPITwitterTimelineType)inTimelineType withRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSString * (^methodNameForType) (IRWebAPITwitterTimelineType) = ^ NSString * (IRWebAPITwitterTimelineType inType) { - - if (inType == IRWebAPITwitterTimelineHome) - return @"1/statuses/home_timeline.json"; - - return @"1/statuses/user_timeline.json"; - - }; - - [self.engine fireAPIRequestNamed:methodNameForType(inTimelineType) withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:self.defaultBatchSize], @"count", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultTimelineValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveMentionsWithRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/statuses/mentions.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:self.defaultBatchSize], @"count", - [NSNumber numberWithBool:YES], @"include_rts", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultTimelineValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveRetweetsOfType:(IRWebAPITwitterRetweetType)inType withRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - NSString *requestName = ((^{ - - switch (inType) { - - case IRWebAPITwitterRetweetByUser: return @"1/statuses/retweeted_by_me.json"; - case IRWebAPITwitterRetweetByFollowers: return @"1/statuses/retweeted_to_me.json"; - case IRWebAPITwitterRetweetOfUser: return @"1/statuses/retweets_of_me.json"; - - } - - })()); - - if (!requestName) { - - NSLog(@"Error: %s failed because of an unknown IRWebAPITwitterRetweetType.", (char *)_cmd); - - } - - [self.engine fireAPIRequestNamed:requestName withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.since]), @"since_id", - IRWebAPIKitNumberOrNull([NSNumber numberWithUnsignedLongLong:inRange.before]), @"max_id", - [NSNumber numberWithInt:MIN(100, self.defaultBatchSize)], @"count", - [NSNumber numberWithBool:YES], @"include_rts", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultTimelineValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveFavoritesWithRange:(IRWebAPITwitterStatusIDRange)inRange successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/favorites.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - // The range / count currently is not even supported as the API returns only the latest 20 tweets - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultTimelineValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) setStatus:(IRWebAPITwitterStatusID)inID asFavorited:(BOOL)inBecomesFavorited successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/favorites/%@/%llu.json", (inBecomesFavorited ? @"create" : @"destroy"), inID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithUnsignedLongLong:inID], @"id", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retweetStatus:(IRWebAPITwitterStatusID)inID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/statuses/retweet/%llu.json", inID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithUnsignedLongLong:inID], @"id", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator:[self defaultSingleTweetValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) retrieveStatusWithIdentifier:(IRWebAPITwitterStatusID)inID successHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:[NSString stringWithFormat:@"1/statuses/show/%llu.json", inID] withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -@end diff --git a/IRWebAPITwitterInterface+User.h b/IRWebAPITwitterInterface+User.h deleted file mode 100644 index 4b2f131..0000000 --- a/IRWebAPITwitterInterface+User.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// IRWebAPITwitterInterface+User.h -// IRWebAPIKit -// -// Created by Evadne Wu on 4/5/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - - -@interface IRWebAPITwitterInterface (User) - -- (void) retrieveMetadataForUserWithIdentifiers:(NSArray *)identifiers withSuccessHandler:(IRWebAPIInterfaceCallback)successBlock failureHandler:(IRWebAPIInterfaceCallback)failureBlock; - -- (void) retrieveMetadataForUser:(IRWebAPITwitterUserID)anUserID withSuccessHandler:(IRWebAPIInterfaceCallback)successBlock failureHandler:(IRWebAPIInterfaceCallback)failureBlock; - -@end diff --git a/IRWebAPITwitterInterface+User.m b/IRWebAPITwitterInterface+User.m deleted file mode 100644 index 1e917d6..0000000 --- a/IRWebAPITwitterInterface+User.m +++ /dev/null @@ -1,43 +0,0 @@ -// -// IRWebAPITwitterInterface+User.m -// IRWebAPIKit -// -// Created by Evadne Wu on 4/5/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface+User.h" - - -@implementation IRWebAPITwitterInterface (User) - -- (void) retrieveMetadataForUserWithIdentifiers:(NSArray *)identifiers withSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/users/lookup.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - [identifiers componentsJoinedByString:@","], @"user_id", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:nil validator:[self defaultNoErrorValidator] successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - -- (void) retrieveMetadataForUser:(IRWebAPITwitterUserID)anUserID withSuccessHandler:(IRWebAPIInterfaceCallback)successBlock failureHandler:(IRWebAPIInterfaceCallback)failureBlock { - - // Just a convenience! - - return [self retrieveMetadataForUserWithIdentifiers:[NSArray arrayWithObject:[NSNumber numberWithUnsignedLongLong:anUserID]] withSuccessHandler:successBlock failureHandler:failureBlock]; - -} - -@end diff --git a/IRWebAPITwitterInterface+Validators.h b/IRWebAPITwitterInterface+Validators.h deleted file mode 100644 index de36f06..0000000 --- a/IRWebAPITwitterInterface+Validators.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// IRWebAPITwitterInterface+Validators.h -// IRWebAPIKit -// -// Created by Evadne Wu on 1/17/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - -@interface IRWebAPITwitterInterface (Validators) - -- (IRWebAPIResposeValidator) defaultNoErrorValidator; - -// Makes sure the response is 200 and does not come with an error - - -- (IRWebAPIResposeValidator) defaultValidatorForArrayNamed:(NSString *)inKeyPathToResponseArray withElementKeyPaths:(NSArray *)inKeyPaths validator:(BOOL(^)(id aKeyPath, id currentObject))inValidator; - -- (IRWebAPIResposeValidator) defaultValidatorForArrayNamed:(NSString *)inKeyPathToResponseArray withElementKeyPaths:(NSArray *)inKeyPaths; - -// Makes sure that the key path inKeyPathToResponseArray points to an NSArray, and each element in that array has values described in inKeyPaths -// The default validator is a “non-nil” validator. - - -- (IRWebAPIResposeValidator) defaultExistingValueValidatorForKeyPaths:(NSArray *)inKeyPaths; - -// return [self defaultValidatorForArrayNamed:@"response" withElementKeyPaths:inKeyPaths]; - - -- (IRWebAPIResposeValidator) defaultTimelineValidator; -- (IRWebAPIResposeValidator) defaultSingleTweetValidator; - -- (IRWebAPIResposeValidator) defaultListsValidator; - -@end diff --git a/IRWebAPITwitterInterface+Validators.m b/IRWebAPITwitterInterface+Validators.m deleted file mode 100644 index 5547aff..0000000 --- a/IRWebAPITwitterInterface+Validators.m +++ /dev/null @@ -1,125 +0,0 @@ -// -// IRWebAPITwitterInterface+Validators.m -// IRWebAPIKit -// -// Created by Evadne Wu on 1/17/11. -// Copyright 2011 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIKit.h" - - -@implementation IRWebAPITwitterInterface (Validators) - -- (IRWebAPIResposeValidator) defaultNoErrorValidator { - - return [IRWebAPIInterface defaultNoErrorValidator]; - -} - -- (IRWebAPIResposeValidator) defaultValidatorForArrayNamed:(NSString *)inKeyPathToResponseArray withElementKeyPaths:(NSArray *)inKeyPaths validator:(BOOL(^)(id aKeyPath, id currentObject))inValidator { - - return [[(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - if (![self defaultNoErrorValidator](inResponseOrNil, inResponseContext)) - return NO; - - NSArray *responseArray = [inResponseOrNil valueForKeyPath:inKeyPathToResponseArray]; - if (![responseArray isKindOfClass:[NSArray class]]) - return NO; - - for (id anObject in responseArray) - for (id aKeyPath in inKeyPaths) - if (!inValidator(aKeyPath, [anObject valueForKeyPath:aKeyPath])) - return NO; - - return YES; - - }) copy] autorelease]; - -} - -- (IRWebAPIResposeValidator) defaultValidatorForArrayNamed:(NSString *)inKeyPathToResponseArray withElementKeyPaths:(NSArray *)inKeyPaths { - - return [self defaultValidatorForArrayNamed:inKeyPathToResponseArray withElementKeyPaths:inKeyPaths validator: ^ (id aKeyPath, id currentObject) { - - return (BOOL)(currentObject != nil); - - }]; - -} - - -- (IRWebAPIResposeValidator) defaultExistingValueValidatorForKeyPaths:(NSArray *)inKeyPaths { - - return [self defaultValidatorForArrayNamed:@"response" withElementKeyPaths:inKeyPaths]; - -} - -- (IRWebAPIResposeValidator) defaultTimelineValidator { - - return [[(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - if (![self defaultExistingValueValidatorForKeyPaths:[NSArray arrayWithObject:@"response"]]) - return NO; - - id response = [inResponseOrNil valueForKeyPath:@"response"]; - - if (!response || ![response isKindOfClass:[NSArray class]]) - return NO; - - if ([(NSArray *)response count] > 0) - if ([[[(NSArray *)response objectAtIndex:0] valueForKeyPath:@"text"] isEqual:[NSNull null]]) - return NO; - - return YES; - - }) copy] autorelease]; - -} - -- (IRWebAPIResposeValidator) defaultListsValidator { - - return [[(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - if (![self defaultNoErrorValidator](inResponseOrNil, inResponseContext)) - return NO; - - id response = [inResponseOrNil valueForKeyPath:@"response"]; - - if (!response) - return NO; - - if ([response isEqual:[NSNull null]]) - return NO; - - if (![response isKindOfClass:[NSArray class]]) - return NO; - - if ([(NSArray *)response count] > 0) - if ([[[(NSArray *)response objectAtIndex:0] valueForKeyPath:@"name"] isEqual:[NSNull null]]) - return NO; - - return YES; - - }) copy] autorelease]; - -} - -- (IRWebAPIResposeValidator) defaultSingleTweetValidator { - - return [[(^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - if (![self defaultNoErrorValidator](inResponseOrNil, inResponseContext)) - return NO; - - if (![inResponseOrNil valueForKeyPath:@"text"]) - return NO; - - return YES; - - }) copy] autorelease]; - -} - -@end diff --git a/IRWebAPITwitterInterface.h b/IRWebAPITwitterInterface.h deleted file mode 100644 index c4aea62..0000000 --- a/IRWebAPITwitterInterface.h +++ /dev/null @@ -1,90 +0,0 @@ -// -// IRWebAPITwitterInterface.h -// IRWebAPIKit -// -// Created by Evadne Wu on 12/1/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPIKit.h" - -#ifndef __IRWebAPITwitterInterface__ -#define __IRWebAPITwitterInterface__ - - -typedef uint64_t IRWebAPITwitterStatusID; -#define IRWebAPITwitterStatusIdentifierNotApplicable 0 - -typedef struct IRWebAPITwitterStatusIDRange { - - IRWebAPITwitterStatusID since; - IRWebAPITwitterStatusID before; - -} IRWebAPITwitterStatusIDRange; - -#define IRWebAPITwitterStatusIDRangeNull ((IRWebAPITwitterStatusIDRange){0, 0}) - - -static inline IRWebAPITwitterStatusIDRange IRWebAPITwitterStatusIDRangeMake (IRWebAPITwitterStatusID begin, IRWebAPITwitterStatusID end) { - - IRWebAPITwitterStatusIDRange returnedRange; - - returnedRange.since = begin; - returnedRange.before = end; - - return returnedRange; - -} - -typedef uint64_t IRWebAPITwitterUserID; -typedef uint64_t IRWebAPITwitterListID; -typedef uint64_t IRWebAPITwitterDirectMessageID; - -typedef IRWebAPITwitterStatusIDRange IRWebAPITwitterDirectMessageIDRange; - -#define IRWebAPITwitterDirectMessageIDRangeNull IRWebAPITwitterStatusIDRangeNull -#define IRWebAPITwitterDirectMessageIdentifierNotApplicable IRWebAPITwitterStatusIdentifierNotApplicable - -static inline IRWebAPITwitterDirectMessageIDRange IRWebAPITwitterDirectMessageIDRangeMake (IRWebAPITwitterDirectMessageID begin, IRWebAPITwitterDirectMessageID end) { - - IRWebAPITwitterDirectMessageIDRange returnedRange; - - returnedRange.since = begin; - returnedRange.before = end; - - return returnedRange; - -} - -#endif - - - - - -@interface IRWebAPITwitterInterface : IRWebAPIInterface - -@property (nonatomic, readwrite, assign) NSUInteger defaultBatchSize; - -- (void) updateStatusForCurrentUserWithContents:(NSString *)inContents userInfo:(NSDictionary *)inUserInfo onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback; - -- (void) lookupCurrentUserWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessHandler failureHandler:(IRWebAPIInterfaceCallback)inFailureHandler; - -@end - - - - - -#import "IRWebAPITwitterInterface+Validators.h" - -#import "IRWebAPITwitterInterface+Timeline.h" -#import "IRWebAPITwitterInterface+Geo.h" -#import "IRWebAPITwitterInterface+Lists.h" -#import "IRWebAPITwitterInterface+DirectMessages.h" -#import "IRWebAPITwitterInterface+Friendships.h" -#import "IRWebAPITwitterInterface+User.h" - - - - diff --git a/IRWebAPITwitterInterface.m b/IRWebAPITwitterInterface.m deleted file mode 100644 index c57cf3d..0000000 --- a/IRWebAPITwitterInterface.m +++ /dev/null @@ -1,173 +0,0 @@ -// -// IRWebAPITwitterInterface.m -// IRWebAPIKit -// -// Created by Evadne Wu on 12/1/10. -// Copyright 2010 Iridia Productions. All rights reserved. -// - -#import "IRWebAPITwitterInterface.h" - -@implementation IRWebAPITwitterInterface - -@synthesize defaultBatchSize; -@synthesize consumerKey, consumerSecret; -@dynamic authenticator; - -- (id) init { - - IRWebAPIContext *twitterContext = [[[IRWebAPIContext alloc] initWithBaseURL:[NSURL URLWithString:@"https://api.twitter.com/"]] autorelease]; - - IRWebAPIEngine *twitterEngine = [[[IRWebAPIEngine alloc] initWithContext:twitterContext] autorelease]; - - twitterEngine.parser = IRWebAPIResponseDefaultJSONParserMake(); - - IRWebAPIXOAuthAuthenticator *twitterAuthenticator = [[[IRWebAPIXOAuthAuthenticator alloc] initWithEngine:twitterEngine] autorelease]; - - self = [self initWithEngine:twitterEngine authenticator:twitterAuthenticator]; - - if (!self) return nil; - - self.defaultBatchSize = 200; - - return self; - -} - -- (void) dealloc { - -// IRWebAPIInterfaceXOAuthAuthenticating - self.consumerKey = nil; - self.consumerSecret = nil; - - [super dealloc]; - -} - - - - - -- (void) setConsumerKey:(NSString *)inConsumerKey { - - ((IRWebAPIXOAuthAuthenticator *)(self.authenticator)).consumerKey = inConsumerKey; - -} - -- (NSString *) consumerKey { - - return ((IRWebAPIXOAuthAuthenticator *)(self.authenticator)).consumerKey; - -} - -- (void) setConsumerSecret:(NSString *)inConsumerSecret { - - ((IRWebAPIXOAuthAuthenticator *)(self.authenticator)).consumerSecret = inConsumerSecret; - -} - -- (NSString *) consumerSecret { - - return ((IRWebAPIXOAuthAuthenticator *)(self.authenticator)).consumerSecret; - -} - -- (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess:(IRWebAPIAuthenticatorCallback)successHandler onFailure:(IRWebAPIAuthenticatorCallback)failureHandler { - - NSLog(@"%@ %s", self, __PRETTY_FUNCTION__); - - NSLog(@"My authenticator , %@", self.authenticator); - - [self.authenticator authenticateCredentials:inCredentials onSuccess: ^ (IRWebAPIAuthenticator *inAuthenticator, BOOL isAuthenticated, BOOL *inShouldRetry) { - - NSLog(@"authentication is done."); - - if (!isAuthenticated) { - - *inShouldRetry = YES; - return; - - } - - if (successHandler) - successHandler(inAuthenticator, isAuthenticated, inShouldRetry); - - } onFailure: ^ (IRWebAPIAuthenticator *inAuthenticator, BOOL isAuthenticated, BOOL *inShouldRetry) { - - NSLog(@"Failed. %@", self); - - if (failureHandler) - failureHandler(inAuthenticator, isAuthenticated, inShouldRetry); - - }]; - -} - - - - - -- (void) updateStatusForCurrentUserWithContents:(NSString *)inContents userInfo:(NSDictionary *)inUserInfo onSuccess:(IRWebAPIInterfaceCallback)inSuccessCallback onFailure:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/statuses/update.json" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: - - inContents, @"status", - [NSString stringWithFormat:@"%llu", [(NSNumber *)[inUserInfo objectForKey:@"replyingStatusIdentifier"] unsignedLongLongValue]], @"in_reply_to_status_id", - [inUserInfo objectForKey:@"latitude"], @"lat", - [inUserInfo objectForKey:@"longitude"], @"lng", - [inUserInfo objectForKey:@"placeIdentifier"], @"placeID", - [inUserInfo objectForKey:@"displaysCoordinates"], @"display_coordinates", - [NSNumber numberWithBool:YES], @"include_entities", - - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: - - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext) { - - id returnedError = [inResponseOrNil objectForKey:@"error"]; - return (BOOL)(returnedError == nil); - - } successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"statuses/update response: %@", inResponseOrNil); - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - NSLog(@"Failed. %@", inResponseOrNil); - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -- (void) lookupCurrentUserWithSuccessHandler:(IRWebAPIInterfaceCallback)inSuccessCallback failureHandler:(IRWebAPIInterfaceCallback)inFailureCallback { - - [self.engine fireAPIRequestNamed:@"1/account/verify_credentials.json" withArguments:nil options:nil validator:nil successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inSuccessCallback) - inSuccessCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { - - if (inFailureCallback) - inFailureCallback(inResponseOrNil, outNotifyDelegate, outShouldRetry); - - }]; - -} - - - - - -@end diff --git a/IRWebAPIXOAuthAuthenticator.h b/IRWebAPIXOAuthAuthenticator.h index ab21e82..ba660e8 100644 --- a/IRWebAPIXOAuthAuthenticator.h +++ b/IRWebAPIXOAuthAuthenticator.h @@ -6,39 +6,13 @@ // Copyright 2010 Iridia Productions. All rights reserved. // -// OAUTH ON DESKTOP / MOBILE APPS IS A JOKE. -// THERE IS NO OAUTH AUTHENTICATOR PROVIDED. - @class IRWebAPIAuthenticator; -@interface IRWebAPIXOAuthAuthenticator : IRWebAPIAuthenticator { - - NSString *consumerKey; - NSString *consumerSecret; - - NSString *retrievedToken; - NSString *retrievedTokenSecret; - - NSURL *xAuthAccessTokenBaseURL; - NSURL *authorizeURL; - -} - -@property (nonatomic, readwrite, retain) NSString *consumerKey; -@property (nonatomic, readwrite, retain) NSString *consumerSecret; +@interface IRWebAPIXOAuthAuthenticator : IRWebAPIAuthenticator -@property (nonatomic, readwrite, retain) NSString *retrievedToken; -@property (nonatomic, readwrite, retain) NSString *retrievedTokenSecret; +@property (nonatomic, readwrite, copy) NSString *consumerKey; +@property (nonatomic, readwrite, copy) NSString *consumerSecret; - -- (NSDictionary *) oAuthHeaderValuesForHTTPMethod:(NSString *)inHTTPMethod baseURL:(NSURL *)inBaseURL arguments:(NSDictionary *)inMethodArguments; -- (NSString *) oAuthHeaderValueForHTTPMethod:(NSString *)inHTTPMethod baseURL:(NSURL *)inBaseURL arguments:(NSDictionary *)inMethodArguments; - -// The former returns a dictionary, which is used by the latter, which concatenates everything into a string ready for use in the Authorization header or another header, e.g. X-Verify-Credentials-Authorization - - -- (NSString *) oAuthHeaderValueForRequestContext:(NSDictionary *)inRequestContext; - -// Convenience. - +@property (nonatomic, readwrite, copy) NSString *retrievedToken; +@property (nonatomic, readwrite, copy) NSString *retrievedTokenSecret; @end diff --git a/IRWebAPIXOAuthAuthenticator.m b/IRWebAPIXOAuthAuthenticator.m index dac7e7a..314dc31 100644 --- a/IRWebAPIXOAuthAuthenticator.m +++ b/IRWebAPIXOAuthAuthenticator.m @@ -7,6 +7,7 @@ // #import "IRWebAPIKit.h" +#import "IRWebAPIRequestContext.h" #import "IRWebAPIXOAuthAuthenticator.h" @@ -14,82 +15,67 @@ @interface IRWebAPIXOAuthAuthenticator () @property (nonatomic, retain, readwrite) IRWebAPICredentials *currentCredentials; -@end +- (NSDictionary *) oAuthHeaderValuesForHTTPMethod:(NSString *)inHTTPMethod baseURL:(NSURL *)inBaseURL arguments:(NSDictionary *)inMethodArguments; +- (NSString *) oAuthHeaderValueForHTTPMethod:(NSString *)inHTTPMethod baseURL:(NSURL *)inBaseURL arguments:(NSDictionary *)inMethodArguments; +// The former returns a dictionary, which is used by the latter, which concatenates everything into a string ready for use in the Authorization header or another header, e.g. X-Verify-Credentials-Authorization -@implementation IRWebAPIXOAuthAuthenticator -@synthesize consumerKey, consumerSecret, retrievedToken, retrievedTokenSecret; -@synthesize currentCredentials; +- (NSString *) oAuthHeaderValueForRequestContext:(IRWebAPIRequestContext *)inRequestContext; -- (id) initWithEngine:(IRWebAPIEngine *)inEngine { +// Convenience. - self = [super initWithEngine:inEngine]; if (!self) return nil; - - consumerKey = nil; - consumerSecret = nil; - retrievedToken = nil; - retrievedTokenSecret = nil; - - xAuthAccessTokenBaseURL = nil; - authorizeURL = nil; - - return self; - -} +@end -- (void) dealloc { - self.consumerKey = nil; - self.consumerSecret = nil; - self.retrievedToken = nil; - self.retrievedTokenSecret = nil; - - [super dealloc]; +@implementation IRWebAPIXOAuthAuthenticator -} +@synthesize consumerKey = _consumerKey; +@synthesize consumerSecret = _consumerSecret; +@synthesize retrievedToken = _retrievedToken; +@synthesize retrievedTokenSecret = _retrievedTokenSecret; +@synthesize currentCredentials = _currentCredentials; - (void) createTransformerBlocks { - self.globalRequestPostTransformerBlock = ^ (NSDictionary *inOriginalContext) { + __weak IRWebAPIXOAuthAuthenticator *wSelf = self; + + self.globalRequestPostTransformerBlock = ^ (IRWebAPIRequestContext *context) { - NSMutableDictionary *mutatedContext = [inOriginalContext mutableCopy]; - NSMutableDictionary *mutatedContextHeaderFields = (NSMutableDictionary *)[mutatedContext objectForKey:kIRWebAPIEngineRequestHTTPHeaderFields]; - - BOOL isRequestAuthenticated = (BOOL)(!!(self.retrievedTokenSecret)), - isPOST = [@"POST" isEqual:[mutatedContext valueForKey:kIRWebAPIEngineRequestHTTPMethod]], + BOOL isRequestAuthenticated = (BOOL)(!!(wSelf.retrievedTokenSecret)), + isPOST = [@"POST" isEqual:context.method], removesQueryParameters = NO; - + if (isRequestAuthenticated && isPOST) { - [mutatedContext setObject:((^ { + [context setBody:((^ { NSMutableArray *POSTBodyElements = [NSMutableArray array]; - [[mutatedContext objectForKey:kIRWebAPIEngineRequestHTTPQueryParameters] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + [context.queryParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { [POSTBodyElements addObject:[NSString stringWithFormat:@"%@=%@", key, IRWebAPIKitRFC3986EncodedStringMake(obj)]]; }]; - + return [[POSTBodyElements componentsJoinedByString:@"&"] dataUsingEncoding:NSUTF8StringEncoding]; - })()) forKey:kIRWebAPIEngineRequestHTTPBody]; + })())]; - [mutatedContextHeaderFields setObject:@"application/x-www-form-urlencoded" forKey:@"Content-Type"]; + [context setValue:@"application/x-www-form-urlencoded" forHeaderField:@"Content-Type"]; removesQueryParameters = YES; } - [mutatedContextHeaderFields setObject:[self oAuthHeaderValueForRequestContext:mutatedContext] forKey:@"Authorization"]; + id authHeaderFieldValue = [wSelf oAuthHeaderValueForRequestContext:context]; - if (removesQueryParameters) - [mutatedContext setObject:[NSMutableArray array] forKey:kIRWebAPIEngineRequestHTTPQueryParameters]; + [context setValue:authHeaderFieldValue forHeaderField:@"Authorization"]; - IRWebAPIKitLog(@"mutatedContext %@", mutatedContext); + if (removesQueryParameters) + [context removeAllQueryParamValues]; - return [mutatedContext autorelease]; + return context; }; @@ -107,30 +93,25 @@ - (void) associateWithEngine:(IRWebAPIEngine *)inEngine { } - (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess:(IRWebAPIAuthenticatorCallback)successHandler onFailure:(IRWebAPIAuthenticatorCallback)failureHandler { - - [self.engine fireAPIRequestNamed:@"oauth/access_token" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: + + IRWebAPIRequestOperation *operation = [self.engine operationForMethod:@"oauth/access_token" arguments:[NSDictionary dictionaryWithObjectsAndKeys: inCredentials.identifier, @"x_auth_username", inCredentials.qualifier, @"x_auth_password", @"client_auth", @"x_auth_mode", - nil] options:[NSDictionary dictionaryWithObjectsAndKeys: + nil] validator: ^ (NSDictionary *response, IRWebAPIRequestContext *context) { - IRWebAPIResponseQueryResponseParserMake(), kIRWebAPIEngineParser, - @"POST", kIRWebAPIEngineRequestHTTPMethod, - - nil] validator: ^ (NSDictionary *inResponseOrNil, NSDictionary *inRequestContext) { - - if (!([IRWebAPIInterface defaultNoErrorValidator])(inResponseOrNil, inRequestContext)) + if (!([IRWebAPIInterface defaultNoErrorValidator])(response, context)) return NO; for (id key in [NSArray arrayWithObjects:@"oauth_token", @"oauth_token_secret", nil]) - if (!IRWebAPIKitValidResponse([inResponseOrNil objectForKey:key])) - return NO; + if (!IRWebAPIKitValidResponse([response objectForKey:key])) + return NO; return YES; - } successHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { + } successBlock: ^ (NSDictionary *inResponseOrNil, IRWebAPIRequestContext *context) { self.retrievedToken = [inResponseOrNil valueForKey:@"oauth_token"]; self.retrievedTokenSecret = [inResponseOrNil valueForKey:@"oauth_token_secret"]; @@ -141,24 +122,27 @@ - (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess: [self.currentCredentials.userInfo setObject:self.retrievedToken forKey:@"oauth_token"]; [self.currentCredentials.userInfo setObject:self.retrievedTokenSecret forKey:@"oauth_token_secret"]; - NSParameterAssert(self.currentCredentials && self.currentCredentials.authenticated); + NSCParameterAssert(self.currentCredentials && self.currentCredentials.authenticated); if (successHandler) - successHandler(self, YES, outShouldRetry); + successHandler(self, YES); - } failureHandler: ^ (NSDictionary *inResponseOrNil, NSDictionary *inResponseContext, BOOL *outNotifyDelegate, BOOL *outShouldRetry) { + } failureBlock: ^ (NSDictionary *inResponseOrNil, IRWebAPIRequestContext *context) { self.currentCredentials.authenticated = NO; self.retrievedToken = nil; self.retrievedTokenSecret = nil; - NSLog(@"XOAuth FAIL %@, %@", inResponseOrNil, inResponseContext); - if (failureHandler) - failureHandler(self, NO, outShouldRetry); + failureHandler(self, NO); }]; - + + operation.context.parser = IRWebAPIResponseQueryResponseParserMake(); + operation.context.method = @"POST"; + + [operation start]; + } @@ -167,8 +151,6 @@ - (void) authenticateCredentials:(IRWebAPICredentials *)inCredentials onSuccess: - (NSDictionary *) oAuthHeaderValuesForHTTPMethod:(NSString *)inHTTPMethod baseURL:(NSURL *)inBaseURL arguments:(NSDictionary *)inMethodArguments { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSMutableDictionary *signatureStringParameters = [NSMutableDictionary dictionary]; NSMutableDictionary *oAuthParameters = [NSMutableDictionary dictionaryWithObjectsAndKeys: @@ -207,12 +189,7 @@ - (NSDictionary *) oAuthHeaderValuesForHTTPMethod:(NSString *)inHTTPMethod baseU ) forKey:@"oauth_signature"]; - [oAuthParameters retain]; - [pool drain]; - - IRWebAPIKitLog(@"oAuthHeaderValuesForHTTPMethod -> %@", oAuthParameters); - - return [oAuthParameters autorelease]; + return oAuthParameters; } @@ -238,9 +215,13 @@ - (NSString *) oAuthHeaderValueForHTTPMethod:(NSString *)inHTTPMethod baseURL:(N } -- (NSString *) oAuthHeaderValueForRequestContext:(NSDictionary *)inRequestContext { +- (NSString *) oAuthHeaderValueForRequestContext:(IRWebAPIRequestContext *)context { + + NSString *method = context.method; + NSURL *baseURL = context.baseURL; + NSDictionary *arguments = context.queryParams; - return [self oAuthHeaderValueForHTTPMethod:[inRequestContext valueForKey:kIRWebAPIEngineRequestHTTPMethod] baseURL:[inRequestContext valueForKey:kIRWebAPIEngineRequestHTTPBaseURL] arguments:[inRequestContext valueForKey:kIRWebAPIEngineRequestHTTPQueryParameters]]; + return [self oAuthHeaderValueForHTTPMethod:method baseURL:baseURL arguments:arguments]; } diff --git a/JSONKit.h b/JSONKit.h new file mode 100644 index 0000000..71bd0c3 --- /dev/null +++ b/JSONKit.h @@ -0,0 +1,251 @@ +// +// JSONKit.h +// http://github.com/johnezang/JSONKit +// Dual licensed under either the terms of the BSD License, or alternatively +// under the terms of the Apache License, Version 2.0, as specified below. +// + +/* + Copyright (c) 2011, John Engelhart + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the Zang Industries nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + Copyright 2011 John Engelhart + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include +#include +#include +#include +#include + +#ifdef __OBJC__ +#import +#import +#import +#import +#import +#import +#endif // __OBJC__ + +#ifdef __cplusplus +extern "C" { +#endif + + +// For Mac OS X < 10.5. +#ifndef NSINTEGER_DEFINED +#define NSINTEGER_DEFINED +#if defined(__LP64__) || defined(NS_BUILD_32_LIKE_64) +typedef long NSInteger; +typedef unsigned long NSUInteger; +#define NSIntegerMin LONG_MIN +#define NSIntegerMax LONG_MAX +#define NSUIntegerMax ULONG_MAX +#else // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64) +typedef int NSInteger; +typedef unsigned int NSUInteger; +#define NSIntegerMin INT_MIN +#define NSIntegerMax INT_MAX +#define NSUIntegerMax UINT_MAX +#endif // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64) +#endif // NSINTEGER_DEFINED + + +#ifndef _JSONKIT_H_ +#define _JSONKIT_H_ + +#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__APPLE_CC__) && (__APPLE_CC__ >= 5465) +#define JK_DEPRECATED_ATTRIBUTE __attribute__((deprecated)) +#else +#define JK_DEPRECATED_ATTRIBUTE +#endif + +#define JSONKIT_VERSION_MAJOR 1 +#define JSONKIT_VERSION_MINOR 4 + +typedef NSUInteger JKFlags; + +/* + JKParseOptionComments : Allow C style // and /_* ... *_/ (without a _, obviously) comments in JSON. + JKParseOptionUnicodeNewlines : Allow Unicode recommended (?:\r\n|[\n\v\f\r\x85\p{Zl}\p{Zp}]) newlines. + JKParseOptionLooseUnicode : Normally the decoder will stop with an error at any malformed Unicode. + This option allows JSON with malformed Unicode to be parsed without reporting an error. + Any malformed Unicode is replaced with \uFFFD, or "REPLACEMENT CHARACTER". + */ + +enum { + JKParseOptionNone = 0, + JKParseOptionStrict = 0, + JKParseOptionComments = (1 << 0), + JKParseOptionUnicodeNewlines = (1 << 1), + JKParseOptionLooseUnicode = (1 << 2), + JKParseOptionPermitTextAfterValidJSON = (1 << 3), + JKParseOptionValidFlags = (JKParseOptionComments | JKParseOptionUnicodeNewlines | JKParseOptionLooseUnicode | JKParseOptionPermitTextAfterValidJSON), +}; +typedef JKFlags JKParseOptionFlags; + +enum { + JKSerializeOptionNone = 0, + JKSerializeOptionPretty = (1 << 0), + JKSerializeOptionEscapeUnicode = (1 << 1), + JKSerializeOptionEscapeForwardSlashes = (1 << 4), + JKSerializeOptionValidFlags = (JKSerializeOptionPretty | JKSerializeOptionEscapeUnicode | JKSerializeOptionEscapeForwardSlashes), +}; +typedef JKFlags JKSerializeOptionFlags; + +#ifdef __OBJC__ + +typedef struct JKParseState JKParseState; // Opaque internal, private type. + +// As a general rule of thumb, if you use a method that doesn't accept a JKParseOptionFlags argument, it defaults to JKParseOptionStrict + +@interface JSONDecoder : NSObject { + JKParseState *parseState; +} ++ (id)decoder; ++ (id)decoderWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (id)initWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (void)clearCache; + +// The parse... methods were deprecated in v1.4 in favor of the v1.4 objectWith... methods. +- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithUTF8String:length: instead. +- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length error:(NSError **)error JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithUTF8String:length:error: instead. +// The NSData MUST be UTF8 encoded JSON. +- (id)parseJSONData:(NSData *)jsonData JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithData: instead. +- (id)parseJSONData:(NSData *)jsonData error:(NSError **)error JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithData:error: instead. + +// Methods that return immutable collection objects. +- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length; +- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error; +// The NSData MUST be UTF8 encoded JSON. +- (id)objectWithData:(NSData *)jsonData; +- (id)objectWithData:(NSData *)jsonData error:(NSError **)error; + +// Methods that return mutable collection objects. +- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length; +- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error; +// The NSData MUST be UTF8 encoded JSON. +- (id)mutableObjectWithData:(NSData *)jsonData; +- (id)mutableObjectWithData:(NSData *)jsonData error:(NSError **)error; + +@end + +//////////// +#pragma mark Deserializing methods +//////////// + +@interface NSString (JSONKitDeserializing) +- (id)objectFromJSONString; +- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error; +- (id)mutableObjectFromJSONString; +- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error; +@end + +@interface NSData (JSONKitDeserializing) +// The NSData MUST be UTF8 encoded JSON. +- (id)objectFromJSONData; +- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error; +- (id)mutableObjectFromJSONData; +- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags; +- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error; +@end + +//////////// +#pragma mark Serializing methods +//////////// + +@interface NSString (JSONKitSerializing) +// Convenience methods for those that need to serialize the receiving NSString (i.e., instead of having to serialize a NSArray with a single NSString, you can "serialize to JSON" just the NSString). +// Normally, a string that is serialized to JSON has quotation marks surrounding it, which you may or may not want when serializing a single string, and can be controlled with includeQuotes: +// includeQuotes:YES `a "test"...` -> `"a \"test\"..."` +// includeQuotes:NO `a "test"...` -> `a \"test\"...` +- (NSData *)JSONData; // Invokes JSONDataWithOptions:JKSerializeOptionNone includeQuotes:YES +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error; +- (NSString *)JSONString; // Invokes JSONStringWithOptions:JKSerializeOptionNone includeQuotes:YES +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error; +@end + +@interface NSArray (JSONKitSerializing) +- (NSData *)JSONData; +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error; +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error; +- (NSString *)JSONString; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error; +@end + +@interface NSDictionary (JSONKitSerializing) +- (NSData *)JSONData; +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error; +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error; +- (NSString *)JSONString; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error; +@end + +#ifdef __BLOCKS__ + +@interface NSArray (JSONKitSerializingBlockAdditions) +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error; +@end + +@interface NSDictionary (JSONKitSerializingBlockAdditions) +- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error; +- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error; +@end + +#endif + + +#endif // __OBJC__ + +#endif // _JSONKIT_H_ + +#ifdef __cplusplus +} // extern "C" +#endif