Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue-89 - Add support for arrays in query parameters #98

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions DeepLinkKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
DEE40E5F1A42B0530097EA33 /* DPLActionDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE40E5D1A42ABE80097EA33 /* DPLActionDataSource.m */; };
DEE40E601A42B0580097EA33 /* DPLDemoAction.m in Sources */ = {isa = PBXBuildFile; fileRef = DEE40E581A42A3F50097EA33 /* DPLDemoAction.m */; };
DEEBD4A91AAB7946000BCA84 /* DPLSerializableObject.m in Sources */ = {isa = PBXBuildFile; fileRef = DEEBD4A81AAB7946000BCA84 /* DPLSerializableObject.m */; };
E9A189201CB6E6600029E56B /* DPLArrayRouteHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9A1891F1CB6E6600029E56B /* DPLArrayRouteHandler.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -190,6 +191,7 @@
DEEBD4A71AAB7946000BCA84 /* DPLSerializableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DPLSerializableObject.h; path = Fixtures/DPLSerializableObject.h; sourceTree = "<group>"; };
DEEBD4A81AAB7946000BCA84 /* DPLSerializableObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DPLSerializableObject.m; path = Fixtures/DPLSerializableObject.m; sourceTree = "<group>"; };
DF9272621ECB6C2824AD5C94 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ./LICENSE; sourceTree = "<group>"; };
E9A1891F1CB6E6600029E56B /* DPLArrayRouteHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DPLArrayRouteHandler.swift; sourceTree = "<group>"; };
E9CA1DB95577CF3689F4B77F /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ./README.md; sourceTree = "<group>"; };
EC3E153594BC11ACCA16FACF /* Pods_ReceiverDemoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ReceiverDemoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
FB774EA6D84A50233F032ADC /* Pods-ReceiverDemoSwift.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReceiverDemoSwift.test.xcconfig"; path = "Pods/Target Support Files/Pods-ReceiverDemoSwift/Pods-ReceiverDemoSwift.test.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -343,6 +345,7 @@
children = (
62EE96F31B570891003D7564 /* DPLProductRouteHandler.swift */,
62891E8A1B57FE5A00C2AF4F /* DPLMessageRouteHandler.swift */,
E9A1891F1CB6E6600029E56B /* DPLArrayRouteHandler.swift */,
);
path = RouteHandlers;
sourceTree = "<group>";
Expand Down Expand Up @@ -1076,6 +1079,7 @@
buildActionMask = 2147483647;
files = (
62EE96F61B570B10003D7564 /* DPLProductDataSource.m in Sources */,
E9A189201CB6E6600029E56B /* DPLArrayRouteHandler.swift in Sources */,
62EE96F51B570AF4003D7564 /* DPLProductDetailViewController.m in Sources */,
62335E031B57007F00E3818C /* DPLReceiverSwiftAppDelegate.swift in Sources */,
62891E8B1B57FE5A00C2AF4F /* DPLMessageRouteHandler.swift in Sources */,
Expand Down
28 changes: 28 additions & 0 deletions DeepLinkKit/Categories/NSString+DPLQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,32 @@
*/
- (NSString *)DPL_stringByReplacingPercentEscapesUsingEncoding:(NSStringEncoding)encoding;



///---------------------
/// @name Array Literals
///---------------------


/**
Checks if string ends with array literal ('[]')
@return YES if string ends with '[]', NO otherwise
*/
- (BOOL)DPL_containsArrayLiteral;


/**
Checks if string contains key with array literal
@return YES if string contains key with '[]' attached (e.g. "key[]"),
NO otherwise (e.g. "key")
*/
- (BOOL)DPL_containsArrayLiteralWithKey:(NSString *)key;


/**
Removes array literal ('[]') from the string
@return String without array literal ('[]')
*/
- (NSString *)DPL_removeArrayLiteral;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convention would indicate:
DPL_stringByRemovingArrayLiteral or something similar

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for noticing, will correct it shortly.

On Thursday, April 7, 2016, Chris Maddern [email protected] wrote:

In DeepLinkKit/Categories/NSString+DPLQuery.h
#98 (comment):

+- (BOOL)DPL_containsArrayLiteral;
+
+
+/**

  • Checks if string contains key with array literal
  • @return YES if string contains key with '[]' attached (e.g. "key[]"),
  •      NO otherwise (e.g. "key")
    
  • /
    +- (BOOL)DPL_containsArrayLiteralWithKey:(NSString *)key;
    +
    +
    +/
    *
  • Removes array literal ('[]') from the string
  • @return String without array literal ('[]')
  • */
    +- (NSString *)DPL_removeArrayLiteral;

Convention would indicate:
DPL_stringByRemovingArrayLiteral or something similar


You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
https://github.com/button/DeepLinkKit/pull/98/files/7cebc8717560a0a64fb675df53f041ef2e2d7acb#r58930895

Best regards,
Pavel Pantus


@end
74 changes: 67 additions & 7 deletions DeepLinkKit/Categories/NSString+DPLQuery.m
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
#import "NSString+DPLQuery.h"

static NSString * const DPL_ArrayLiteral = @"[]";

@implementation NSString (UBRQuery)

+ (NSString *)DPL_queryStringWithParameters:(NSDictionary *)parameters {
NSMutableString *query = [NSMutableString string];
[[parameters allKeys] enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop) {
NSString *value = [parameters[key] description];
key = [key DPL_stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
value = [value DPL_stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[query appendFormat:@"%@%@%@%@", (idx > 0) ? @"&" : @"", key, (value.length > 0) ? @"=" : @"", value];
NSString *value = @"";
if ([parameters[key] isKindOfClass:[NSArray class]]) {
NSString *keyValuePair = nil;
NSString *arrayValueString = nil;
for (NSString *arrayValue in parameters[key]) {
arrayValueString = [arrayValue.description DPL_stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
keyValuePair = [NSString stringWithFormat:@"%@[]=%@", key, arrayValueString];
keyValuePair = [NSString stringWithFormat:@"%@%@", (value.length > 0) ? @"&" : @"", keyValuePair];
value = [value stringByAppendingString:keyValuePair];
}
if (value.length == 0) {
value = [NSString stringWithFormat:@"%@[]", key];
}
key = @"";
}
else {
value = [parameters[key] description];
key = [key DPL_stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
value = [value DPL_stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
[query appendFormat:@"%@%@%@%@", (idx > 0) ? @"&" : @"", key, (value.length > 0 && key.length > 0) ? @"=" : @"", value];
}];
return [query copy];
}
Expand All @@ -23,12 +42,33 @@ - (NSDictionary *)DPL_parametersFromQueryString {
// e.g. ?key=value
NSString *key = [pairs[0] DPL_stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *value = [pairs[1] DPL_stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
paramsDict[key] = value;
if ([key DPL_containsArrayLiteral]) {
// e.g. ?items[]=item1&items[]=item2
key = [key DPL_removeArrayLiteral];
if (!paramsDict[key]) {
paramsDict[key] = @[value];
}
else {
paramsDict[key] = [paramsDict[key] arrayByAddingObject:value];
}
}
else {
paramsDict[key] = value;
}
}
else if (pairs.count == 1) {
// e.g. ?key
NSString *key = [[pairs firstObject] DPL_stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
paramsDict[key] = @"";
NSObject *value;
if ([key DPL_containsArrayLiteral]) {
// e.g. ?items[]
key = [key DPL_removeArrayLiteral];
value = @[];
}
else {
// e.g. ?key
value = @"";
}
paramsDict[key] = value;
}
}
return [paramsDict copy];
Expand All @@ -47,4 +87,24 @@ - (NSString *)DPL_stringByReplacingPercentEscapesUsingEncoding:(NSStringEncoding
return [self stringByRemovingPercentEncoding];
}


#pragma mark - Array Literals

- (BOOL)DPL_containsArrayLiteral {
return [self hasSuffix:DPL_ArrayLiteral];
}


- (BOOL)DPL_containsArrayLiteralWithKey:(NSString *)key {
return [self containsString:[NSString stringWithFormat:@"%@%@", key, DPL_ArrayLiteral]];
}


- (NSString *)DPL_removeArrayLiteral {
if ([self DPL_containsArrayLiteral]) {
return [self substringWithRange:NSMakeRange(0, self.length - DPL_ArrayLiteral.length)];
}
return [self copy];
}

@end
12 changes: 9 additions & 3 deletions DeepLinkKit/Regex/DPLRegularExpression.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#import "DPLRegularExpression.h"
#import "NSString+DPLQuery.h"

static NSString * const DPLNamedGroupComponentPattern = @":[a-zA-Z0-9-_][^/]+";
static NSString * const DPLRouteParameterPattern = @":[a-zA-Z0-9-_]+";
Expand Down Expand Up @@ -40,9 +41,14 @@ - (DPLMatchResult *)matchResultForString:(NSString *)str {
for (NSTextCheckingResult *result in matches) {
// Begin at 1 as first range is the whole match
for (NSInteger i = 1; i < result.numberOfRanges && i <= self.groupNames.count; i++) {
NSString *parameterName = self.groupNames[i - 1];
NSString *parameterValue = [str substringWithRange:[result rangeAtIndex:i]];
routeParameters[parameterName] = parameterValue;
NSString *parameterName = self.groupNames[i - 1];
NSString *parameterValue = [str substringWithRange:[result rangeAtIndex:i]];
if ([parameterValue DPL_containsArrayLiteralWithKey:parameterName]) {
routeParameters[parameterName] = [parameterValue DPL_parametersFromQueryString][parameterName];
}
else {
routeParameters[parameterName] = parameterValue;
}
}
}

Expand Down
15 changes: 15 additions & 0 deletions SampleApps/ReceiverDemo/DPLReceiverAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
[navController pushViewController:controller animated:NO];
};

self.router[@"shoppinglist/:list"] = ^(DPLDeepLink *link) {
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Shopping List", nil)
message:NSLocalizedString(@"Please buy the following:", nil)
preferredStyle:UIAlertControllerStyleActionSheet];
for (NSString *title in link[@"list"]) {
[actionSheet addAction:[UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:NULL]];
}
[actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:NULL]];
UIViewController *rootViewController = weakSelf.window.rootViewController;
if ([rootViewController.presentedViewController isKindOfClass:[UIAlertController class]]) {
[rootViewController dismissViewControllerAnimated:NO completion:NULL];
}
[rootViewController presentViewController:actionSheet animated:YES completion:NULL];
};

return YES;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class DPLReceiverSwiftAppDelegate: UIResponder, UIApplicationDelegate {

// Register a class to a route using object subscripting
self.router["/product/:sku"] = DPLProductRouteHandler.self

self.router["shoppinglist/:list"] = DPLArrayRouteHandler.self

// Register a class to a route using the explicit registration call
self.router.registerHandlerClass(DPLMessageRouteHandler.self, forRoute: "/say/:title/:message")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation

public class DPLArrayRouteHandler: DPLRouteHandler {
public override func shouldHandleDeepLink(deepLink: DPLDeepLink!) -> Bool {
if let list = deepLink["list"] as? Array<String> {
let alertController = UIAlertController(title: NSLocalizedString("Shopping List", comment: ""),
message: NSLocalizedString("Please buy the following:", comment: ""),
preferredStyle: .ActionSheet)
for title in list {
alertController.addAction(UIAlertAction(title: title, style: .Default, handler: nil))
}
alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)
}
return false
}
}
14 changes: 13 additions & 1 deletion SampleApps/SenderDemo/ActionData/DPLActionDataSource.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ - (instancetype)init {
if (self) {
_actions = @[[self loadBeersAction],
[self loadOktoberfestAction],
[self logHelloWorldAction]];
[self logHelloWorldAction],
[self logShoppingList]];
}
return self;
}
Expand Down Expand Up @@ -74,4 +75,15 @@ - (DPLDemoAction *)logHelloWorldAction {
return action;
}


- (DPLDemoAction *)logShoppingList {
DPLMutableDeepLink *link = [[DPLMutableDeepLink alloc] initWithString:@"dpl://shoppinglist"];
link.path = @"/list[]=Bread&list[]=Candies&list[]=Wine&list[]=Beer";

DPLDemoAction *action = [[DPLDemoAction alloc] init];
action.actionURL = link.URL;
action.actionName = @"Print: Shopping List";
return action;
}

@end
Loading