Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Mar 09 2020 17:00
    tindzk commented #37
  • Mar 08 2020 01:03
    raquo commented #37
  • Mar 07 2020 21:19
    raquo edited #37
  • Mar 07 2020 21:15
    raquo edited #37
  • Mar 07 2020 21:12
    raquo edited #37
  • Mar 07 2020 21:12
    raquo edited #37
  • Mar 07 2020 21:11
    raquo edited #37
  • Mar 07 2020 21:10
    raquo opened #37
  • Jul 10 2019 07:26

    tindzk on v0.2.1

    (compare)

  • Jul 10 2019 07:26

    tindzk on master

    Build: Publish v0.2.1 Build: Change version to v0.2.2… (compare)

  • Jul 09 2019 14:59

    tindzk on manual

    (compare)

  • Jul 09 2019 14:59

    tindzk on master

    Manual: Add example for encodin… Merge pull request #36 from spa… (compare)

  • Jul 09 2019 14:59
    tindzk closed #36
  • Jul 09 2019 14:59

    tindzk on scala213

    (compare)

  • Jul 09 2019 14:58

    tindzk on master

    Build: Add support for Scala 2.… Merge pull request #35 from spa… (compare)

  • Jul 09 2019 14:58
    tindzk closed #35
  • Jul 09 2019 14:57

    tindzk on parse-opt-elems

    (compare)

  • Jul 09 2019 14:57

    tindzk on master

    Route: Fix parsing of optional … Merge pull request #34 from spa… (compare)

  • Jul 09 2019 14:57
    tindzk closed #34
  • Jul 09 2019 14:57

    tindzk on redundant-amp

    (compare)

Darren Gibson
@zarthross
I read the issue #19 on widok, and certainly agree with most of your concerns.
As for the Akka support, personally, I'm interested in SPA development right now so jvm support isn't a priority for me, but I can see the importance for hybrid SPA applications. I feel though that if akka support is added, it should be added in a separate library so people feel they can easily add support for other frameworks like play or scalatra, finagle without pulling in akka.
On the overall design, I would love to see this router support Reverse Routing similiar to what playframework can do (https://www.playframework.com/documentation/2.4.x/ScalaRouting#Reverse-routing This is not an endorsement of how playframework does its routing, just a feature i would like to see)
Darren Gibson
@zarthross
I feel reverse routing is essential since routes can change. Being able to know at compile time if a route has been broken is extremely useful, which is why I'm a fan of Autowire (https://github.com/lihaoyi/autowire)
Tim Nieradzik
@tindzk
That's a great idea, indeed. We should definitely strive for type-safety when referencing routes.
Tim Nieradzik
@tindzk

Here is how I'm using MetaRouter in one of my projects:

object Routes {
  val Upload = Route("upload")
  val Library = Route("library")
  val Details = Route("details")

  def upload(): Route = Upload
  def library(): Route = Library
  def details(contentId: Long): Route =
    Details.copy(path = Details.path + "/" + contentId)
  ...
}

object MyRouter extends Router {
  override def dispatch(route: Route, attach: Boolean = false): Unit =
    route.path match {
      case Routes.Library.path => ...
      case Routes.Upload.path => ...      
      case x if x.startsWith(Routes.Details.path) => ...
  }
}

To come up with a better DSL we should discuss ideas for:

a) Specifying routes
b) Instantiating routes
c) Matching routes
d) Registering a JavaScript handler

Tim Nieradzik
@tindzk

To get the brainstorming started, I'll toss in an example how I envision the DSL to look like:

val Details : Route[Int] = "details" / Arg[Int]("contentId")
val UserInfo: Route[(String, Boolean)] = "user" / Arg[String]("user") / Arg[Boolean]("details")

val userInfo: InstantiatedRoute[(String, Boolean)] = UserInfo("bob", false)
userInfo == "user" / "bob" / false
userInfo.url == "user/bob/false"

Route.parse("a/b/c") == "a" / "b" / "c"

userInfo.matches(UserInfo) == true

("user" / "bob").errorMessage(UserInfo) == Some("`user` not specified")

val router = new Router(Seq(Details, UserInfo))
val matchingRoutes = Seq[Route[_]] = router.filter(userInfo)
matchingRoutes == Seq(UserInfo)

Please criticise and point out any shortcomings. :)

Darren Gibson
@zarthross
I think this line ("user" / "bob").errorMessage(UserInfo) == Some("`user` not specified") should be ("user" / "bob").errorMessage(UserInfo) == Some("`details` not specified")
perhaps val router = Router(Details, UserInfo) would be cleaner
using an apply method with a varaible parameter list..
But yeah, so far, I like it, could use a little ironing but i think its a good start.
Darren Gibson
@zarthross
Worked on the Route DSL a little this weekend... here is a sample of what it looks like so far:
 "Multiple Routes with the same Arg Types" should "be equal" in {
    val foo = !# / "asdf" / Arg[Int]("foo") / Arg[Boolean]("bar")
    val bar = !# / "asdf" / Arg[Int]("foo") / Arg[Boolean]("bar")

    assert(foo === bar)
  }

  it should "be equal even with different names" in {
    val foo = !# / "asdf" / Arg[Int]("foo") / Arg[Boolean]("bar")
    val bar = !# / "asdf" / Arg[Int]("foo1") / Arg[Boolean]("bar1")

    assert(foo === bar)
  }

  "Multiple Routes with the different Arg Types" should "not be equal" in {
    val foo = !# / "asdf" / Arg[Int]("foo") / Arg[Boolean]("bar")
    val bar = !# / "asdf" / Arg[Boolean]("fdas") / Arg[Int]("asdf")

    assert(foo !== bar)
  }

  it should "not be equal even with the same names" in {
    val foo = !# / "asdf" / Arg[Int]("foo") / Arg[Boolean]("bar")
    val bar = !# / "asdf" / Arg[Boolean]("foo") / Arg[Int]("bar")

    assert(foo !== bar)
  }

The InstantiatedRoute looks something like this:

  "InstantiatedRoute" should "be created by filling a Route's Args" in {
    val UserInfo = !# / Arg[Boolean]("details")

    val ui1 = UserInfo(false)

    val ui2: InstantiatedRoute[_, _] = UserInfo(false)
  }

  it should "be created by filling a Route's Args in a complex example" in {
    val UserInfo =  !# / "user" / Arg[String]("user") / Arg[Boolean]("details")

    val ui1 = UserInfo(false, "bob")

    val ui2: InstantiatedRoute[_ , _] = UserInfo(false, "bob")
  }

Full type signature of InstantiatedRoute were removed for brevity.

Unfortunately the parameters on apply for Route to create an InstantiatedRoute are reversed, but I'm working on a fix for that.
Darren Gibson
@zarthross
@tindzk ^ What do you think of using '!#' for the start of a Route? I was trying to make it clear that it was an absolute URL and not a relative one. FYI I'm using shapeless with HLists, so thats part of the reason the UserInfo.apply's arguments are showing up in reverse for the moment.
Tim Nieradzik
@tindzk

Indeed, the error message should be: details not specified.

I think it's a good idea to provide the apply() method as you suggested.

I am not sure !# is an intuitive operator. How about this:

val foo = Root / "asdf" / Arg[Int]("foo") / Arg[Boolean]("bar")

(or Index?)

Apart from this it looks really good!

We may also consider providing methods, e.g. Akka provides path() and pathPrefix().

@zarthross I have given you writing permissions to the repository. So if you want to push your changes in a new branch, please go ahead!
Darren Gibson
@zarthross
Awesome. I still have some clean up before I'm happy with it. I'll try and get what I have pushed over the weekend.
Darren Gibson
@zarthross
@tindzk Pushed my idea for a Route DSL to https://github.com/zarthross/MetaRouter/tree/new-route-dsl. I haven't spent much time on the Router portion, but I have some thoughts I'll try to put to code this week.
Tim Nieradzik
@tindzk
Thanks! I'll review it over the next few days.
Tim Nieradzik
@tindzk
@zarthross Impressive work! It's a great idea to use Shapeless. I made a few minor changes here.
Darren Gibson
@zarthross
Kool, I'll look at the changes you made later when i get a chance.
Tim Nieradzik
@tindzk
Do you have an idea how we could merge fill and fillN (see also f455b92aff451799f023d4d9379198ff3248ad17)?
Darren Gibson
@zarthross
Just a cursorer look though, I'm concerned about your move of matches, i think it breaks the type safey of the returned value.
Tim Nieradzik
@tindzk
I actually simplified the type to HList
Darren Gibson
@zarthross
that was the mistake
the Arg Parameter is specifically calculated at compile time based ont eh ROUTE type
Tim Nieradzik
@tindzk
But from what I understood it was untyped before as well.
Darren Gibson
@zarthross
it was type A from CanFillRoute
which was infered from FlatMapper.Aux[ConvertArgs.type, D, A]
Tim Nieradzik
@tindzk
Exactly, and A was determined for fill()'s arguments
But as matches only takes a string, it A is just HList
Am I mistaken?
I had to inline CanFillRoute because IntelliJ didn't find those methods
Darren Gibson
@zarthross
The type A parameter is just the T part of the Args[T] in the ROUTE hlist. I'm pull out the T's to make A
so its more than just an HList, its a specific type known at compile time.
sadly, true taht Intellij didn't like it, but if you inline it you break some of the shapeless checks.
or so i thought
i'll have to check it all later, i'll then take a look at fillN.
Tim Nieradzik
@tindzk
You're right, thanks. I'll try to add the parameters to matches.
Darren Gibson
@zarthross
Trust me, i wouldn't have made teh CanFillRoute extensions if i could have gotten fill and matches to work otherwise...
if you can figure out how to make it work inlined into Route, that would be awesome and i'm curous how to do it.
Tim Nieradzik
@tindzk
My idea was to use Sized.
There is the problem that the wrong fill() function is chosen when only one argument is provided.
With Sized it may be possible to check whether the Product argument is unary.
Darren Gibson
@zarthross
does it not work if you just remove the single argument fill and only use fill() and fill(TP) ?
Tim Nieradzik
@tindzk
I tried that already.
Darren Gibson
@zarthross
so, i'm not really sure how the fillN works in the first place since the function only has one argument but your passing in a list of arguments
Tim Nieradzik
@tindzk
Are there unary tuples?
fillN receives a tuple and creates an HList from it