Skip to content
This repository has been archived by the owner on Mar 23, 2021. It is now read-only.

Commit

Permalink
Refactor route construction with resource prefixes
Browse files Browse the repository at this point in the history
  • Loading branch information
dingbat committed Jun 6, 2012
1 parent ce3200e commit 15d6be5
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 58 deletions.
68 changes: 29 additions & 39 deletions nsrails/Source/NSRRemoteObject.m
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ - (id) remoteRepresentationOfObjectForProperty:(NSRProperty *)prop;

+ (NSString *) routeForControllerMethod:(NSString *)customRESTMethod;
- (NSString *) routeForInstanceMethod:(NSString *)customRESTMethod httpVerb:(NSString *)verb;
- (void) assertCanSendInstanceRequestOnVerb:(NSString *)httpVerb;

+ (NSString *) NSRMap;
+ (NSString *) NSRUseModelName;
Expand Down Expand Up @@ -825,79 +824,70 @@ + (NSString *) routeForControllerMethod:(NSString *)method
return route;
}

- (BOOL) verbUsesPrefixConstruction:(NSString *)verb
- (NSString *) routeForInstanceMethod:(NSString *)method httpMethod:(NSString *)verb
{
NSArray *allowedVerbs = [self performSelectorWithoutClimbingHierarchy:@selector(NSRUseResourcePrefixMethods)];

return (!allowedVerbs || [allowedVerbs containsObject:verb] || [allowedVerbs containsObject:[verb lowercaseString]]);
}

- (NSString *) routeForInstanceMethod:(NSString *)method httpVerb:(NSString *)verb
{
[self assertCanSendInstanceRequestOnVerb:verb];
if (!self.remoteID)
{
[NSException raise:NSRNullRemoteIDException format:@"Attempt to %@ to %@/:id/%@ with %@ instance that has a nil remoteID.",verb,[[self class] masterPluralName],method ? method : @"",[self class]];
}

NSRRemoteObject *prefix = nil;
BOOL shouldUsePrefixConstruction = NO;
if ([self respondsToSelectorWithoutClimbingHierarchy:@selector(NSRUseResourcePrefix)])
{
NSArray *allowedVerbs = [self performSelectorWithoutClimbingHierarchy:@selector(NSRUseResourcePrefixMethods)];

shouldUsePrefixConstruction = (!allowedVerbs ||
[allowedVerbs containsObject:verb] ||
[allowedVerbs containsObject:[verb lowercaseString]]);

if (shouldUsePrefixConstruction)
{
prefix = [self performSelectorWithoutClimbingHierarchy:@selector(NSRUseResourcePrefix)];
if (!prefix.remoteID)
{
[NSException raise:NSRNullRemoteIDException format:@"Attempt to %@ %@ instance with a prefix association (%@ instance) that has a nil remoteID.",verb,[self class],[prefix class]];
}
}
}

// 1/something
// posts/1/something
// other/5/posts/1/something (only if prefix - use everything as instance method of prefix object)

NSString *route = [[self.remoteID stringValue] stringByAppendingPathComponent:method];
route = [[self class] routeForControllerMethod:route];

NSRRemoteObject *prefix = [self performSelectorWithoutClimbingHierarchy:@selector(NSRUseResourcePrefix)];
if (prefix && [self verbUsesPrefixConstruction:verb])
{
route = [prefix routeForInstanceMethod:route httpVerb:verb];
}
if (shouldUsePrefixConstruction)
route = [prefix routeForInstanceMethod:route httpMethod:verb];

return route;
}


#pragma mark Performing actions on instances

- (void) assertCanSendInstanceRequestOnVerb:(NSString *)verb
{
if (!self.remoteID)
{
[NSException raise:NSRNullRemoteIDException format:@"Attempted to update, delete, or retrieve an object with no ID. (Instance of %@)",[self class]];
}
else if ([self respondsToSelectorWithoutClimbingHierarchy:@selector(NSRUseResourcePrefix)] &&
[self verbUsesPrefixConstruction:verb])
{
NSRRemoteObject *prefix = [self performSelectorWithoutClimbingHierarchy:@selector(NSRUseResourcePrefix)];
if (!prefix.remoteID)
{
[NSException raise:NSRNullRemoteIDException format:@"Attempted to update, delete, or retrieve an object whose prefix association (%@) has no ID. (Instance of %@)",[prefix class],[self class]];
}
}
}

- (id) remoteRequest:(NSString *)httpVerb method:(NSString *)customRESTMethod body:(id)body error:(NSError **)error
{
NSString *route = [self routeForInstanceMethod:customRESTMethod httpVerb:httpVerb];
NSString *route = [self routeForInstanceMethod:customRESTMethod httpMethod:httpVerb];
return [[self getRelevantConfig] makeRequest:httpVerb requestBody:body route:route sync:error orAsync:nil];
}

- (void) remoteRequest:(NSString *)httpVerb method:(NSString *)customRESTMethod body:(id)body async:(NSRHTTPCompletionBlock)completionBlock
{
NSString *route = [self routeForInstanceMethod:customRESTMethod httpVerb:httpVerb];
NSString *route = [self routeForInstanceMethod:customRESTMethod httpMethod:httpVerb];
[[self getRelevantConfig] makeRequest:httpVerb requestBody:body route:route sync:nil orAsync:completionBlock];
}

//these are really just convenience methods that'll call the above method sending the object data as request body

- (id) remoteRequest:(NSString *)httpVerb method:(NSString *)customRESTMethod error:(NSError **)error
{
//done again so it can be tested before converting to JSON
[self assertCanSendInstanceRequestOnVerb:httpVerb];

return [self remoteRequest:httpVerb method:customRESTMethod body:[self remoteDictionaryRepresentationWrapped:YES] error:error];
}

- (void) remoteRequest:(NSString *)httpVerb method:(NSString *)customRESTMethod async:(NSRHTTPCompletionBlock)completionBlock
{
[self assertCanSendInstanceRequestOnVerb:httpVerb];

[self remoteRequest:httpVerb method:customRESTMethod body:[self remoteDictionaryRepresentationWrapped:YES] async:completionBlock];
}

Expand Down
2 changes: 1 addition & 1 deletion nsrails/Tests/NSRAsserts.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
+ (NSRPropertyCollection *) propertyCollection;
- (NSRPropertyCollection *) propertyCollection;

- (NSString *) routeForInstanceMethod:(NSString *)route httpVerb:(NSString *)str;
- (NSString *) routeForInstanceMethod:(NSString *)route httpMethod:(NSString *)str;
+ (NSString *) routeForControllerMethod:(NSString *)route;

+ (NSString *) typeForProperty:(NSString *)prop;
Expand Down
36 changes: 18 additions & 18 deletions nsrails/Tests/NSRRemoteObject.m
Original file line number Diff line number Diff line change
Expand Up @@ -372,11 +372,11 @@ - (void) test_routes

// Instance
Empty *smth = [[Empty alloc] init];
STAssertThrowsSpecificNamed([smth routeForInstanceMethod:nil httpVerb:verb], NSException, NSRNullRemoteIDException, @"Should have been an exception getting instance route if nil remoteID");
STAssertThrowsSpecificNamed([smth routeForInstanceMethod:nil httpMethod:verb], NSException, NSRNullRemoteIDException, @"Should have been an exception getting instance route if nil remoteID");

smth.remoteID = [NSNumber numberWithInt:1];
STAssertEqualObjects([smth routeForInstanceMethod:nil httpVerb:verb], @"empties/1", @"Nil instance route failed");
STAssertEqualObjects([smth routeForInstanceMethod:@"action" httpVerb:verb], @"empties/1/action", @"Instance route failed");
STAssertEqualObjects([smth routeForInstanceMethod:nil httpMethod:verb], @"empties/1", @"Nil instance route failed");
STAssertEqualObjects([smth routeForInstanceMethod:@"action" httpMethod:verb], @"empties/1/action", @"Instance route failed");
}

- (void) test_routes_with_prefixes
Expand All @@ -391,18 +391,18 @@ - (void) test_routes_with_prefixes
Prefixer *smth = [[Prefixer alloc] init];
STAssertNil([smth NSRUseResourcePrefixMethods], @"Should have nil allowed array");

STAssertThrowsSpecificNamed([smth routeForInstanceMethod:nil httpVerb:verb], NSException, NSRNullRemoteIDException, @"Should have been an exception getting instance route if nil remoteID");
STAssertThrowsSpecificNamed([smth routeForInstanceMethod:nil httpMethod:verb], NSException, NSRNullRemoteIDException, @"Should have been an exception getting instance route if nil remoteID");

smth.remoteID = [NSNumber numberWithInt:1];
STAssertThrowsSpecificNamed([smth routeForInstanceMethod:nil httpVerb:verb], NSException, NSRNullRemoteIDException, @"Should still crash, because 'empty' relation is nil");
STAssertThrowsSpecificNamed([smth routeForInstanceMethod:nil httpMethod:verb], NSException, NSRNullRemoteIDException, @"Should still crash, because 'empty' relation is nil");

smth.empty = [[Empty alloc] init];
STAssertThrowsSpecificNamed([smth routeForInstanceMethod:nil httpVerb:verb], NSException, NSRNullRemoteIDException, @"Should still crash, because 'empty' relation has a nil remoteID");
STAssertThrowsSpecificNamed([smth routeForInstanceMethod:nil httpMethod:verb], NSException, NSRNullRemoteIDException, @"Should still crash, because 'empty' relation has a nil remoteID");

smth.empty.remoteID = [NSNumber numberWithInt:15];

STAssertEqualObjects([smth routeForInstanceMethod:nil httpVerb:verb], @"empties/15/prefixers/1", @"Nil instance route failed");
STAssertEqualObjects([smth routeForInstanceMethod:@"action" httpVerb:verb], @"empties/15/prefixers/1/action", @"Instance route failed");
STAssertEqualObjects([smth routeForInstanceMethod:nil httpMethod:verb], @"empties/15/prefixers/1", @"Nil instance route failed");
STAssertEqualObjects([smth routeForInstanceMethod:@"action" httpMethod:verb], @"empties/15/prefixers/1/action", @"Instance route failed");


// Now double nested + custom names
Expand All @@ -418,12 +418,12 @@ - (void) test_routes_with_prefixes

NSRAssertEqualArraysNoOrder([smth2 NSRUseResourcePrefixMethods], NSRArray(@"GET", @"patch"));

STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpVerb:verb], NSException, NSRNullRemoteIDException, @"Should have been an exception getting instance route if nil remoteID");
STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpMethod:verb], NSException, NSRNullRemoteIDException, @"Should have been an exception getting instance route if nil remoteID");

smth2.remoteID = [NSNumber numberWithInt:15];

STAssertEqualObjects([smth2 routeForInstanceMethod:nil httpVerb:@"DELETE"], @"premans/15", @"Should be normal for non-included");
STAssertEqualObjects([smth2 routeForInstanceMethod:@"something" httpVerb:@"DELETE"], @"premans/15/something", @"Should be normal for non-included");
STAssertEqualObjects([smth2 routeForInstanceMethod:nil httpMethod:@"DELETE"], @"premans/15", @"Should be normal for non-included");
STAssertEqualObjects([smth2 routeForInstanceMethod:@"something" httpMethod:@"DELETE"], @"premans/15/something", @"Should be normal for non-included");

for (int i = 0; i < 2; i++)
{
Expand All @@ -436,24 +436,24 @@ - (void) test_routes_with_prefixes
smth2.thePrefixer = nil;

// Instance
STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpVerb:verb], NSException, NSRNullRemoteIDException, @"Should have been an exception getting instance route if nil remoteID");
STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpMethod:verb], NSException, NSRNullRemoteIDException, @"Should have been an exception getting instance route if nil remoteID");

smth2.remoteID = [NSNumber numberWithInt:1];
STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpVerb:verb], NSException, NSRNullRemoteIDException, @"Should still crash, because 'empty' relation is nil");
STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpMethod:verb], NSException, NSRNullRemoteIDException, @"Should still crash, because 'empty' relation is nil");

smth2.thePrefixer = [[Prefixer alloc] init];
STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpVerb:verb], NSException, NSRNullRemoteIDException, @"Should still crash, because 'empty' relation has a nil remoteID");
STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpMethod:verb], NSException, NSRNullRemoteIDException, @"Should still crash, because 'empty' relation has a nil remoteID");

smth2.thePrefixer.remoteID = [NSNumber numberWithInt:15];
STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpVerb:verb], NSException, NSRNullRemoteIDException, @"Should STILL crash, because 'thePrefixer' relation has a nil empty");
STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpMethod:verb], NSException, NSRNullRemoteIDException, @"Should STILL crash, because 'thePrefixer' relation has a nil empty");

smth2.thePrefixer.empty = [[Empty alloc] init];
STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpVerb:verb], NSException, NSRNullRemoteIDException, @"Should STILL crash, because 'thePrefixer' relation's empty has a nil remoteID");
STAssertThrowsSpecificNamed([smth2 routeForInstanceMethod:nil httpMethod:verb], NSException, NSRNullRemoteIDException, @"Should STILL crash, because 'thePrefixer' relation's empty has a nil remoteID");

smth2.thePrefixer.empty.remoteID = [NSNumber numberWithInt:23];

STAssertEqualObjects([smth2 routeForInstanceMethod:nil httpVerb:verb], @"empties/23/prefixers/15/premans/1", @"Nil instance route failed");
STAssertEqualObjects([smth2 routeForInstanceMethod:@"action" httpVerb:verb], @"empties/23/prefixers/15/premans/1/action", @"Instance route failed");
STAssertEqualObjects([smth2 routeForInstanceMethod:nil httpMethod:verb], @"empties/23/prefixers/15/premans/1", @"Nil instance route failed");
STAssertEqualObjects([smth2 routeForInstanceMethod:@"action" httpMethod:verb], @"empties/23/prefixers/15/premans/1/action", @"Instance route failed");
}
}

Expand Down

0 comments on commit 15d6be5

Please sign in to comment.