Skip to content

Commit ad96bee

Browse files
committed
Use tuplez.Composition instead of our Tupler. Fixes #12
1 parent f8d9f98 commit ad96bee

10 files changed

+108
-188
lines changed

README.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ or an error of type `A` (if the segment could not retrieve the information).
8787

8888
`PathSegment`s are immutable objects that can be composed together with the `/` operator. This operator is associative
8989
and creates, given two `PathSegment`s with type parameters `T` and `U`, will create a `PathSegment` with type parameter,
90-
roughly, `(T, U)` (with some additional rules described in the `Tupler` class that, without entering details, flattens
91-
the tuples and remove `Unit`s). So if `T =:= (String, Int)` and `U =:= (String, Double)`, you'll get the type
90+
roughly, `(T, U)` (with some additional rules described in the `Composition` class that, without entering details, flattens
91+
the tuples and removes `Unit`s). So if `T =:= (String, Int)` and `U =:= (String, Double)`, you'll get the type
9292
`(String, Int, String, Double)`.
9393

9494
When a `PathSegment` matches a URL, it internally receives the list of `Segment`s, consumes one or several of them, and
@@ -278,6 +278,10 @@ import urldsl.language.dummyErrorImpl._
278278

279279
url-dsl was thought with one possible goal in mind, the one of creating a routing system. An example of how to do that can be found [here](shared/src/test/scala/urldsl/examples/RouterUseCaseExample.scala).
280280

281+
## Moving from 0.4.x to 0.5.x
282+
283+
In 0.5.0 we replaced our `Tupler` with the `Composition` type from the [tuplez](https://github.com/tulz-app/tuplez) library. It works exactly the same for most use cases, but if your data types are complex enough that URL-DSL previously gave you nested tuples, those tuples will generally be flattened now.
284+
281285
## Moving from 0.2.0 to 0.3.x
282286

283287
If you come from version 0.2.0, here are a few things that you should pay attention to.

build.sbt

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ lazy val `url-dsl` = crossProject(JSPlatform, JVMPlatform)
2626
.settings(name := "url-dsl")
2727
.settings(
2828
libraryDependencies ++= Seq(
29+
"app.tulz" %%% "tuplez-full-light" % "0.4.0-M1",
2930
"org.scalatest" %%% "scalatest" % "3.2.9" % "test",
3031
"org.scalacheck" %%% "scalacheck" % "1.15.4" % "test"
3132
)

url-dsl/src/main/scala/urldsl/language/PathSegment.scala

+8-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import urldsl.errors.{DummyError, ErrorFromThrowable, PathMatchingError, SimpleP
44
import urldsl.url.{UrlStringDecoder, UrlStringGenerator, UrlStringParserGenerator}
55
import urldsl.vocabulary._
66

7+
import app.tulz.tuplez.Composition
8+
79
import scala.language.implicitConversions
810

911
/**
@@ -84,20 +86,20 @@ trait PathSegment[T, +A] extends UrlPart[T, A] {
8486
final def createPart(t: T, encoder: UrlStringGenerator): String = createPath(t, encoder)
8587

8688
/**
87-
* Concatenates `this` [[urldsl.language.PathSegment]] with `that` one, "tupling" the types with the [[Tupler]]
89+
* Concatenates `this` [[urldsl.language.PathSegment]] with `that` one, "tupling" the types with the [[Composition]]
8890
* rules.
8991
*/
90-
final def /[U, A1 >: A](that: PathSegment[U, A1])(implicit ev: Tupler[T, U]): PathSegment[ev.Out, A1] =
91-
PathSegment.factory[ev.Out, A1](
92+
final def /[U, A1 >: A](that: PathSegment[U, A1])(implicit c: Composition[T, U]): PathSegment[c.Composed, A1] =
93+
PathSegment.factory[c.Composed, A1](
9294
(segments: List[Segment]) =>
9395
for {
9496
firstOut <- this.matchSegments(segments)
9597
PathMatchOutput(t, remaining) = firstOut
9698
secondOut <- that.matchSegments(remaining)
9799
PathMatchOutput(u, lastRemaining) = secondOut
98-
} yield PathMatchOutput(ev(t, u), lastRemaining),
99-
(out: ev.Out) => {
100-
val (t, u) = ev.unapply(out)
100+
} yield PathMatchOutput(c.compose(t, u), lastRemaining),
101+
(out: c.Composed) => {
102+
val (t, u) = c.unapply(out)
101103

102104
this.createSegments(t) ++ that.createSegments(u)
103105
}

url-dsl/src/main/scala/urldsl/language/PathSegmentWithQueryParams.scala

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package urldsl.language
22

3+
import app.tulz.tuplez.Composition
34
import urldsl.url.{UrlStringDecoder, UrlStringGenerator, UrlStringParserGenerator}
45
import urldsl.vocabulary._
56

@@ -74,12 +75,12 @@ final class PathSegmentWithQueryParams[PathType, +PathError, ParamsType, +Params
7475

7576
def &[OtherParamsType, ParamsError1 >: ParamsError](otherParams: QueryParameters[OtherParamsType, ParamsError1])(
7677
implicit
77-
ev: Tupler[ParamsType, OtherParamsType]
78-
): PathSegmentWithQueryParams[PathType, PathError, ev.Out, ParamsError1] =
79-
new PathSegmentWithQueryParams[PathType, PathError, ev.Out, ParamsError1](
78+
c: Composition[ParamsType, OtherParamsType]
79+
): PathSegmentWithQueryParams[PathType, PathError, c.Composed, ParamsError1] =
80+
new PathSegmentWithQueryParams[PathType, PathError, c.Composed, ParamsError1](
8081
pathSegment,
8182
(queryParams & otherParams)
82-
.asInstanceOf[QueryParameters[ev.Out, ParamsError1]] // not necessary but IntelliJ complains.
83+
.asInstanceOf[QueryParameters[c.Composed, ParamsError1]] // not necessary but IntelliJ complains.
8384
)
8485

8586
def withFragment[FragmentType, FragmentError](

url-dsl/src/main/scala/urldsl/language/QueryParameters.scala

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package urldsl.language
22

3+
import app.tulz.tuplez.Composition
34
import urldsl.errors.{DummyError, ParamMatchingError, SimpleParamMatchingError}
45
import urldsl.url.{UrlStringDecoder, UrlStringGenerator, UrlStringParserGenerator}
56
import urldsl.vocabulary._
@@ -59,24 +60,24 @@ trait QueryParameters[Q, +A] extends UrlPart[Q, A] {
5960
createParamsString(q, encoder)
6061

6162
/**
62-
* Adds `that` QueryParameters to `this` one, "tupling" the returned type with the implicit [[urldsl.language.Tupler]]
63+
* Adds `that` QueryParameters to `this` one, "tupling" the returned type with the implicit [[Composition]]
6364
*
6465
* The matching and writing of strings is functionally commutative under `&`, but the returned type `Q` is not. So,
6566
* if you have two parameters, one matching an Int and the other one a String, depending on the order in which `&` is
6667
* called, you can end up with "Q = (Int, String)" or "Q = (String, Int)". This property is called
6768
* "QuasiCommutativity" in the tests.
6869
*/
69-
final def &[R, A1 >: A](that: QueryParameters[R, A1])(implicit ev: Tupler[Q, R]): QueryParameters[ev.Out, A1] =
70-
factory[ev.Out, A1](
70+
final def &[R, A1 >: A](that: QueryParameters[R, A1])(implicit c: Composition[Q, R]): QueryParameters[c.Composed, A1] =
71+
factory[c.Composed, A1](
7172
(params: Map[String, Param]) =>
7273
for {
7374
firstMatch <- this.matchParams(params)
7475
ParamMatchOutput(q, remainingParams) = firstMatch
7576
secondMatch <- that.matchParams(remainingParams)
7677
ParamMatchOutput(r, finalRemainingParams) = secondMatch
77-
} yield ParamMatchOutput(ev(q, r), finalRemainingParams),
78-
(out: ev.Out) => {
79-
val (q, r) = ev.unapply(out)
78+
} yield ParamMatchOutput(c.compose(q, r), finalRemainingParams),
79+
(out: c.Composed) => {
80+
val (q, r) = c.unapply(out)
8081
this.createParams(q) ++ that.createParams(r)
8182
}
8283
)

url-dsl/src/main/scala/urldsl/language/Tupler.scala

-167
This file was deleted.

url-dsl/src/test/scala/urldsl/examples/PathSegmentExamples.scala

+5
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ final class PathSegmentExamples extends AnyFlatSpec with Matchers {
132132
)
133133
)
134134

135+
/** Flattening of int-tuple segment with [[app.tulz.tuplez.Composition]] */
136+
(root / segment[String] / segment[(Int, Int)] / "hey").matchPath("hello/22-33/hey") should be(Right("hello", 22, 33))
137+
135138
}
136139

137140
"Some generating examples" should "work" in {
@@ -143,6 +146,8 @@ final class PathSegmentExamples extends AnyFlatSpec with Matchers {
143146
*/
144147
(root / segment[String] / segment[Int] / "hey").createPart(("hello", 22)) should be("hello/22/hey")
145148

149+
/** Flattening of int-tuple segment with [[app.tulz.tuplez.Composition]] */
150+
(root / segment[String] / segment[(Int, Int)] / "hey").createPart(("hello", 22, 33)) should be("hello/22-33/hey")
146151
}
147152

148153
}

0 commit comments

Comments
 (0)