Skip to content

Commit

Permalink
Merge branch 'master' of git://github.com/twotoasters/RestKit
Browse files Browse the repository at this point in the history
  • Loading branch information
ecordell committed Jul 7, 2011
2 parents 8dbfc81 + 6de4290 commit cbb07dd
Show file tree
Hide file tree
Showing 19 changed files with 211 additions and 41 deletions.
23 changes: 17 additions & 6 deletions Code/Network/RKClient.m
Expand Up @@ -72,7 +72,11 @@
}

NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryParams) {
return [NSString stringWithFormat:@"%@?%@", resourcePath, [queryParams URLEncodedString]];
if ([queryParams count] > 0) {
return [NSString stringWithFormat:@"%@?%@", resourcePath, [queryParams URLEncodedString]];
} else {
return resourcePath;
}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -189,7 +193,7 @@ - (NSString*)URLPathForResourcePath:(NSString*)resourcePath {
}

- (NSURL*)URLForResourcePath:(NSString *)resourcePath queryParams:(NSDictionary*)queryParams {
return [self URLForResourcePath:RKPathAppendQueryParams(resourcePath, queryParams)];
return [RKURL URLWithBaseURLString:self.baseURL resourcePath:resourcePath queryParams:queryParams];
}

- (void)setupRequest:(RKRequest*)request {
Expand Down Expand Up @@ -248,11 +252,19 @@ - (RKRequest*)requestWithResourcePath:(NSString*)resourcePath delegate:(NSObject
///////////////////////////////////////////////////////////////////////////////////////////////////////////

- (RKRequest*)load:(NSString*)resourcePath method:(RKRequestMethod)method params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate {
RKRequest* request = [[RKRequest alloc] initWithURL:[self URLForResourcePath:resourcePath] delegate:delegate];
NSURL* resourcePathURL = nil;
if (method == RKRequestMethodGET) {
resourcePathURL = [self URLForResourcePath:resourcePath queryParams:(NSDictionary*)params];
} else {
resourcePathURL = [self URLForResourcePath:resourcePath];
}
RKRequest* request = [[RKRequest alloc] initWithURL:resourcePathURL delegate:delegate];
[self setupRequest:request];
[request autorelease];
request.method = method;
request.params = params;
if (method != RKRequestMethodGET) {
request.params = params;
}
[request send];

return request;
Expand All @@ -263,8 +275,7 @@ - (RKRequest*)get:(NSString*)resourcePath delegate:(id)delegate {
}

- (RKRequest*)get:(NSString*)resourcePath queryParams:(NSDictionary*)queryParams delegate:(id)delegate {
NSString* resourcePathWithQueryString = [NSString stringWithFormat:@"%@?%@", resourcePath, [queryParams URLEncodedString]];
return [self load:resourcePathWithQueryString method:RKRequestMethodGET params:nil delegate:delegate];
return [self load:resourcePath method:RKRequestMethodGET params:queryParams delegate:delegate];
}

- (RKRequest*)post:(NSString*)resourcePath params:(NSObject<RKRequestSerializable>*)params delegate:(id)delegate {
Expand Down
2 changes: 1 addition & 1 deletion Code/Network/RKNetwork.h
Expand Up @@ -12,7 +12,7 @@
* Returns the global value for credential persistence to use during HTTP AUTH
* Defaults to NSURLCredentialPersistenceForSession
*/
NSURLCredentialPersistence RKNetworkGetGlobalCredentialPersistence();
NSURLCredentialPersistence RKNetworkGetGlobalCredentialPersistence(void);

/**
* Set the global value for credential persistence to use during HTTP AUTH
Expand Down
2 changes: 1 addition & 1 deletion Code/Network/RKNetwork.m
Expand Up @@ -11,7 +11,7 @@
// Global credential persistence value.
static NSURLCredentialPersistence gCredentialPersistence = NSURLCredentialPersistenceForSession;

NSURLCredentialPersistence RKNetworkGetGlobalCredentialPersistence() {
NSURLCredentialPersistence RKNetworkGetGlobalCredentialPersistence(void) {
return gCredentialPersistence;
}

Expand Down
4 changes: 4 additions & 0 deletions Code/Network/RKURL.h
Expand Up @@ -9,12 +9,16 @@
@interface RKURL : NSURL {
NSString* _baseURLString;
NSString* _resourcePath;
NSDictionary* _queryParams;
}

@property (nonatomic, readonly) NSString* baseURLString;
@property (nonatomic, readonly) NSString* resourcePath;
@property (nonatomic, readonly) NSDictionary* queryParams;

- (id)initWithBaseURLString:(NSString*)baseURLString resourcePath:(NSString*)resourcePath;
- (id)initWithBaseURLString:(NSString*)baseURLString resourcePath:(NSString*)resourcePath queryParams:(NSDictionary*)queryParams;
+ (RKURL*)URLWithBaseURLString:(NSString*)baseURLString resourcePath:(NSString*)resourcePath;
+ (RKURL*)URLWithBaseURLString:(NSString*)baseURLString resourcePath:(NSString*)resourcePath queryParams:(NSDictionary*)queryParams;

@end
32 changes: 26 additions & 6 deletions Code/Network/RKURL.m
Expand Up @@ -7,24 +7,42 @@
//

#import "RKURL.h"
#import "RKClient.h"

@implementation RKURL

@synthesize baseURLString = _baseURLString;
@synthesize resourcePath = _resourcePath;
@synthesize queryParams = _queryParams;

+ (RKURL*)URLWithBaseURLString:(NSString*)baseURLString resourcePath:(NSString*)resourcePath {
return [[[RKURL alloc] initWithBaseURLString:baseURLString resourcePath:resourcePath] autorelease];
return [[[self alloc] initWithBaseURLString:baseURLString resourcePath:resourcePath] autorelease];
}

+ (RKURL*)URLWithBaseURLString:(NSString*)baseURLString resourcePath:(NSString*)resourcePath queryParams:(NSDictionary*)queryParams {
return [[[self alloc] initWithBaseURLString:baseURLString resourcePath:resourcePath queryParams:queryParams] autorelease];
}

- (id)initWithBaseURLString:(NSString*)baseURLString resourcePath:(NSString*)resourcePath {
NSString* completeURL = [NSString stringWithFormat:@"%@%@", baseURLString, resourcePath];
completeURL = [(NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)completeURL, NULL, (CFStringRef)@"+", kCFStringEncodingUTF8) autorelease];

self = [self initWithString:completeURL];
if (self) {
return [self initWithBaseURLString:baseURLString resourcePath:resourcePath queryParams:nil];
}

- (id)initWithBaseURLString:(NSString*)baseURLString resourcePath:(NSString*)resourcePath queryParams:(NSDictionary*)queryParams {
NSString* resourcePathWithQueryString = RKPathAppendQueryParams(resourcePath, queryParams);
NSURL *baseURL = [NSURL URLWithString:baseURLString];
NSString* completePath = [[baseURL path] stringByAppendingPathComponent:resourcePathWithQueryString];
NSURL* completeURL = [NSURL URLWithString:completePath relativeToURL:baseURL];
if (!completeURL) {
[self release];
return nil;
}

// You can't safely use initWithString:relativeToURL: in a NSURL subclass, see http://www.openradar.me/9729706
self = [self initWithString:[completeURL absoluteString]];
if (self) {
_baseURLString = [baseURLString copy];
_resourcePath = [resourcePath copy];
_queryParams = [queryParams retain];
}
return self;
}
Expand All @@ -34,6 +52,8 @@ - (void)dealloc {
_baseURLString = nil;
[_resourcePath release];
_resourcePath = nil;
[_queryParams release];
_queryParams = nil;
[super dealloc];
}

Expand Down
5 changes: 5 additions & 0 deletions Code/ObjectMapping/RKObjectLoader.h
Expand Up @@ -46,6 +46,11 @@
*/
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjectDictionary:(NSDictionary*)dictionary;

/**
Invoked when the object loader has finished loading
*/
- (void)objectLoaderDidFinishLoading:(RKObjectLoader*)objectLoader;

/**
Sent when an object loader encounters a response status code it does not know how to handle.
2xx, 4xx, and 5xx responses are all handled appropriately. This should only occur when the remote
Expand Down
28 changes: 25 additions & 3 deletions Code/ObjectMapping/RKObjectLoader.m
Expand Up @@ -85,13 +85,18 @@ - (void)finalizeLoad:(BOOL)successful error:(NSError*)error {

if (successful) {
_isLoaded = YES;
if ([self.delegate respondsToSelector:@selector(objectLoaderDidFinishLoading:)]) {
[(NSObject<RKObjectLoaderDelegate>*)self.delegate objectLoaderDidFinishLoading:self];
}

NSDictionary* userInfo = [NSDictionary dictionaryWithObject:_response
forKey:RKRequestDidLoadResponseNotificationUserInfoResponseKey];
[[NSNotificationCenter defaultCenter] postNotificationName:RKRequestDidLoadResponseNotification
object:self
userInfo:userInfo];
} else {
NSDictionary* userInfo = [NSDictionary dictionaryWithObject:error forKey:RKRequestDidFailWithErrorNotificationUserInfoErrorKey];
NSDictionary* userInfo = [NSDictionary dictionaryWithObject:(error ? error : (NSError*)[NSNull null])
forKey:RKRequestDidFailWithErrorNotificationUserInfoErrorKey];
[[NSNotificationCenter defaultCenter] postNotificationName:RKRequestDidFailWithErrorNotification
object:self
userInfo:userInfo];
Expand Down Expand Up @@ -144,7 +149,21 @@ - (void)processMappingResult:(RKObjectMappingResult*)result {
- (RKObjectMappingResult*)mapResponseWithMappingProvider:(RKObjectMappingProvider*)mappingProvider toObject:(id)targetObject error:(NSError**)error {
id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:self.response.MIMEType];
NSAssert1(parser, @"Cannot perform object load without a parser for MIME Type '%@'", self.response.MIMEType);
id parsedData = [parser objectFromString:[self.response bodyAsString] error:error];

// Check that there is actually content in the response body for mapping. It is possible to get back a 200 response
// with the appropriate MIME Type with no content (such as for a successful PUT or DELETE). Make sure we don't generate an error
// in these cases
id bodyAsString = [self.response bodyAsString];
if (bodyAsString == nil || [[bodyAsString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) {
RKLogDebug(@"Mapping attempted on empty response body...");
if (self.targetObject) {
return [RKObjectMappingResult mappingResultWithDictionary:[NSDictionary dictionaryWithObject:self.targetObject forKey:@""]];
}

return nil;
}

id parsedData = [parser objectFromString:bodyAsString error:error];
if (parsedData == nil && error) {
return nil;
}
Expand Down Expand Up @@ -203,8 +222,11 @@ - (void)performMappingOnBackgroundThread {
_result = [[self performMapping:&error] retain];
if (self.result) {
[self processMappingResult:self.result];
} else {
} else if (error) {
[self performSelectorInBackground:@selector(didFailLoadWithError:) withObject:error];
} else {
// A nil response with an error indicates success, but no mapping results
[self finalizeLoad:YES error:nil];
}

[pool drain];
Expand Down
2 changes: 1 addition & 1 deletion Code/Support/RKLog.h
Expand Up @@ -124,4 +124,4 @@ lcl_configure_by_name("App", level);
/**
Initialize the logging environment
*/
void RKLogInitialize();
void RKLogInitialize(void);
2 changes: 1 addition & 1 deletion Code/Support/RKLog.m
Expand Up @@ -10,7 +10,7 @@

static BOOL loggingInitialized = NO;

void RKLogInitialize() {
void RKLogInitialize(void) {
if (loggingInitialized == NO) {
lcl_configure_by_name("RestKit*", RKLogLevelDefault);
lcl_configure_by_name("App", RKLogLevelDefault);
Expand Down
4 changes: 4 additions & 0 deletions RestKit.xcodeproj/project.pbxproj
Expand Up @@ -126,6 +126,7 @@
258A92691379D18A00D80034 /* RKObjectFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 258A92681379D18A00D80034 /* RKObjectFactory.h */; settings = {ATTRIBUTES = (Public, ); }; };
258A926C1379D41F00D80034 /* RKManagedObjectFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 258A926A1379D41F00D80034 /* RKManagedObjectFactory.h */; settings = {ATTRIBUTES = (Private, ); }; };
258A926D1379D41F00D80034 /* RKManagedObjectFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 258A926B1379D41F00D80034 /* RKManagedObjectFactory.m */; };
258E490113C51FE600C9C883 /* RKJSONParserJSONKitSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 258E490013C51FE600C9C883 /* RKJSONParserJSONKitSpec.m */; };
25901D7C137B6CF60002ECEB /* RKManagedObjectFactorySpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 25901D7B137B695F0002ECEB /* RKManagedObjectFactorySpec.m */; };
2590E67F125235C200531FA8 /* JSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 2590E674125235C200531FA8 /* JSON.h */; settings = {ATTRIBUTES = (Public, ); }; };
2590E680125235C200531FA8 /* NSObject+SBJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 2590E675125235C200531FA8 /* NSObject+SBJSON.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -516,6 +517,7 @@
258A926B1379D41F00D80034 /* RKManagedObjectFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKManagedObjectFactory.m; sourceTree = "<group>"; };
258C65EF133C317A004388A4 /* CopyHeadersToLegacyBuildDir.command */ = {isa = PBXFileReference; lastKnownFileType = text; path = CopyHeadersToLegacyBuildDir.command; sourceTree = "<group>"; };
258C6687133C377A004388A4 /* libUISpec.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libUISpec.a; sourceTree = SOURCE_ROOT; };
258E490013C51FE600C9C883 /* RKJSONParserJSONKitSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKJSONParserJSONKitSpec.m; sourceTree = "<group>"; };
25901D7B137B695F0002ECEB /* RKManagedObjectFactorySpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKManagedObjectFactorySpec.m; sourceTree = "<group>"; };
2590E64F125231F600531FA8 /* libRestKitJSONParserYAJL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRestKitJSONParserYAJL.a; sourceTree = BUILT_PRODUCTS_DIR; };
2590E66B1252353700531FA8 /* libRestKitJSONParserSBJSON.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRestKitJSONParserSBJSON.a; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -1385,6 +1387,7 @@
children = (
259D511B1328547000897272 /* NSDictionary+RKRequestSerializationSpec.m */,
3F4EAF57134205CF00F944E4 /* RKXMLParserSpec.m */,
258E490013C51FE600C9C883 /* RKJSONParserJSONKitSpec.m */,
);
path = Support;
sourceTree = "<group>";
Expand Down Expand Up @@ -2136,6 +2139,7 @@
2559209713BD1B8700E9C29C /* RKParamsSpec.m in Sources */,
250CAF5813BF9F2D00A1330E /* RKManagedObjectStoreSpec.m in Sources */,
259BEF5113C3B12B00487F66 /* RKObjectMappingResultSpec.m in Sources */,
258E490113C51FE600C9C883 /* RKJSONParserJSONKitSpec.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
10 changes: 5 additions & 5 deletions RestKit.xcodeproj/xcshareddata/xcschemes/UISpec.xcscheme
Expand Up @@ -62,7 +62,7 @@
<EnvironmentVariables>
<EnvironmentVariable
key = "UISPEC_SPEC"
value = "RKObjectMappingNextGenSpec"
value = "RKManagedObjectLoaderSpec"
isEnabled = "NO">
</EnvironmentVariable>
<EnvironmentVariable
Expand All @@ -72,7 +72,7 @@
</EnvironmentVariable>
<EnvironmentVariable
key = "UISPEC_EXAMPLE"
value = "itShouldMapACollectionOfObjectsWithDynamicKeysAndRelationships"
value = "itShouldDeleteObjectFromLocalStoreOnDELETE"
isEnabled = "NO">
</EnvironmentVariable>
<EnvironmentVariable
Expand All @@ -87,12 +87,12 @@
</EnvironmentVariable>
<EnvironmentVariable
key = "UISPEC_SPEC"
value = "RKObjectMappingResultSpec"
isEnabled = "YES">
value = "RKObjectLoaderSpec"
isEnabled = "NO">
</EnvironmentVariable>
<EnvironmentVariable
key = "UISPEC_EXAMPLE"
value = "itShouldSuspendTheMainQueueOnBaseURLChangeWhenReachabilityHasNotBeenEstablished"
value = "itShouldReturnSuccessWhenTheStatusCodeIs200ButTheResponseBodyIsEmpty"
isEnabled = "NO">
</EnvironmentVariable>
<EnvironmentVariable
Expand Down
1 change: 0 additions & 1 deletion Specs/Network/RKParamsSpec.m
Expand Up @@ -17,7 +17,6 @@ @interface RKParamsSpec : RKSpec
@implementation RKParamsSpec

- (void)itShouldNotOverReleaseTheParams {
RKLogConfigureByName("RestKit/Network*", RKLogLevelTrace);
NSDictionary* dictionary = [NSDictionary dictionaryWithObject:@"foo" forKey:@"bar"];
RKParams* params = [[RKParams alloc] initWithDictionary:dictionary];
NSURL* URL = [NSURL URLWithString:[RKSpecGetBaseURL() stringByAppendingFormat:@"/echo_params"]];
Expand Down
1 change: 0 additions & 1 deletion Specs/Network/RKRequestSpec.m
Expand Up @@ -287,7 +287,6 @@ - (void)itShouldLoadFromCacheWhenWeRecieveA304 {
}

- (void)itShouldUpdateTheInternalCacheDateWhenWeRecieveA304 {
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
NSString* baseURL = RKSpecGetBaseURL();
NSString* cacheDirForClient = [NSString stringWithFormat:@"RKClientRequestCache-%@",
[[NSURL URLWithString:baseURL] host]];
Expand Down
37 changes: 34 additions & 3 deletions Specs/Network/RKURLSpec.m
Expand Up @@ -27,9 +27,40 @@ - (void)itShouldNotExplodeBecauseOfUnicodeCharacters {
}
}

- (void)itShouldEncodePlusCharacters {
RKURL* URL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:@"/john+restkit@gmail.com"];
assertThat([URL absoluteString], is(equalTo(@"http://restkit.org/john%2Brestkit@gmail.com")));
- (void)itShouldEscapeQueryParameters {
NSDictionary* queryParams = [NSDictionary dictionaryWithObjectsAndKeys:@"What is your #1 e-mail?", @"question", @"john+restkit@gmail.com", @"answer", nil];
RKURL* URL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:@"/test" queryParams:queryParams];
assertThat([URL absoluteString], is(equalTo(@"http://restkit.org/test?answer=john%2Brestkit%40gmail.com&question=What%20is%20your%20%231%20e-mail%3F")));
}

- (void)itShouldHandleNilQueryParameters {
RKURL* URL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:@"/test" queryParams:nil];
assertThat([URL absoluteString], is(equalTo(@"http://restkit.org/test")));
}

- (void)itShouldHandleEmptyQueryParameters {
RKURL* URL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:@"/test" queryParams:[NSDictionary dictionary]];
assertThat([URL absoluteString], is(equalTo(@"http://restkit.org/test")));
}

- (void)itShouldHandleResourcePathWithoutLeadingSlash {
RKURL* URL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:@"test"];
assertThat([URL absoluteString], is(equalTo(@"http://restkit.org/test")));
}

- (void)itShouldHandleEmptyResourcePath {
RKURL* URL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:@""];
assertThat([URL absoluteString], is(equalTo(@"http://restkit.org")));
}

- (void)itShouldHandleBaseURLsWithAPath {
RKURL* URL = [RKURL URLWithBaseURLString:@"http://restkit.org/this" resourcePath:@"/test" queryParams:nil];
assertThat([URL absoluteString], is(equalTo(@"http://restkit.org/this/test")));
}

- (void)itShouldSimplifyURLsWithSeveralSlashes {
RKURL* URL = [RKURL URLWithBaseURLString:@"http://restkit.org//this//" resourcePath:@"/test" queryParams:nil];
assertThat([URL absoluteString], is(equalTo(@"http://restkit.org/this/test")));
}

@end
Expand Down

0 comments on commit cbb07dd

Please sign in to comment.