/src/test/scala/coalgebras/scalaz/cofreeweb.scala

https://github.com/hablapps/gist · Scala · 124 lines · 101 code · 23 blank · 0 comment · 0 complexity · 70c35a7db39571befa85054eebadff76 MD5 · raw file

  1. package org.hablapps.gist
  2. package coalgebras
  3. package scalazimpl
  4. import akka.http.scaladsl._
  5. import akka.http.scaladsl.model._
  6. import akka.http.scaladsl.unmarshalling._
  7. import akka.http.scaladsl.marshalling._
  8. import akka.stream.Materializer
  9. import scala.concurrent.Future
  10. import scalaz.{StateT, ~>}
  11. import scalaz.std.scalaFuture._
  12. import CoChurchFinalCoalgebra.Cofree
  13. import Automata.Input.ADT
  14. object WebEntity {
  15. trait CofreeWeb[I, Y] {
  16. type X
  17. var x: X
  18. val f: X => Y
  19. val coalg: Automata[Future, I, X]
  20. val handler: HttpRequest => Future[HttpResponse]
  21. }
  22. trait MyTypeClass[I] {
  23. def fromEntity: FromEntityUnmarshaller[I]
  24. }
  25. def cofree[I](
  26. host: String,
  27. port: Int,
  28. httpExt: HttpExt)(implicit
  29. mat: Materializer,
  30. typ: MyTypeClass[I]) =
  31. new CofreeCoalgebra2[CofreeWeb[I, ?], Automata[Future, I, ?]] {
  32. import httpExt.system.dispatcher
  33. type YCat[Y] = ToEntityMarshaller[Y]
  34. def label[Y: YCat](cy: CofreeWeb[I, Y]): Y =
  35. cy.f(cy.x)
  36. def machine[Y]: Automata[Future, I, CofreeWeb[I, Y]] =
  37. new Automata[Future, I, CofreeWeb[I, Y]] {
  38. def isFinal(): StateT[Future, CofreeWeb[I, Y], Boolean] =
  39. StateT[Future, CofreeWeb[I, Y], Boolean] { cw =>
  40. cw.coalg
  41. .isFinal()
  42. .eval(cw.x)
  43. .map((cw, _))
  44. }
  45. def next(i: I): StateT[Future, CofreeWeb[I, Y], Unit] =
  46. StateT[Future, CofreeWeb[I, Y], Unit] { cw =>
  47. cw.coalg
  48. .next(i)
  49. .eval(cw.x)
  50. .map((cw, _))
  51. }
  52. }
  53. def trace[_X: Automata[Future, I, ?], Y: YCat](_f: _X => Y): _X => CofreeWeb[I, Y] =
  54. _x => new CofreeWeb[I, Y] {
  55. type X = _X
  56. var x: X = _x
  57. val coalg = implicitly[Automata[Future, I, X]]
  58. val handler: HttpRequest => Future[HttpResponse] = {
  59. case HttpRequest(HttpMethods.POST, Uri.Path("/next"), _, entity, _) =>
  60. typ.fromEntity(entity) flatMap { input =>
  61. coalg.next(input).run(x) map { case (s, o) =>
  62. x = s
  63. HttpResponse()
  64. }
  65. }
  66. case HttpRequest(HttpMethods.GET, Uri.Path("/isFinal"), _, _, _) =>
  67. coalg.isFinal().run(x) map { case (s, o) =>
  68. x = s
  69. HttpResponse(entity = HttpEntity(o.toString))
  70. }
  71. case HttpRequest(HttpMethods.GET, Uri.Path("/"), _, _, _) =>
  72. Marshal(f(x)).to[HttpResponse]
  73. }
  74. httpExt.bindAndHandleAsync(handler, host, port)
  75. val f: X => Y = _f
  76. }
  77. }
  78. }
  79. import akka.actor.ActorSystem
  80. import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
  81. import akka.stream.ActorMaterializer
  82. import spray.json._
  83. object WebEntityTest extends App with DefaultJsonProtocol {
  84. import WebEntity._
  85. import AnAutomata._
  86. case class Wrapper[A](a: A)
  87. object Wrapper {
  88. implicit def jsonFormat[A: JsonFormat]: RootJsonFormat[Wrapper[A]] =
  89. jsonFormat1(Wrapper.apply[A])
  90. }
  91. implicit val system = ActorSystem("cofree-web")
  92. import system.dispatcher
  93. implicit val materializer = ActorMaterializer()
  94. implicit object foo extends MyTypeClass[Boolean] {
  95. def fromEntity: FromEntityUnmarshaller[Boolean] =
  96. implicitly[FromEntityUnmarshaller[Wrapper[Boolean]]].map(_.a)
  97. }
  98. val httpExt = Http()
  99. implicit val CofreeAutomata = cofree[Boolean]("localhost", 8080, httpExt)
  100. CofreeAutomata.trace[Int, String](_.toString)(Even[Future], implicitly[ToEntityMarshaller[String]])(0)
  101. }