Skip to content

Commit b36692c

Browse files
authored
Merge pull request #342 from RafalSumislawski/scala_2_13
Upgrade to scala 2.13 and http4s 0.21.0 (second attempt)
2 parents f6acd78 + a7e21a9 commit b36692c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+276
-199
lines changed

Diff for: .travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
language: scala
22
scala:
3-
- 2.11.12
4-
- 2.12.8
3+
- 2.12.10
4+
- 2.13.1
55
jdk:
66
- openjdk8
77
- openjdk11

Diff for: build.sbt

+26-10
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,31 @@ lazy val rho = project
1616

1717
lazy val `rho-core` = project
1818
.in(file("core"))
19-
.settings(rhoPreviousArtifacts(lastVersion = "0.19.0", "core"))
20-
.settings(buildSettings: _*)
19+
.settings(mimaConfiguration)
20+
.settings(buildSettings ++ Seq(
21+
Compile / unmanagedSourceDirectories ++= {
22+
val baseDir = baseDirectory.value
23+
24+
val mainSrcDir = "src/main/scala"
25+
CrossVersion.partialVersion(scalaVersion.value) match {
26+
case Some((2, minor)) if minor <= 12 => Seq(baseDir / s"$mainSrcDir-2.12-")
27+
case Some((2, minor)) if minor >= 13 => Seq(baseDir / s"$mainSrcDir-2.13+")
28+
case _ => Nil
29+
}
30+
},
31+
libraryDependencies ++= Seq("org.scala-lang.modules" %% "scala-collection-compat" % "2.0.0")
32+
): _*)
2133

2234
lazy val `rho-hal` = project
2335
.in(file("hal"))
2436
.settings(buildSettings :+ halDeps: _*)
25-
.settings(rhoPreviousArtifacts(lastVersion = "0.19.0", "hal"))
37+
.settings(mimaConfiguration)
2638
.dependsOn(`rho-core`)
2739

2840
lazy val `rho-swagger` = project
2941
.in(file("swagger"))
3042
.settings(buildSettings :+ swaggerDeps: _*)
31-
.settings(rhoPreviousArtifacts(lastVersion = "0.19.0", "swagger"))
43+
.settings(mimaConfiguration)
3244
.dependsOn(`rho-core` % "compile->compile;test->test")
3345

3446
lazy val docs = project
@@ -46,7 +58,7 @@ lazy val docs = project
4658
version.value,
4759
apiVersion.value
4860
),
49-
scalacOptions in (ScalaUnidoc, unidoc) += "-Ypartial-unification",
61+
scalacOptions in (ScalaUnidoc, unidoc) ++= versionSpecificEnabledFlags(scalaVersion.value),
5062
unidocProjectFilter in (ScalaUnidoc, unidoc) := inProjects(
5163
`rho-core`,
5264
`rho-hal`,
@@ -77,18 +89,22 @@ lazy val `rho-examples` = project
7789
): _*)
7890
.dependsOn(`rho-swagger`, `rho-hal`)
7991

80-
lazy val compileFlags = Seq(
92+
lazy val compilerFlags = Seq(
8193
"-feature",
8294
"-deprecation",
8395
"-unchecked",
8496
"-language:higherKinds",
8597
"-language:existentials",
8698
"-language:implicitConversions",
8799
"-Ywarn-unused",
88-
"-Ypartial-unification",
89100
"-Xfatal-warnings"
90101
)
91102

103+
def versionSpecificEnabledFlags(version: String) = (CrossVersion.partialVersion(version) match {
104+
case Some((2, 13)) => Seq.empty[String]
105+
case _ => Seq("-Ypartial-unification")
106+
})
107+
92108
/* Don't publish setting */
93109
lazy val dontPublish = packagedArtifacts := Map.empty
94110

@@ -99,9 +115,9 @@ lazy val license = licenses in ThisBuild := Seq(
99115

100116
lazy val buildSettings = publishing ++
101117
Seq(
102-
scalaVersion := "2.12.8",
103-
crossScalaVersions := Seq(scalaVersion.value, "2.11.12"),
104-
scalacOptions ++= compileFlags,
118+
scalaVersion := "2.13.1",
119+
crossScalaVersions := Seq(scalaVersion.value, "2.12.10"),
120+
scalacOptions := compilerFlags ++ versionSpecificEnabledFlags(scalaVersion.value),
105121
resolvers += Resolver.sonatypeRepo("snapshots"),
106122
fork in run := true,
107123
organization in ThisBuild := "org.http4s",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package scala.jdk
2+
3+
import scala.collection.convert.{DecorateAsJava, DecorateAsScala}
4+
5+
object CollectionConverters extends DecorateAsJava with DecorateAsScala
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package scala.collection.compat.view
2+
3+
import scala.collection.generic.CanBuildFrom
4+
5+
class MapViewExtensionMethods[K, V, C <: scala.collection.Map[K, V]](private val self: IterableView[(K, V), C]) extends AnyVal {
6+
def mapValues[W, That](f: V => W)(implicit bf: CanBuildFrom[IterableView[(K, V), C], (K, W), That]): That =
7+
self.map[(K, W), That] { case (k, v) => (k, f(v)) }
8+
}
9+
10+
trait MapViewExtensions {
11+
implicit def toMapViewExtensionMethods[K, V, C <: scala.collection.Map[K, V]](self: IterableView[(K, V), C]): MapViewExtensionMethods[K, V, C] =
12+
new MapViewExtensionMethods[K, V, C](self)
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package scala.collection.compat
2+
3+
import scala.collection.{IterableView => SCIterableView}
4+
5+
package object view extends MapViewExtensions {
6+
type IterableView[A, B] = SCIterableView[A, B]
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package scala.collection.compat
2+
3+
import scala.collection.{IterableOps, View}
4+
5+
package object view {
6+
type IterableView[A, _] = IterableOps[A, View, View[A]]
7+
}

Diff for: core/src/main/scala/org/http4s/rho/CompileRoutes.scala

+3-6
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@ package org.http4s
22
package rho
33

44
import scala.collection.immutable.Seq
5-
6-
import cats.Monad
7-
import cats.data.Kleisli
5+
import cats.effect.Sync
86
import shapeless.HList
9-
107
import org.http4s.rho.RhoRoute.Tpe
118
import org.http4s.rho.bits.PathTree
129

@@ -43,8 +40,8 @@ object CompileRoutes {
4340
* @param routes `Seq` of routes to bundle into a service.
4441
* @return An `HttpRoutes`
4542
*/
46-
def foldRoutes[F[_]: Monad](routes: Seq[RhoRoute.Tpe[F]]): HttpRoutes[F] = {
43+
def foldRoutes[F[_]: Sync](routes: Seq[RhoRoute.Tpe[F]]): HttpRoutes[F] = {
4744
val tree = routes.foldLeft(PathTree[F]()){ (t, r) => t.appendRoute(r) }
48-
Kleisli((req: Request[F]) => tree.getResult(req).toResponse)
45+
HttpRoutes((req: Request[F]) => tree.getResult(req).toResponse)
4946
}
5047
}

Diff for: core/src/main/scala/org/http4s/rho/RhoDslPathExtractors.scala

+21-3
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,27 @@ package org.http4s.rho
22

33
import org.http4s.rho.bits.PathAST._
44
import org.http4s.rho.bits._
5+
import org.http4s.rho.RhoDslPathExtractors._
56
import shapeless.{::, HNil}
67

78
import scala.reflect.runtime.universe.TypeTag
89

910
trait RhoDslPathExtractors[F[_]] {
1011

11-
private val stringTag = implicitly[TypeTag[String]]
12-
1312
implicit def pathMatch(s: String): TypedPath[F, HNil] = TypedPath(PathMatch(s))
1413

15-
implicit def pathMatch(s: Symbol): TypedPath[F, String :: HNil] =
14+
/**
15+
* Provides 'pathVar syntax for String path variables (Scala 2.12 only)
16+
*/
17+
implicit def pathCapture(s: Symbol): TypedPath[F, String :: HNil] =
1618
TypedPath(PathCapture(s.name, None, StringParser.strParser, stringTag))
1719

20+
/**
21+
* Provides pv"pathVarName" syntax for String path variables as an alternative for 'pathVar (Symbol) syntax which was removed in Scala 2.13.
22+
*/
23+
implicit def pathCapture(sc: StringContext): PathCaptureStringContext[F] =
24+
new PathCaptureStringContext[F](sc)
25+
1826
/**
1927
* Defines a path variable of a URI that should be bound to a route definition
2028
*/
@@ -34,3 +42,13 @@ trait RhoDslPathExtractors[F[_]] {
3442
TypedPath(PathCapture[F](id, Some(description), parser, stringTag))
3543

3644
}
45+
46+
object RhoDslPathExtractors {
47+
48+
private val stringTag = implicitly[TypeTag[String]]
49+
50+
class PathCaptureStringContext[F[_]](val sc: StringContext) extends AnyVal {
51+
def pv(): TypedPath[F, String :: HNil] =
52+
TypedPath[F, String :: HNil](PathCapture(sc.parts.mkString, None, StringParser.strParser, stringTag))
53+
}
54+
}

Diff for: core/src/main/scala/org/http4s/rho/RhoRoutes.scala

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ package org.http4s
22
package rho
33

44
import scala.collection.immutable.Seq
5-
6-
import cats.Monad
5+
import cats.effect.Sync
76
import org.http4s.rho.bits.PathAST.TypedPath
87
import org.log4s.getLogger
98
import shapeless.{HList, HNil}
@@ -24,7 +23,7 @@ import shapeless.{HList, HNil}
2423
*
2524
* @param routes Routes to prepend before elements in the constructor.
2625
*/
27-
class RhoRoutes[F[_]: Monad](routes: Seq[RhoRoute[F, _ <: HList]] = Vector.empty)
26+
class RhoRoutes[F[_]: Sync](routes: Seq[RhoRoute[F, _ <: HList]] = Vector.empty)
2827
extends bits.MethodAliases
2928
with bits.ResponseGeneratorInstances[F]
3029
with RoutePrependable[F, RhoRoutes[F]]

Diff for: core/src/main/scala/org/http4s/rho/RoutesBuilder.scala

+8-6
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package org.http4s.rho
22

33
import scala.collection.immutable.VectorBuilder
44
import scala.collection.immutable.Seq
5-
import cats.Monad
5+
import cats.effect.Sync
66
import shapeless.HList
77
import org.http4s._
88

9+
import scala.collection.compat._
10+
911
/** CompileRoutes which accumulates routes and can build a `HttpRoutes` */
10-
final class RoutesBuilder[F[_]: Monad] private(internalRoutes: VectorBuilder[RhoRoute.Tpe[F]]) extends CompileRoutes[F, RhoRoute.Tpe[F]] {
12+
final class RoutesBuilder[F[_]: Sync] private(internalRoutes: VectorBuilder[RhoRoute.Tpe[F]]) extends CompileRoutes[F, RhoRoute.Tpe[F]] {
1113

1214
/** Turn the accumulated routes into an `HttpRoutes`
1315
*
@@ -25,8 +27,8 @@ final class RoutesBuilder[F[_]: Monad] private(internalRoutes: VectorBuilder[Rho
2527
* @param routes Routes to accumulate.
2628
* @return `this` instance with its internal state mutated.
2729
*/
28-
def append(routes: TraversableOnce[RhoRoute.Tpe[F]]): this.type = {
29-
internalRoutes ++= routes
30+
def append(routes: IterableOnce[RhoRoute.Tpe[F]]): this.type = {
31+
internalRoutes ++= routes.iterator.to(Iterable)
3032
this
3133
}
3234

@@ -46,10 +48,10 @@ final class RoutesBuilder[F[_]: Monad] private(internalRoutes: VectorBuilder[Rho
4648

4749
object RoutesBuilder {
4850
/** Constructor method for new `RoutesBuilder` instances */
49-
def apply[F[_]: Monad](): RoutesBuilder[F] = apply(Seq.empty)
51+
def apply[F[_]: Sync](): RoutesBuilder[F] = apply(Seq.empty)
5052

5153
/** Constructor method for new `RoutesBuilder` instances with existing routes */
52-
def apply[F[_]: Monad](routes: Seq[RhoRoute.Tpe[F]]): RoutesBuilder[F] = {
54+
def apply[F[_]: Sync](routes: Seq[RhoRoute.Tpe[F]]): RoutesBuilder[F] = {
5355
val builder = new VectorBuilder[RhoRoute.Tpe[F]]
5456
builder ++= routes
5557

Diff for: core/src/main/scala/org/http4s/rho/bits/HeaderAppendable.scala

-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package org.http4s
22
package rho.bits
33

4-
import scala.language.higherKinds
5-
64
import shapeless.HList
75
import shapeless.ops.hlist.Prepend
86

Diff for: core/src/main/scala/org/http4s/rho/bits/PathTree.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -258,12 +258,12 @@ private[rho] trait PathTreeOps[F[_]] extends RuleExecutor[F] {
258258

259259
if (!result.isEmpty || end.isEmpty || method == Method.OPTIONS) result
260260
else FailureResponse.pure[F] {
261-
val ms = end.keys
261+
val ms = end.keySet
262262
val allowedMethods = ms.mkString(", ")
263263
val msg = s"$method not allowed. Defined methods: $allowedMethods\n"
264264

265265
F.map(MethodNotAllowed.pure(msg))(
266-
_.putHeaders(headers.Allow(ms.head, ms.tail.toList:_*)))
266+
_.putHeaders(headers.Allow(ms)))
267267
}
268268
}
269269
}

Diff for: core/src/main/scala/org/http4s/rho/bits/QueryParser.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import org.http4s.rho.bits.QueryParser.Params
66

77
import scala.annotation.tailrec
88
import scala.collection.immutable.Seq
9-
import scala.collection.generic.CanBuildFrom
9+
import scala.collection.compat._
1010

1111
/** Extract a value from the `Request` `Query`
1212
*
@@ -41,9 +41,9 @@ trait QueryParsers[F[_]] extends FailureResponseOps[F] {
4141
*
4242
* The elements must have the same name and each be a valid representation of the requisite type.
4343
*/
44-
implicit def multipleParse[A, B[_]](implicit F: Monad[F], p: StringParser[F, A], cbf: CanBuildFrom[Seq[_], A, B[A]]) = new QueryParser[F, B[A]] {
44+
implicit def multipleParse[A, B[_]](implicit F: Monad[F], p: StringParser[F, A], cbf: Factory[A, B[A]]) = new QueryParser[F, B[A]] {
4545
override def collect(name: String, params: Params, default: Option[B[A]]): ResultResponse[F, B[A]] = {
46-
val b = cbf()
46+
val b = cbf.newBuilder
4747
params.get(name) match {
4848
case None => SuccessResponse(default.getOrElse(b.result))
4949
case Some(Seq()) => SuccessResponse(default.getOrElse(b.result))

Diff for: core/src/main/scala/org/http4s/rho/package.scala

-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import org.http4s.rho.bits._
66
import org.http4s.rho.bits.PathAST._
77
import shapeless.{HList, HNil}
88

9-
import scala.language.implicitConversions
10-
119
package object rho extends org.http4s.syntax.AllSyntax {
1210
type RhoMiddleware[F[_]] = Seq[RhoRoute[F, _ <: HList]] => Seq[RhoRoute[F, _ <: HList]]
1311

Diff for: core/src/test/scala/ApiExamples.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ class ApiExamples extends Specification {
3939
GET / "helloworldnumber" / pathVar[Int] / "foo" |>> { i: Int =>
4040
Ok(s"Received $i")
4141
}
42-
// the symbol 'world just says 'capture a String' with variable name "world"
43-
GET / "helloworldstring" / 'world / "foo" |>> { i: String =>
42+
// the pv"world" (pv stands for path variable) says 'capture a String' with variable name "world"
43+
GET / "helloworldstring" / pv"world" / "foo" |>> { i: String =>
4444
Ok(s"Received $i")
4545
}
4646
// capture dates
@@ -118,7 +118,7 @@ class ApiExamples extends Specification {
118118
val path2 = "two" / pathVar[Int]
119119

120120
val getLength = captureMap(`Content-Length`)(_.length)
121-
val getTag = captureMap(ETag)(_ => -1l)
121+
val getTag = captureMap(ETag)(_ => -1L)
122122

123123
GET / (path1 || path2) +? param[String]("foo") >>> (getLength || getTag) |>> {
124124
(i: Int, foo: String, v: Long) => Ok(s"Received $i, $foo, $v")
@@ -134,7 +134,7 @@ class ApiExamples extends Specification {
134134
GET / "request" |>> { _: Request[IO] =>
135135
Ok("I don't actually need a request...")
136136
}
137-
GET / "request" / 'foo |>> { (_: Request[IO], _: String) =>
137+
GET / "request" / pv"foo" |>> { (_: Request[IO], _: String) =>
138138
Ok("I wanted a request")
139139
}
140140
}

0 commit comments

Comments
 (0)