Added support for parser class specification by regular expression. closes #489

This commit is contained in:
Robert Altman
2012-01-02 13:44:39 -06:00
committed by Blake Watters
parent 53bbeca099
commit 99a108096f
3 changed files with 110 additions and 16 deletions

View File

@@ -22,39 +22,76 @@
#import "RKParser.h"
/**
The Parser Registry provides for the registration of RKParser classes
for a particular MIME Type. This enables
*/
RKParserRegistry provides for the registration of RKParser classes
that handle parsing/serializing for content by MIME Type. Registration
is configured via exact string matches (i.e. application/json) or via regular
expression.
*/
@interface RKParserRegistry : NSObject {
NSMutableDictionary *_MIMETypeToParserClasses;
NSMutableArray *_MIMETypeToParserClassesRegularExpressions;
}
/**
Return the global shared singleton registry for MIME Type to Parsers
@return The global shared RKParserRegistry instance.
*/
+ (RKParserRegistry *)sharedRegistry;
/**
Sets the global shared registry singleton to a new instance of RKParserRegistry
@param registry A new parser registry object to configure as the shared instance.
*/
+ (void)setSharedRegistry:(RKParserRegistry *)registry;
/**
Instantiate and return a Parser for the given MIME Type
Returns an instance of the RKParser conformant class registered to handle content
with the given MIME Type.
MIME Types are searched in the order in which they are registered and exact
string matches are favored over regular expressions.
@param MIMEType The MIME Type of the content to be parsed/serialized.
@return An instance of the RKParser conformant class registered to handle the given MIME Type.
*/
- (id<RKParser>)parserForMIMEType:(NSString *)MIMEType;
/**
Return the class registered for handling parser/encoder operations
for a given MIME Type
Returns an instance of the RKParser conformant class registered to handle content
with the given MIME Type.
MIME Types are searched in the order in which they are registered and exact
string matches are favored over regular expressions.
@param MIMEType The MIME Type of the content to be parsed/serialized.
@return The RKParser conformant class registered to handle the given MIME Type.
*/
- (Class<RKParser>)parserClassForMIMEType:(NSString *)MIMEType;
/**
Registers an RKParser conformant class as the handler for the specified MIME Type
Registers an RKParser conformant class as the handler for MIME Types exactly matching the
specified MIME Type string.
@param parserClass The RKParser conformant class to instantiate when parsing/serializing MIME Types matching MIMETypeExpression.
@param MIMEType A MIME Type string for which instances of parserClass should be used for parsing/serialization.
*/
- (void)setParserClass:(Class<RKParser>)parserClass forMIMEType:(NSString *)MIMEType;
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
/**
Registers an RKParser conformant class as the handler for MIME Types matching the
specified regular expression.
@param parserClass The RKParser conformant class to instantiate when parsing/serializing MIME Types matching MIMETypeExpression.
@param MIMETypeRegex A regular expression that matches MIME Types that should be handled by instances of parserClass.
*/
- (void)setParserClass:(Class<RKParser>)parserClass forMIMETypeRegularExpression:(NSRegularExpression *)MIMETypeRegex;
#endif
/**
Automatically configure the registry via run-time reflection of the RKParser classes
available that ship with RestKit. This happens automatically when the shared registry

View File

@@ -20,11 +20,11 @@
#import "RKParserRegistry.h"
RKParserRegistry* gSharedRegistry;
RKParserRegistry *gSharedRegistry;
@implementation RKParserRegistry
+ (RKParserRegistry*)sharedRegistry {
+ (RKParserRegistry *)sharedRegistry {
if (gSharedRegistry == nil) {
gSharedRegistry = [RKParserRegistry new];
[gSharedRegistry autoconfigure];
@@ -33,7 +33,7 @@ RKParserRegistry* gSharedRegistry;
return gSharedRegistry;
}
+ (void)setSharedRegistry:(RKParserRegistry*)registry {
+ (void)setSharedRegistry:(RKParserRegistry *)registry {
[registry retain];
[gSharedRegistry release];
gSharedRegistry = registry;
@@ -43,6 +43,7 @@ RKParserRegistry* gSharedRegistry;
self = [super init];
if (self) {
_MIMETypeToParserClasses = [[NSMutableDictionary alloc] init];
_MIMETypeToParserClassesRegularExpressions = [[NSMutableArray alloc] init];
}
return self;
@@ -50,18 +51,42 @@ RKParserRegistry* gSharedRegistry;
- (void)dealloc {
[_MIMETypeToParserClasses release];
[_MIMETypeToParserClassesRegularExpressions release];
[super dealloc];
}
- (Class<RKParser>)parserClassForMIMEType:(NSString*)MIMEType {
return [_MIMETypeToParserClasses objectForKey:MIMEType];
- (Class<RKParser>)parserClassForMIMEType:(NSString *)MIMEType {
id parserClass = [_MIMETypeToParserClasses objectForKey:MIMEType];
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
if (!parserClass)
{
for (NSArray *regexAndClass in _MIMETypeToParserClassesRegularExpressions) {
NSRegularExpression *regex = [regexAndClass objectAtIndex:0];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:MIMEType options:0 range:NSMakeRange(0, [MIMEType length])];
if (numberOfMatches) {
parserClass = [regexAndClass objectAtIndex:1];
break;
}
}
}
#endif
return parserClass;
}
- (void)setParserClass:(Class<RKParser>)parserClass forMIMEType:(NSString*)MIMEType {
- (void)setParserClass:(Class<RKParser>)parserClass forMIMEType:(NSString *)MIMEType {
[_MIMETypeToParserClasses setObject:parserClass forKey:MIMEType];
}
- (id<RKParser>)parserForMIMEType:(NSString*)MIMEType {
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
- (void)setParserClass:(Class<RKParser>)parserClass forMIMETypeRegularExpression:(NSRegularExpression *)MIMETypeRegex {
NSArray *expressionAndClass = [NSArray arrayWithObjects:MIMETypeRegex, parserClass, nil];
[_MIMETypeToParserClassesRegularExpressions addObject:expressionAndClass];
}
#endif
- (id<RKParser>)parserForMIMEType:(NSString *)MIMEType {
Class parserClass = [self parserClassForMIMEType:MIMEType];
if (parserClass) {
return [[[parserClass alloc] init] autorelease];
@@ -74,8 +99,8 @@ RKParserRegistry* gSharedRegistry;
Class parserClass = nil;
// JSON
NSSet* JSONParserClassNames = [NSSet setWithObjects:@"RKJSONParserJSONKit", @"RKJSONParserYAJL", @"RKJSONParserSBJSON", @"RKJSONParserNXJSON", nil];
for (NSString* parserClassName in JSONParserClassNames) {
NSSet *JSONParserClassNames = [NSSet setWithObjects:@"RKJSONParserJSONKit", @"RKJSONParserYAJL", @"RKJSONParserSBJSON", @"RKJSONParserNXJSON", nil];
for (NSString *parserClassName in JSONParserClassNames) {
parserClass = NSClassFromString(parserClassName);
if (parserClass) {
[self setParserClass:parserClass forMIMEType:RKMIMETypeJSON];

View File

@@ -53,4 +53,36 @@
assertThat(parser, is(instanceOf([RKXMLParserXMLReader class])));
}
- (void)testRetrievalOfExactStringMatchForMIMEType {
RKParserRegistry* registry = [[RKParserRegistry new] autorelease];
[registry setParserClass:[RKJSONParserJSONKit class] forMIMEType:RKMIMETypeJSON];
id<RKParser> parser = [registry parserForMIMEType:RKMIMETypeJSON];
assertThat(parser, is(instanceOf([RKJSONParserJSONKit class])));
}
- (void)testRetrievalOfRegularExpressionMatchForMIMEType {
RKParserRegistry *registry = [[RKParserRegistry new] autorelease];
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"application/xml\\+\\w+" options:0 error:&error];
[registry setParserClass:[RKJSONParserJSONKit class] forMIMETypeRegularExpression:regex];
id<RKParser> parser = [registry parserForMIMEType:@"application/xml+whatever"];
assertThat(parser, is(instanceOf([RKJSONParserJSONKit class])));
}
- (void)testRetrievalOfExactStringMatchIsFavoredOverRegularExpression {
RKParserRegistry *registry = [[RKParserRegistry new] autorelease];
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"application/xml\\+\\w+" options:0 error:&error];
[registry setParserClass:[RKJSONParserJSONKit class] forMIMETypeRegularExpression:regex];
[registry setParserClass:[RKXMLParserXMLReader class] forMIMEType:@"application/xml+whatever"];
// Exact match
id<RKParser> exactParser = [registry parserForMIMEType:@"application/xml+whatever"];
assertThat(exactParser, is(instanceOf([RKXMLParserXMLReader class])));
// Fallback to regex
id<RKParser> regexParser = [registry parserForMIMEType:@"application/xml+different"];
assertThat(regexParser, is(instanceOf([RKJSONParserJSONKit class])));
}
@end