Guest User

Untitled

a guest
Jun 18th, 2018
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.88 KB | None | 0 0
  1. import scala.reflect._
  2.  
  3. sealed trait TransformResult[+T]
  4.  
  5. case class TransformContext(path: List[String]) {
  6. def append(p: String) = TransformContext(p::path)
  7.  
  8. override def toString = path.reverse.mkString(".")
  9. }
  10.  
  11. object TransformContext {
  12. val empty = TransformContext(List())
  13. }
  14.  
  15. case class Success[+T](v: T) extends TransformResult[T]
  16. case class Failure(context: TransformContext, message: String) extends TransformResult[Nothing]
  17.  
  18. trait Transform[+T] {
  19.  
  20. def run(context: TransformContext, current: Any): TransformResult[T]
  21.  
  22. def flatMap[U](uf: (T) => Transform[U]) = Transform.flatMap(this, uf)
  23.  
  24. def map[U](m: T => U) = Transform.map(this, m)
  25.  
  26. def and[U](u: Transform[U]) = Transform.and(this, u)
  27.  
  28. def named(name: String) = Transform.named(this, name)
  29.  
  30. def optional = Transform.optional(this)
  31.  
  32. def transform(m: Map[String, Any]): TransformResult[T] = run(TransformContext.empty, m)
  33. }
  34.  
  35. object Implicits {
  36.  
  37. implicit class ImplicitFlattenTransform[T](val t: Transform[Transform[T]]) extends AnyVal {
  38. def flatten = Transform.flatten(t)
  39. }
  40.  
  41. implicit class ImplicitOrTransform[T](val f: Transform[T]) extends AnyVal {
  42. def or(s: Transform[T]) = Transform.or(f, s)
  43. }
  44.  
  45. implicit class ImplicitApplyTransform[T, U](val f: Transform[T => U]) extends AnyVal {
  46. def apply(t: Transform[T]) = Transform.apply(f, t)
  47. }
  48. }
  49.  
  50. object Transform {
  51. def create[T](m: (TransformContext, Any) => TransformResult[T]) = new Transform[T] {
  52. def run(context: TransformContext, current: Any): TransformResult[T] = {
  53. m(context, current)
  54. }
  55. }
  56.  
  57. def value[T](v: T) = new Transform[T] {
  58. def run(context: TransformContext, current: Any): TransformResult[T] = {
  59. Success(v)
  60. }
  61. }
  62.  
  63. def failWith(message: String) = new Transform[Nothing] {
  64. def run(context: TransformContext, current: Any): TransformResult[Nothing] = {
  65. Failure(context, message)
  66. }
  67. }
  68.  
  69. def flatMap[T, U](t: Transform[T], uf: (T) => Transform[U]) = new Transform[U] {
  70. def run(context: TransformContext, current: Any): TransformResult[U] = {
  71. t.run(context, current) match {
  72. case Success(tv) =>
  73. val u = uf(tv)
  74. u.run(context, current)
  75. case Failure(tctx, tmsg) => Failure(tctx, tmsg)
  76. }
  77. }
  78. }
  79.  
  80. def flatten[T](t: Transform[Transform[T]]) = t.flatMap(tv => tv)
  81.  
  82. def apply[T, U](f: Transform[T => U], t: Transform[T]) = f.flatMap(fv => t.flatMap(tv => Transform.value(fv(tv))))
  83.  
  84. def map[T, U](t: Transform[T], m: T => U) = t.flatMap(tv => value(m(tv)))
  85.  
  86. def and[T, U](t: Transform[T], u: Transform[U]) = t.flatMap(tv => u.flatMap(uv => value((tv, uv))))
  87.  
  88. def or[T](f: Transform[T], s: Transform[T]) = new Transform[T] {
  89. def run(context: TransformContext, current: Any): TransformResult[T] = {
  90. f.run(context, current) match {
  91. case Success(tv) => Success(tv)
  92. case Failure(tctx, tmsg) => s.run(context, current)
  93. }
  94. }
  95. }
  96.  
  97. def optional[T](t: Transform[T]) = new Transform[Option[T]] {
  98. def run(context: TransformContext, current: Any): TransformResult[Option[T]] = {
  99. t.run(context, current) match {
  100. case Success(tv) => Success(Some(tv))
  101. case Failure(_, _) => Success(None)
  102. }
  103. }
  104. }
  105.  
  106. def named[T](t: Transform[T], name: String) = new Transform[T] {
  107. def run(context: TransformContext, current: Any): TransformResult[T] = {
  108. current match {
  109. case null => Failure(context, "current is null")
  110. case m : Map[String,_] =>
  111. m.get(name) match {
  112. case Some(next) =>
  113. val nctx = context.append(name)
  114. t.run(nctx, next)
  115. case None => Failure(context, s"Map does not contain key: $name")
  116. }
  117. case _ => Failure(context, "current is not a Map")
  118. }
  119. }
  120. }
  121.  
  122. def cast[T : ClassTag] = new Transform[T] {
  123. def run(context: TransformContext, current: Any): TransformResult[T] = {
  124. current match {
  125. case tv : T => Success(tv)
  126. case _ => Failure(context, s"Cannot cast current to T") // TODO: Improve
  127. }
  128. }
  129. }
  130.  
  131. val asString = new Transform[String] {
  132. def run(context: TransformContext, current: Any): TransformResult[String] = {
  133. current match {
  134. case null => Success("")
  135. case s : String => Success(s)
  136. case v => Success(v.toString)
  137. }
  138. }
  139. }
  140.  
  141. val asNumber = new Transform[Number] {
  142. def run(context: TransformContext, current: Any): TransformResult[Number] = {
  143. current match {
  144. case null => Success(0)
  145. case n : Number => Success(n)
  146. case _ => Failure(context, "Not a number")
  147. }
  148. }
  149. }
  150. }
  151.  
  152. case class MyInnerModel(xx: Either[Int, String])
  153.  
  154. case class MyModel(x: Number, y: String,z: MyInnerModel)
  155.  
  156. import Implicits._
  157.  
  158. object Program {
  159. def main(args: Array[String]): Unit = {
  160. def intVal(v: Int): Either[Int, String] = Left(v)
  161. def stringVal(v: String): Either[Int, String] = Right(v)
  162.  
  163. def string(key: String) = Transform.asString.named(key)
  164. def number(key: String) = Transform.asNumber.named(key)
  165. def either(key: String) = Transform.cast[Int].map(intVal(_))
  166. .or(Transform.cast[String].map(stringVal(_)))
  167. .or(Transform.failWith("Expected either int or string"))
  168. .named(key)
  169.  
  170.  
  171. def map(kvs: (String, Any)*) = Map(kvs:_*)
  172.  
  173. val tmyInnermodel = either("xx")
  174. .map(MyInnerModel(_))
  175.  
  176. val tmyModel1 = Transform
  177. .value(MyModel.curried)
  178. .apply(number("x"))
  179. .apply(string("y"))
  180. .apply(tmyInnermodel.named("z"))
  181.  
  182. val tmyModel3 = Transform
  183. .value(MyModel.curried)
  184. .apply(number("x"))
  185. .apply(string("y"))
  186. .apply(Transform.value(MyInnerModel(Left(0))))
  187.  
  188. val versions = Map(1 -> tmyModel1, 3 -> tmyModel3)
  189.  
  190. def tmyModel = Transform.cast[Int].flatMap { v =>
  191. versions.get(v) match {
  192. case Some(vv) => Transform.value(vv)
  193. case None => Transform.failWith(s"Unrecognized version: $v")
  194. }
  195. }.named("v").flatten
  196.  
  197. def test(map: Map[String, Any]) = {
  198. val result = tmyModel.transform(map)
  199. println(map)
  200. println(result)
  201. }
  202.  
  203. test(map(
  204. "v" -> 1,
  205. "x" -> 1,
  206. "y" -> "a",
  207. "z" -> map("xx" -> 11)))
  208.  
  209. test(map(
  210. "v" -> 1,
  211. "x" -> 1,
  212. "y" -> "a",
  213. "z" -> map("xx" -> "XX")))
  214.  
  215. test(map(
  216. "v" -> 1,
  217. "x" -> 1,
  218. "y" -> "a",
  219. "z" -> map("xx" -> true)))
  220.  
  221. test(map(
  222. "v" -> 1,
  223. "x" -> 1,
  224. "y" -> "a",
  225. "z" -> map()))
  226.  
  227. test(map(
  228. "v" -> 1,
  229. "x" -> 1,
  230. "y" -> "a",
  231. "z" -> 1))
  232.  
  233. test(map(
  234. "v" -> 1,
  235. "x" -> 1,
  236. "y" -> "a"))
  237.  
  238. test(map(
  239. "v" -> 1,
  240. "x" -> "a",
  241. "y" -> "a"))
  242.  
  243. test(map(
  244. "v" -> 2))
  245.  
  246. test(map(
  247. "v" -> ""))
  248.  
  249. test(map(
  250. "v" -> 3,
  251. "x" -> 1,
  252. "y" -> "a"))
  253.  
  254. test(map())
  255. }
  256. }
Add Comment
Please, Sign In to add comment