-
Notifications
You must be signed in to change notification settings - Fork 13
/
TestDSL.scala
84 lines (65 loc) · 2.29 KB
/
TestDSL.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package app.impl.scalaz
import scalaz.Free._
import scalaz.{Free, ~>}
/**
* Created by pabloperezgarcia on 12/03/2017.
*
*
*/
class TestDSL {
/**
* With type we define a new class type instead have to create an object
* class as we have to do in Java
*/
type Id[+X] = X
/**
* The next classes are our ADT algebraic data types
*/
sealed trait Action[A]
case class _Action(action: String, any: Any) extends Action[Any]
val PARAM = "(.*)"
val VERSION = "([0-2].0)"
val ADD = s"add '$PARAM'".r
val MESSAGE = s"A message with version $VERSION".r
val MULTIPLY = s"multiply by '$PARAM'".r
val HIGHER_THAN = s"The result should be higher than '$PARAM'".r
/**
* A Free monad it´s kind like an Observable,
* where we specify the Entry type Orders, and output type A
*/
type ActionMonad[A] = Free[Action, A]
def Given(action: String, any: Any): ActionMonad[Any] = liftF[Action, Any](_Action(action, any))
implicit class customFree(free: Free[Action, Any]) {
def When(action: String): ActionMonad[Any] = {
free.flatMap(any => liftF[Action, Any](_Action(action, any)))
}
def Then(action: String): ActionMonad[Any] = {
free.flatMap(any => liftF[Action, Any](_Action(action, any)))
}
def And(action: String): ActionMonad[Any] = {
free.flatMap(any => liftF[Action, Any](_Action(action, any)))
}
def runScenario = free.foldMap(actionInterpreter)
}
/**
* This function return a function which receive an Order type of A and return that type
* That type it could be anything, so using the same FreeMonad DSL we can define multiple
* implementations types.
*
* @return
*/
def actionInterpreter: Action ~> Id = new (Action ~> Id) {
def apply[A](order: Action[A]): Id[A] = order match {
case _Action(action, any) => processAction(action, any)
}
}
private def processAction(action: String, any: Any): Any = {
action match {
case "Giving a number" => any
case MESSAGE(version) => any
case MULTIPLY(value) => any.asInstanceOf[Int] * value.asInstanceOf[String].toInt
case ADD(value) => any.asInstanceOf[Int] + value.asInstanceOf[String].toInt
case HIGHER_THAN(value) => assert(any.asInstanceOf[Int] > value.asInstanceOf[String].toInt); any
}
}
}