Giter VIP home page Giter VIP logo

jlroutes's People

Contributors

antons avatar berg avatar calebd avatar ejensen avatar inacioferrarini avatar jakemarsh avatar javisoto avatar jcampbell05 avatar jessedc avatar joeldev avatar joeldevjcp avatar juantri94 avatar klaaspieter avatar lickel avatar martijnthe avatar maximveksler avatar min avatar nolanw avatar orta avatar philipengberg avatar pietbrauer avatar ravelantunes avatar sascha-wolf avatar speednoisemovement avatar stevestreza avatar wlisac avatar zats avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jlroutes's Issues

myapp://web/:URLString doesn't work

I defiend myapp://web/:URLString
URLString will be URLencoded before,
it would be myapp://web/http%3A%2F%2Fbaidu.com
but it's broken in pathComponents parsing. The encoded url would be split.
See your code, pathComponents would be web, http:, baidu.com

JLRoutes.m line:370
    // break the URL down into path components and filter out any leading/trailing slashes from it
    NSArray *pathComponents = [(URL.pathComponents ?: @[]) filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"NOT SELF like '/'"]];

    if ([URL.host rangeOfString:@"."].location == NSNotFound) {
        // For backward compatibility, handle scheme://path/to/ressource as if path was part of the
        // path if it doesn't look like a domain name (no dot in it)
        pathComponents = [@[URL.host] arrayByAddingObjectsFromArray:pathComponents];
}

Do you have an official way in your mind of this ?

Adding a route with nonzero priority fails if there are no routes yet

Given a JLRoutes instance router, the following lines of code result in no routes being added to the router:

router.addRoute("/:entityType/id/:id", priority: 20, handler: handler)
router.addRoute("/:entityType/open-modal/:id", priority: 10, handler: handler)
router.addRoute("/:entityType/:id", priority: 1, handler: handler)

This problem occurs in -addRoute:priority:handler:, specifically:

    if (priority == 0) {
        [self.routes addObject:route];
    } else {
        NSArray *existingRoutes = self.routes;
        NSUInteger index = 0;
        for (_JLRoute *existingRoute in existingRoutes) {
            if (existingRoute.priority < priority) {
                [self.routes insertObject:route atIndex:index];
                break;
            }
            index++;
        }
    }

Seeing that we're adding a route with a nonzero priority, we enter the else part of that logic, which is supposed to iterate over existing routes and insert the new route just ahead of the first route of lower priority. But since this is the first route we're trying to add there's nothing in existingRoutes, so we never enter the for loop and the route is never added.

This could be fixed by changing the conditional to read if (priority == 0 || self.routes.count == 0).

JLRoutes 2.0.3 doesn't support host as parameter

Is it possible to switch between the possibility to keep the host as parameter?
This because this minor release affects all the app are using it with this behaviour.
I can suggest a pull request if you want.

Best practice for routes with navigation controllers?

Do you have any recommendation for how to use JLRoutes with navigation controllers?

Imagine you have something like a UserProfileViewController, it takes a user_id param and you want to launch it from many different parts of the interface in your app. Sometimes it's presented modally, other times pushed onto a navigation controller.

You've got a route for /users/:user_id, how would you recommend making UserProfileViewController get pushed from the top-most navigation controller?

For now I've added a param "useNavigationController," and added code in the route handler to try to find the top-most view controller and check if it's a navigation controller. This is not very elegant, though, and I realize it's brittle.

I've seen some other routing libraries take explicit navigation controller arguments in the call to handleRoute(https://github.com/aaronbrethorst/ABRouter#in-your-parent-view-controllers). I'm not sure that's the right way, either, though.

Have you encountered this or do you have any thoughts on this?

Static analysis fails: possible nil added to dictionary

JLRoutes.m line 112:

variables[variableName] = [variableValue JLRoutes_URLDecodedString];

The static analyzer claims that variableValue could be nil, which would lead to nil being added to a dictionary, which is illegal.

Don't be shy about supporting carthage

Hey guys,

Just writing to let you know that carthage works great with your repo setup, so it's a quick win to let people know they can use it.

All you have to do is add

github "joeldev/JLRoutes" to your Cartfile and bam, now this happens:

➜  finder-ios git:(master) ✗ carthage update
*** Cloning JLRoutes
*** Checking out JLRoutes at "1.5.5"
*** Building scheme "JLRoutes-iOS" in JLRoutes.xcodeproj

GET parameters not parsed?

The following URL: transit://routes?ll=45.5391,-73.5997 (as received by application:openURL:)

Outputs a nil parameters dictionary...

[JLRoutes addRoute:@"/routes" handler:^BOOL(NSDictionary *parameters) {
    // parameters is nil
    return YES;
}];

Am I missing something? The read me does say JLRoutes parses GET parameters.

URL.host is added as path component and prevents route matching

I have this route setup:

[JLRoutes addRoute:@"/playeractivation" handler:^BOOL(NSDictionary *parameters) {...}

The incoming URL (universal links) is this: https://websitename.rs/[email protected]&code=123142

Everything goes until line 518 in JLRoutes.m :

    if (URL.host.length > 0 && ![URL.host isEqualToString:@"localhost"]) {
        // For backward compatibility, handle scheme://path/to/ressource as if path was part of the
        // path if it doesn't look like a domain name (no dot in it)
        pathComponents = [@[URL.host] arrayByAddingObjectsFromArray:pathComponents];
    }

This piece of code picks up the websitename.rs and adds it to the existing playeractivation (which is the only path component).
Thus, when it later gets in line 173, to this:

    BOOL componentCountEqual = patternComponents.count == components.count;
    BOOL patternContainsWildcard = [patternComponents containsObject:@"*"];
    if (componentCountEqual || patternContainsWildcard) {

That first boolean is NO, because components has two elements and patternComponents has only one (which is correct).

What's the purpose of that block above?

The comment says:

        // For backward compatibility, handle scheme://path/to/ressource as if path was part of the
        // path if it doesn't look like a domain name (no dot in it)

but it never actually checks for the existence of the . in the URL.host, it just blindly adds it.

Routing for both http and https

Hi

In general: how can I setup a route for a scheme by pattern?

More specifically: I want to have same routes for 'http' and 'https' (used internally), but I would like to not define the routes twice. Is that possible?

URLs aren't parsed correctly

You should be using NSURL's path property instead trying to parse the URL's path from the absoluteString. In your README you use myapp://user/view/joeldev as an example URL, with two slashes. With a valid URL parser, user would be parsed as the host component and shouldn't be part of the path. A valid example would be either myapp:/user/view/joeldev or myapp:///user/view/joeldev to omit the host part, but such example wouldn't be matched.

Not using NSURL prevents your lib from handling smart ad banners transmitted URL correctly. You often pass the full URL with domain of the site as parameter in such cases.

I can submit a pull request if you want.

"unmatchedURLHandler" gets called for "canRouteURL"

When calling canRouteURL the unmatchedURLHandler gets called if no handler can be found. In the unmatchedURLHandler it's not possible to distinguish between a genuine attempt to open the URL or a check if the URL can be routed.

Missing parameters still fire routes

This is a bit difficult to explain so I'll just use examples. I have a route setup for /users/:user_id which is triggered by the URL app://users/ but not app://users. In the first case, the paramter for user_id is /. It would be nice to see /users and /users/ be treated the same as neither pass the target route.

Add pre-compiled framework to the release for Carthage

Hi,
I think a lot of JLRoutes projects are using CircleCI, or similar to build builds
If you can attach the pre-compiled framework: JLRoutes.framework.zip to the release, this will save tons of CircleCI building time.
Thanks,
Wei

Optional parameters

Hi

In this example the article is an optional parameter.

  open/edition/:editionId
  open/edition/:editionId/article/:articleId

In kohana in php I can setup optional stuff by adding some paranthesis. Like this

  open/edition/:editionId(/article/:articleId)

Ability to register regex url pattern

Could JLRoutes add the regex match? Sometimes I want to register regex pattern like ^..test.com/. . Then I can handle the specific url like m.test.com, h5.test.com etc .

Route aliasing

In order to gracefully handle backwards compatibility, it would be great if you could add a route alias during the transitioning period between route changes.

So if in an old version the profile deeplinking route was /profile/:username and in a later version is /user/:username, one would have to have to support both routes in the transitioning period until the old route can be deprecated. This means that you would have to have the exact same handler for two different routes:

[JLRoutes addRoute:@"/profile/:username" handler:^BOOL(NSDictionary *parameters) {
    // Show profile
    return YES;
}];

[JLRoutes addRoute:@"/user/:username" handler:^BOOL(NSDictionary *parameters) {
    // Show profile
    return YES;
}];

Instead it would be nice to be able to do something like:

[JLRoutes addAlias:@"/profile/:username" forRoute:@"/user/:username"];

resulting in the /user/:username handler being invoked for the /profile/:username route.

I know that one could just factor this functionality out into an external method, but it would be a much appreciated feature nonetheless.

`addRoute…` is annotated have block parameters NSDictionary<String *, String *> but isn't

The addRoute method is declared like:

+ (void)addRoute:(NSString *)routePattern handler:(BOOL (^__nullable)(NSDictionary<NSString *, NSString *> *parameters))handlerBlock;

However, the parameters it passes include:

  • kJLRouteNamespaceKey which can be [NSNull null]
  • kJLRouteURLKey which is an NSURL

These cause a crash when trying to convert into a [String: String] (in Swift) that looks like…

* thread #1: tid = 0xbbf578, 0x000000010cb4855f libswiftCore.dylib`swift_bridgeNonVerbatimFromObjectiveC + 255, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
    frame #0: 0x000000010cb4855f libswiftCore.dylib`swift_bridgeNonVerbatimFromObjectiveC + 255
    frame #1: 0x000000010cb43f70 libswiftCore.dylib`deallocateBuffer value witness for Swift.LazyMapCollection + 16
    frame #2: 0x000000010ce63da1 libswiftFoundation.dylib`Swift._forceBridgeFromObjectiveC <A> (Swift.AnyObject, A.Type) -> A + 385
    frame #3: 0x000000010ce63b80 libswiftFoundation.dylib`static (extension in Foundation):Swift.Dictionary.(_forceBridgeFromObjectiveC (__ObjC.NSDictionary, result : inout Swift.Optional<Swift.Dictionary<A, B>>) -> ()).(closure #1) + 144
    frame #4: 0x000000010ce60624 libswiftFoundation.dylib`partial apply forwarder for static (extension in Foundation):Swift.Dictionary.(_forceBridgeFromObjectiveC (__ObjC.NSDictionary, result : inout Swift.Optional<Swift.Dictionary<A, B>>) -> ()).(closure #1) + 100
    frame #5: 0x000000010bd681e6 CoreFoundation`__65-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 102
    frame #6: 0x000000010bd680af CoreFoundation`-[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:] + 159
    frame #7: 0x000000010ce4fb4e libswiftFoundation.dylib`static (extension in Foundation):Swift.Dictionary._forceBridgeFromObjectiveC (__ObjC.NSDictionary, result : inout Swift.Optional<Swift.Dictionary<A, B>>) -> () + 558
    frame #8: 0x000000010ce4f87b libswiftFoundation.dylib`Foundation._convertNSDictionaryToDictionary <A, B where A: Swift.Hashable> (Swift.Optional<__ObjC.NSDictionary>) -> Swift.Dictionary<A, B> + 75
    frame #9: 0x00000001046ba40d Imgur`thunk + 77 at Routing.swift:0
  * frame #10: 0x0000000108461954 JLRoutes`+[JLRoutes routeURL:withController:parameters:executeBlock:](self=JLRoutes, _cmd="routeURL:withController:parameters:executeBlock:", URL="aaaaaa -- mgur://imgur.com", routesController=0x00007f8b14d20ae0, parameters=0x0000000000000000, executeBlock=YES) + 2740 at JLRoutes.m:551

The key is definitely an NSString but the values are not.

Add more view controller awareness

One of the things that's still kind of unclear how to implement is the common pattern of handling a route by showing a new view controller (such as to view a user profile). A lot can be done to improve on that.

Possible mutation of self.routes during routeURL if route is added at the same time

This one gets me from time to time, as the process of routing a URL ends up adding a route elsewhere, and the outcome is always "fun".

routeURL:withParameters:executeRouteBlock: uses fast enumeration of self.routes to match for a valid route handler.

However, while this enumeration is happening, register or remove methods may be called which will modify the mutable array of self.routes.

I suggest that in routeURL:withParameters:executeRouteBlock: you first copy self.routes to an immutable NSArray and use that to enumerate the routes contained.

You'd be protected against the dreaded Collection <__NSArrayM: 0x17405dc70> was mutated while being enumerated. error.

Thank you. Keep up the good work,

Brian M. Criscuolo
warmwinds software

Add app using JLRoutes

I recently shipped an update to my app, Simple In/Out, that uses your library to do the URL handling. I was manually doing it before, but your library was much easier to setup and maintain. So thank you very much. Feel free to list my app as using your library. As soon as I get my attribution page working, I will definitely list your work there. Thanks!

Wildcard in pattern, failures and crashes

Here are some additional cases to consider for wildcarding. In one or two cases the failure may be my misunderstanding of how it should work. Probably the crashes shouldn't happen even if I am misunderstanding.

Thank you
Doug

- (void)testAdditionalWildcard1 {

    // add a wildcard with a preceding path component
    [JLRoutes addRoute:@"/xyz/wildcard/*" handler:^BOOL(NSDictionary *parameters) {
        testsInstance.lastMatch = parameters;
        return YES;
    }];

    /*
     This causes parameters to be:

     {
     "" = wildcard;
     JLRouteNamespace = JLRoutesGlobalNamespace;
     JLRoutePattern = "/:";
     JLRouteURL = "tests://wildcard";
     }

     consequently parameter count is 1 not 0

     I don't know if that is right or not
     */
   [self route:@"tests://wildcard"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(0);
}

- (void)testAdditionalWildcard2 {

    // add a wildcard with a preceding path component
    [JLRoutes addRoute:@"/xyz/wildcard/*" handler:^BOOL(NSDictionary *parameters) {
        testsInstance.lastMatch = parameters;
        return YES;
    }];

    /*
     Crashes:

     Test Case '-[JLRoutesTests testAdditionalWildcard]' started.
     2014-03-08 08:37:31.806 otest[31234:303] *** Routing tests://xyz/wildcard
     2014-03-08 08:37:31.806 otest[31234:303] [JLRoutes]: Trying to route URL tests://xyz/wildcard
     2014-03-08 08:37:31.806 otest[31234:303] [JLRoutes]: Parsed query parameters: (null)
     2014-03-08 08:37:31.807 otest[31234:303] [JLRoutes]: Parsed fragment parameters: (null)
     2014-03-08 08:37:31.810 otest[31234:303] [JLRoutes]: URL path components: (
     xyz,
     wildcard
     )
     Unknown.m:0: error: -[JLRoutesTests testAdditionalWildcard] : *** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]
     Test Case '-[JLRoutesTests testAdditionalWildcard]' failed (0.005 seconds).

     */
   [self route:@"tests://xyz/wildcard"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
}

- (void)testAdditionalWildcard3 {

    // add a wildcard with a preceding path component
    [JLRoutes addRoute:@"/xyz/wildcard/*" handler:^BOOL(NSDictionary *parameters) {
        testsInstance.lastMatch = parameters;
        return YES;
    }];

    /*
     Crashes:

     Test Case '-[JLRoutesTests testAdditionalWildcard]' started.
     2014-03-08 08:45:44.735 otest[31708:303] *** Routing tests://xyz/wildcard/
     2014-03-08 08:45:44.735 otest[31708:303] [JLRoutes]: Trying to route URL tests://xyz/wildcard/
     2014-03-08 08:45:44.735 otest[31708:303] [JLRoutes]: Parsed query parameters: (null)
     2014-03-08 08:45:44.736 otest[31708:303] [JLRoutes]: Parsed fragment parameters: (null)
     2014-03-08 08:45:44.739 otest[31708:303] [JLRoutes]: URL path components: (
     xyz,
     wildcard
     )
     Unknown.m:0: error: -[JLRoutesTests testAdditionalWildcard] : *** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]
     Test Case '-[JLRoutesTests testAdditionalWildcard]' failed (0.005 seconds).

     */
    [self route:@"tests://xyz/wildcard/"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
}

- (void)testAdditionalWildcard4 {

    // add a wildcard with a preceding path component
    [JLRoutes addRoute:@"/xyz/wildcard/*" handler:^BOOL(NSDictionary *parameters) {
        testsInstance.lastMatch = parameters;
        return YES;
    }];

   [self route:@"tests://xyz/wildcard/matches/with/extra/path/components"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    NSArray *wildcardMatches = @[@"matches", @"with", @"extra", @"path", @"components"];
    JLValidateParameter(@{kJLRouteWildcardComponentsKey: wildcardMatches});
}

Typed parameters

Currently all parsed params come in as strings. While that's useful a lot of the time, there are still probably some cases where the developer has to convert it to, for example, a number.

In the interest of helping people not have to write that extra bit of code, I'd like to find some nice way to encode types in the route pattern string.

Instead of:
/post/view/:postID

It could be (this format is by no means final and only meant to illustrate the concept):
/post/view/:[postID:number]

JLRoutes would see that postID is declared as a number and just give you an NSNumber for that key instead of an NSString.

There is probably some set list of types where this makes any sense at all whatsoever.

Crash on iOS 7.x

JLRRouteRequest Line 81
@property (nullable, copy) NSArray<NSURLQueryItem *> *queryItems NS_AVAILABLE(10_10, 8_0);

Cause Crash on device with iOS 7.x

[JLRoutes routesForScheme:@"My"] addRoute:@"/8888.com/go/main" 无法解析,问题出在.com上

NSURL *url = [NSURL URLWithString:@"My://8888.com/go/main?tab=member_cente"];
if (![[UIApplication sharedApplication] canOpenURL: url]) return NO;

[[UIApplication sharedApplication] openURL:url];
[ [JLRoutes routesForScheme:@"My"] addRoute:@"/8888.com/go/main" handler:^BOOL(NSDictionary *parameters) {
// 这里不执行
return YES;
}];

以下代码拷贝自上面,只是将8888.com改成了8888,但上面的无法进入block,下面的就可以

NSURL *url = [NSURL URLWithString:@"My://8888/go/main?tab=member_cente"];
if (![[UIApplication sharedApplication] canOpenURL: url]) return NO;

[[UIApplication sharedApplication] openURL:url];
[ [JLRoutes routesForScheme:@"My"] addRoute:@"/8888/go/main" handler:^BOOL(NSDictionary *parameters) {
// 但这个就执行
return YES;
}];
有什么办法解决吗?

Ability to query routes

It would be nice if you could query JLRoutes for all the currently registered routes, and then generate, for example, a testing UI that provides easy links to all the routes in the app.

Matching routes using Swift

I am working on a Swift project for OSX.

I am creating a filter object and using it to determine if a URL matches a route.

In AppDelegate.swift

    func applicationDidFinishLaunching(aNotification: NSNotification?)
    {
        let logging = Logging()
        logging.addRoute("/banana")
        server.filterChain.add(logging)

        server.filterChain.add(ErrorPage())
        server.filterChain.add(Nothing())

        startServer(self)
    }

In Filter.swift (base class for all filter objects)

    func addRoute(route:String)
    {
        if !routes
        {
            var classname = NSString(UTF8String: object_getClassName(self))
            routes = JLRoutes(forScheme: classname)
        }

        routes!.addRoute(route, handler: { parameters in return (true as ObjCBool)} )
    }

Also from Filter.swift (base class for all filter objects)

    func processFilter(connection:Connection)
    {
        if !routes || routes!.canRouteURL(connection.request!.URL)
        {
            processRequest(connection)
        }

It looks like JLRoutes is getting the correct URL, but is not matching the route and returning NO.

Verbose logging from JLRoutes

2014-07-19 15:21:38.820 SwiftServeDemo[55655:303] [JLRoutes]: Could not find a matching route, returning NO
2014-07-19 15:21:38.821 SwiftServeDemo[55655:303] [JLRoutes]: Trying to route URL /banana -- http://localhost:3333/
2014-07-19 15:21:38.821 SwiftServeDemo[55655:303] [JLRoutes]: Parsed query parameters: (null)
2014-07-19 15:21:38.822 SwiftServeDemo[55655:303] [JLRoutes]: Parsed fragment parameters: (null)
2014-07-19 15:21:38.822 SwiftServeDemo[55655:303] [JLRoutes]: URL path components: (
    localhost,
    banana
)
2014-07-19 15:21:38.822 SwiftServeDemo[55655:303] [JLRoutes]: Could not find a matching route, returning NO

However, switching the pattern to the /* route does match.

2014-07-19 15:30:04.723 SwiftServeDemo[56074:303] [JLRoutes]: Successfully matched JLRoute /* (0)
2014-07-19 15:30:04.725 SwiftServeDemo[56074:303] [JLRoutes]: Trying to route URL /banana -- http://localhost:3333/
2014-07-19 15:30:04.725 SwiftServeDemo[56074:303] [JLRoutes]: Parsed query parameters: (null)
2014-07-19 15:30:04.725 SwiftServeDemo[56074:303] [JLRoutes]: Parsed fragment parameters: (null)
2014-07-19 15:30:04.725 SwiftServeDemo[56074:303] [JLRoutes]: URL path components: (
    localhost,
    banana
)
2014-07-19 15:30:04.726 SwiftServeDemo[56074:303] [JLRoutes]: Successfully matched JLRoute /* (0)

Any suggestions? Thanks much.

Does it work with react native ?

could you please give me example, how JLRoutes works with react native. i am aiming to route within the app (one view to other view)

Empty variables

I’ve been playing around with the internals to see if I can get a hacky implementation going for what I want, but I’m not having much success.

My use case is as follows:

myapp://value1
myapp:///value2
myapp://value1/value2

I’m abusing the ‘domain’/host portion of the URL, but the point here is that value1 and value2 are always significant to me, even (especially) if one or the other is empty.

I was attempting to use this routing setup:

[JLRoutes addRoute: @"/:value1/:value2" handler: handlerBlock];
[JLRoutes addRoute: @"//:value2" handler: handlerBlock];
[JLRoutes addRoute: @"/:value1" handler: handlerBlock];

And work around any edges in my handler block, but the latter two routes don’t yield the results I thought they would. The extra slash is just being dropped, so the latter two routes are effectively the same thing, meaning when only one value is present, I don’t know which one it is.

What I’d like to be receiving from the first route, when one of the values is omitted, is NSNull. (nil is a no-go because the results are returned via NSArray, of course.)

The roadblocks I’m hitting are:

  1. In +routeURL:withController:, the URL.pathComponents array is filtered of any elements containing just a slash. I’m not familiar enough with NSPredicate to know how, but I believe a predicate/other solution which just removes preceding and trailing slashes, and not any element containing only a slash, would fulfill the requirements of the comment preceding that line ;), as well as enable my desired functionality, without breaking anything.
    In the same method, the code that prepends the URL.host to the component array for compatibility would also need to be aware of this functionality.
  2. Since the ‘normal’ use case is not to need empty values, I think it makes sense to make this functionality opt-in. In my hacked-together-but-not-working code, I was prepending my variables with a tilde (/~:value) to try to indicate to -parametersForURL:components: that the value I was looking for can also be empty. Unfortunately, making it opt-in means that some more complexity may be needed in +routeURL:withController: as part of the initial parsing.

Unsupported special characters

I have this url:
example://query?test=sp%E8cial

However JLRoutes is unable to parse the test parameter because of the "%E8" character.

Is there any way to support special characters?

To workaround this issue, I had to modify the JLRoutes_URLDecodedString method because it is returning NULL.

Better query parsing

It would be awesome if you switched to CMDQueryStringSerialization by @calebd 😄

For example:

key=1&key=2&text=hi

JLRoutes gives:

{ key=2, text=hi }

CMDQueryStringSerialization gives:

{ key=[1, 2], text=hi }

which is correct according to RFC number whatever. Currently, in all of my routes, I'm doing this:

NSString *queryString = [parameters[@"JLRouteURL"] query];
NSDictionary *params = [CMDQueryStringSerialization dictionaryWithQueryString:queryString];

when i want to add optional routes , it will add extra.

in the function
- (void)addRoute:(NSString *)routePattern priority:(NSUInteger)priority handler:(BOOL (^)(NSDictionary *parameters))handlerBlock;
if you pass argument with /user/:userId(/post/:postId)(/reply/:replyId), it will register the following routes:

/user/:userId/post/:postId/reply/:replyId
/user/:userId/post/:postId/
/user/:userId/post/:postId/
/user/:userId

not:

/user/:userId/post/:postId/reply/:replyId
/user/:userId/post/:postId/
/user/:userId

I think the function can be written like this?:

- (void)addRoute:(NSString *)routePattern priority:(NSUInteger)priority handler:(BOOL (^)(NSDictionary *parameters))handlerBlock {
    // if there's a pair of parenthesis, process optionals, trim the parenthesis, put it on trimmedRoute
    NSString *trimmedRoute = routePattern;
    // repeat until no parenthesis pair is found
    while ([trimmedRoute rangeOfString:@")" options:NSBackwardsSearch].location > [trimmedRoute rangeOfString:@"(" options:NSBackwardsSearch].location) {
        //Build route with the optionals
        NSString *patternWithOptionals = [trimmedRoute stringByReplacingOccurrencesOfString:@"(" withString:@""];
        patternWithOptionals = [patternWithOptionals stringByReplacingOccurrencesOfString:@")" withString:@""];
        [self registerRoute:patternWithOptionals priority:priority handler:handlerBlock];

        //Build route without optionals
        NSRange rangeOfLastParentheses = [trimmedRoute rangeOfString:@"(" options:NSBackwardsSearch];
        NSRange rangeToRemove = NSMakeRange(rangeOfLastParentheses.location, trimmedRoute.length - rangeOfLastParentheses.location);
        NSString *patternWithLastOptionalRemoved = [trimmedRoute stringByReplacingCharactersInRange:rangeToRemove withString:@""];
        //Remove any parenthesis for other optionals that might still be in the route
//        NSString *patternWithoutOptionals = [patternWithLastOptionalRemoved stringByReplacingOccurrencesOfString:@"(" withString:@""];
//        patternWithoutOptionals = [patternWithoutOptionals stringByReplacingOccurrencesOfString:@")" withString:@""];
//        [self registerRoute:patternWithoutOptionals priority:priority handler:handlerBlock];
        trimmedRoute = patternWithLastOptionalRemoved;
    }
    //Only register original route if trimmedRoute haven't been modified.
    if (trimmedRoute == routePattern) {
        [self registerRoute:routePattern priority:priority handler:handlerBlock];
    }else{
        [self registerRoute:trimmedRoute priority:priority handler:handlerBlock];
    }
}

what do you think about it ?

Scheme namespaces

JLRoutes should support per-scheme routes. This would allow for schemes to be used as namespaces. For example:

The URLs myapp-foo://some/route and myapp-bar://some/route could be handled in independent blocks, despite being the same route. Without this feature, you'd have to pull out the scheme from the URL and handle the two branches yourself.

This needs a good simple API that doesn't make the current API awkward, which is the only reason I'm writing up an issue for it now instead of just coding it up.

Percent encoding: here's a test case with a couple failures

I'm having problems with quoting slash (/) and plus (+). I looked at the code a bit; the problem seems to be pathComponents doing some unquoting. I think this is why Apple have now introduced NSURLComponents, but that doesn't help if you want to be compatible with older versions. Here's a test case you can drop into your test .m file to demonstrate:

- (void)testPercentEncoding {
    /*
     from http://en.wikipedia.org/wiki/Percent-encoding
     !   #   $   &   '   (   )   *   +   ,   /   :   ;   =   ?   @   [   ]
     %21 %23    %24 %26 %27 %28 %29 %2A %2B %2C %2F %3A %3B %3D %3F %40 %5B %5D
     */

    [self route:@"tests://user/view/joel%21levin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel!levin"});

    [self route:@"tests://user/view/joel%23levin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel#levin"});

    [self route:@"tests://user/view/joel%24levin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel$levin"});

    [self route:@"tests://user/view/joel%26levin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel&levin"});

    [self route:@"tests://user/view/joel%27levin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel'levin"});

    [self route:@"tests://user/view/joel%28levin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel(levin"});

    [self route:@"tests://user/view/joel%29levin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel)levin"});

    [self route:@"tests://user/view/joel%2Alevin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel*levin"});

    /*
     Fails: tries to match 'joel levin' with 'joel+levin'
     */
    [self route:@"tests://user/view/joel%2Blevin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel+levin"});

    [self route:@"tests://user/view/joel%2Clevin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel,levin"});

    /*
     Fails: tries to match (null) with 'joel/levin'
     */
    [self route:@"tests://user/view/joel%2Flevin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel/levin"});

    [self route:@"tests://user/view/joel%3Alevin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel:levin"});

    [self route:@"tests://user/view/joel%3Blevin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel;levin"});

    [self route:@"tests://user/view/joel%3Dlevin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel=levin"});

    [self route:@"tests://user/view/joel%3Flevin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel?levin"});

    [self route:@"tests://user/view/joel%40levin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel@levin"});

    [self route:@"tests://user/view/joel%5Blevin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel[levin"});

    [self route:@"tests://user/view/joel%5Dlevin"];
    JLValidateAnyRouteMatched();
    JLValidateParameterCount(1);
    JLValidateParameter(@{@"userID": @"joel]levin"});

}

JLRoutes 2.0.2 doesn't support multiple hosts

In JLRRouteRequest:

NSURLComponents *components = [NSURLComponents componentsWithString:[self.URL absoluteString]];
if (components.host.length > 0 && ![components.host isEqualToString:@"localhost"]) {
    // convert the host to "/" so that the host is considered a path component
    NSString *host = [components.percentEncodedHost copy];
    components.host = @"/";
    components.percentEncodedPath = [host stringByAppendingPathComponent:(components.percentEncodedPath ?: @"")];
}

This doesn't allow for a support of a variety of hosts. For example, I've tested with:

https://www.mydomain.com/path/3 and https://www.mydomain-test.com/path/3 and these resolve to paths that are www.mydomain.com/path/3 and mydomain-test.com/path/3, which means if I add a route for /path/:pathid nothing matches, since it's trying to match on a path that includes the domain as well.

I haven't seen a workaround for this, but needing to support multiple hosts, this is a breaking change after updating from 1.6.3.

I don't want to submit a PR in case there's a reason for this change, so would like to know why the path is overridden to include the host?

"+" in Query parameters

I have a deeplink where the URL uses the "+" symbol to indicate spaces. Not only in the path, but also in the query part.

For example:
...myBaseURL/invitations/hXVzNLTySmb4TGDL2yxR/accept?invitation_email=daan%40example.com&list_name=Test2+%F0%9F%98%82+%2BHans&actor_name=Daan+De+Boer

Now the NSDictionary *parameters in the handler still contain those "+" symbols instead of being replaced with spaces. So I added this code in my application:continueUserActivity:restorationHandler: method:

NSString *changedURL = [[userActivity.webpageURL absoluteString] stringByReplacingOccurrencesOfString:@"+" withString:@"%20"]; NSURL *outputURL = [NSURL URLWithString:changedURL]; return [JLRoutes routeURL:outputURL];

In my opinion JLRoutes should take care of this, or am I missing something?

Multiple optional routes result in unexpected behavior

:thing/path/:anotherthing(/new)(/anotherpath/:athirdthing)

Results in the unmatched handler being called for:

http://url.com/path/12345/anotherpath/54321

This path should be handled in the case where (/new) is optionally omitted, but it is not.

Defining the route as two separate routes manually including and not including /new in the path results in expected behavior.

Add a New Tag for CocoaPods

Hi Joel,

I would like to use the new features of JLRoutes, but CocoaPods' version of JLRoutes is 3 months older than the current version. I would like to avoid pointing my Podfile to a specific commit.

Can you add a new tag for the latest stable commit JLRoutes?

Thanks,
Trung

JLRoutes 1.5 podspec broken

Hi, there is an issue with the latest podspec you pushed today (1.5) as you can see here: https://travis-ci.org/CocoaPods/Specs/builds/20388139

-> The specification defined in `JLRoutes/1.5/JLRoutes.podspec` could not be loaded.
[!] Invalid `JLRoutes.podspec` file: compile error
JLRoutes/1.5/JLRoutes.podspec:3: Invalid char `\342' in expression
JLRoutes/1.5/JLRoutes.podspec:3: Invalid char `\200' in expression
JLRoutes/1.5/JLRoutes.podspec:3: Invalid char `\234' in expression
JLRoutes/1.5/JLRoutes.podspec:3: Invalid char `\342' in expression
JLRoutes/1.5/JLRoutes.podspec:3: Invalid char `\200' in expression
JLRoutes/1.5/JLRoutes.podspec:3: Invalid char `\235' in expression
JLRoutes/1.5/JLRoutes.podspec:23: Invalid char `\342' in expression
JLRoutes/1.5/JLRoutes.podspec:23: Invalid char `\200' in expression
JLRoutes/1.5/JLRoutes.podspec:23: Invalid char `\234' in expression
JLRoutes/1.5/JLRoutes.podspec:23: Invalid char `\342' in expression
JLRoutes/1.5/JLRoutes.podspec:23: Invalid char `\200' in expression
JLRoutes/1.5/JLRoutes.podspec:23: Invalid char `\235' in expression. Updating CocoaPods might fix the issue.
 #  from JLRoutes/1.5/JLRoutes.podspec:30
 #  -------------------------------------------
 #    s.osx.deployment_target = '10.7'
 >  end
 #  -------------------------------------------
  - JLRoutes (1.5)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.