FSM: remove Ev extractor and move -> into companion object, see #1759

This commit is contained in:
Roland 2012-01-31 21:48:24 +01:00
parent b4d9486e63
commit 983a6d3ace
6 changed files with 56 additions and 54 deletions

View file

@ -7,7 +7,6 @@ package akka.actor
import org.scalatest.{ BeforeAndAfterAll, BeforeAndAfterEach } import org.scalatest.{ BeforeAndAfterAll, BeforeAndAfterEach }
import akka.testkit._ import akka.testkit._
import TestEvent.Mute import TestEvent.Mute
import FSM._
import akka.util.duration._ import akka.util.duration._
import akka.event._ import akka.event._
import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigFactory
@ -52,7 +51,7 @@ object FSMActorSpec {
} }
} }
case Event("hello", _) stay replying "world" case Event("hello", _) stay replying "world"
case Event("bye", _) stop(Shutdown) case Event("bye", _) stop(FSM.Shutdown)
} }
when(Open) { when(Open) {
@ -63,7 +62,7 @@ object FSMActorSpec {
} }
whenUnhandled { whenUnhandled {
case Ev(msg) { case Event(msg, _) {
log.warning("unhandled event " + msg + " in state " + stateName + " with data " + stateData) log.warning("unhandled event " + msg + " in state " + stateName + " with data " + stateData)
unhandledLatch.open unhandledLatch.open
stay stay
@ -82,7 +81,7 @@ object FSMActorSpec {
} }
onTermination { onTermination {
case StopEvent(Shutdown, Locked, _) case StopEvent(FSM.Shutdown, Locked, _)
// stop is called from lockstate with shutdown as reason... // stop is called from lockstate with shutdown as reason...
terminatedLatch.open terminatedLatch.open
} }
@ -110,6 +109,8 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
"unlock the lock" in { "unlock the lock" in {
import FSM.{ Transition, CurrentState, SubscribeTransitionCallBack }
val latches = new Latches val latches = new Latches
import latches._ import latches._
@ -163,7 +164,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
val fsm = TestActorRef(new Actor with FSM[Int, Null] { val fsm = TestActorRef(new Actor with FSM[Int, Null] {
startWith(1, null) startWith(1, null)
when(1) { when(1) {
case Ev("go") goto(2) case Event("go", _) goto(2)
} }
}) })
val name = fsm.path.toString val name = fsm.path.toString
@ -182,7 +183,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
lazy val fsm = new Actor with FSM[Int, Null] { lazy val fsm = new Actor with FSM[Int, Null] {
override def preStart = { started.countDown } override def preStart = { started.countDown }
startWith(1, null) startWith(1, null)
when(1) { NullFunction } when(1) { FSM.NullFunction }
onTermination { onTermination {
case x testActor ! x case x testActor ! x
} }
@ -190,7 +191,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
val ref = system.actorOf(Props(fsm)) val ref = system.actorOf(Props(fsm))
Await.ready(started, timeout.duration) Await.ready(started, timeout.duration)
system.stop(ref) system.stop(ref)
expectMsg(1 second, fsm.StopEvent(Shutdown, 1, null)) expectMsg(1 second, fsm.StopEvent(FSM.Shutdown, 1, null))
} }
"log events and transitions if asked to do so" in { "log events and transitions if asked to do so" in {
@ -204,12 +205,12 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
val fsm = TestActorRef(new Actor with LoggingFSM[Int, Null] { val fsm = TestActorRef(new Actor with LoggingFSM[Int, Null] {
startWith(1, null) startWith(1, null)
when(1) { when(1) {
case Ev("go") case Event("go", _)
setTimer("t", Shutdown, 1.5 seconds, false) setTimer("t", FSM.Shutdown, 1.5 seconds, false)
goto(2) goto(2)
} }
when(2) { when(2) {
case Ev("stop") case Event("stop", _)
cancelTimer("t") cancelTimer("t")
stop stop
} }
@ -230,7 +231,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
expectMsgPF(1 second, hint = "processing Event(stop,null)") { expectMsgPF(1 second, hint = "processing Event(stop,null)") {
case Logging.Debug(`name`, `fsmClass`, s: String) if s.startsWith("processing Event(stop,null) from Actor[") true case Logging.Debug(`name`, `fsmClass`, s: String) if s.startsWith("processing Event(stop,null) from Actor[") true
} }
expectMsgAllOf(1 second, Logging.Debug(name, fsmClass, "canceling timer 't'"), Normal) expectMsgAllOf(1 second, Logging.Debug(name, fsmClass, "canceling timer 't'"), FSM.Normal)
expectNoMsg(1 second) expectNoMsg(1 second)
system.eventStream.unsubscribe(testActor) system.eventStream.unsubscribe(testActor)
} }
@ -251,6 +252,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
}) })
fsmref ! "log" fsmref ! "log"
val fsm = fsmref.underlyingActor val fsm = fsmref.underlyingActor
import FSM.LogEntry
expectMsg(1 second, IndexedSeq(LogEntry(1, 0, "log"))) expectMsg(1 second, IndexedSeq(LogEntry(1, 0, "log")))
fsmref ! "count" fsmref ! "count"
fsmref ! "log" fsmref ! "log"

View file

@ -160,37 +160,37 @@ object FSMTimingSpec {
startWith(Initial, 0) startWith(Initial, 0)
when(Initial) { when(Initial) {
case Ev(TestSingleTimer) case Event(TestSingleTimer, _)
setTimer("tester", Tick, 500 millis, false) setTimer("tester", Tick, 500 millis, false)
goto(TestSingleTimer) goto(TestSingleTimer)
case Ev(TestRepeatedTimer) case Event(TestRepeatedTimer, _)
setTimer("tester", Tick, 100 millis, true) setTimer("tester", Tick, 100 millis, true)
goto(TestRepeatedTimer) using 4 goto(TestRepeatedTimer) using 4
case Ev(TestStateTimeoutOverride) case Event(TestStateTimeoutOverride, _)
goto(TestStateTimeout) forMax (Duration.Inf) goto(TestStateTimeout) forMax (Duration.Inf)
case Ev(x: FSMTimingSpec.State) goto(x) case Event(x: FSMTimingSpec.State, _) goto(x)
} }
when(TestStateTimeout, stateTimeout = 500 millis) { when(TestStateTimeout, stateTimeout = 500 millis) {
case Ev(StateTimeout) goto(Initial) case Event(StateTimeout, _) goto(Initial)
case Ev(Cancel) goto(Initial) replying (Cancel) case Event(Cancel, _) goto(Initial) replying (Cancel)
} }
when(TestSingleTimer) { when(TestSingleTimer) {
case Ev(Tick) case Event(Tick, _)
tester ! Tick tester ! Tick
goto(Initial) goto(Initial)
} }
when(TestCancelTimer) { when(TestCancelTimer) {
case Ev(Tick) case Event(Tick, _)
setTimer("hallo", Tock, 1 milli, false) setTimer("hallo", Tock, 1 milli, false)
TestKit.awaitCond(context.asInstanceOf[ActorCell].mailbox.hasMessages, 1 second) TestKit.awaitCond(context.asInstanceOf[ActorCell].mailbox.hasMessages, 1 second)
cancelTimer("hallo") cancelTimer("hallo")
sender ! Tick sender ! Tick
setTimer("hallo", Tock, 500 millis, false) setTimer("hallo", Tock, 500 millis, false)
stay stay
case Ev(Tock) case Event(Tock, _)
tester ! Tock tester ! Tock
stay stay
case Ev(Cancel) case Event(Cancel, _)
cancelTimer("hallo") cancelTimer("hallo")
goto(Initial) goto(Initial)
} }
@ -206,29 +206,29 @@ object FSMTimingSpec {
} }
when(TestCancelStateTimerInNamedTimerMessage) { when(TestCancelStateTimerInNamedTimerMessage) {
// FSM is suspended after processing this message and resumed 500ms later // FSM is suspended after processing this message and resumed 500ms later
case Ev(Tick) case Event(Tick, _)
suspend(self) suspend(self)
setTimer("named", Tock, 1 millis, false) setTimer("named", Tock, 1 millis, false)
TestKit.awaitCond(context.asInstanceOf[ActorCell].mailbox.hasMessages, 1 second) TestKit.awaitCond(context.asInstanceOf[ActorCell].mailbox.hasMessages, 1 second)
stay forMax (1 millis) replying Tick stay forMax (1 millis) replying Tick
case Ev(Tock) case Event(Tock, _)
goto(TestCancelStateTimerInNamedTimerMessage2) goto(TestCancelStateTimerInNamedTimerMessage2)
} }
when(TestCancelStateTimerInNamedTimerMessage2) { when(TestCancelStateTimerInNamedTimerMessage2) {
case Ev(StateTimeout) case Event(StateTimeout, _)
goto(Initial) goto(Initial)
case Ev(Cancel) case Event(Cancel, _)
goto(Initial) replying Cancel goto(Initial) replying Cancel
} }
when(TestUnhandled) { when(TestUnhandled) {
case Ev(SetHandler) case Event(SetHandler, _)
whenUnhandled { whenUnhandled {
case Ev(Tick) case Event(Tick, _)
tester ! Unhandled(Tick) tester ! Unhandled(Tick)
stay stay
} }
stay stay
case Ev(Cancel) case Event(Cancel, _)
whenUnhandled(NullFunction) whenUnhandled(NullFunction)
goto(Initial) goto(Initial)
} }

View file

@ -5,7 +5,6 @@ package akka.actor
import akka.testkit._ import akka.testkit._
import akka.util.duration._ import akka.util.duration._
import FSM._
import akka.util.Duration import akka.util.Duration
object FSMTransitionSpec { object FSMTransitionSpec {
@ -17,13 +16,13 @@ object FSMTransitionSpec {
class MyFSM(target: ActorRef) extends Actor with FSM[Int, Unit] { class MyFSM(target: ActorRef) extends Actor with FSM[Int, Unit] {
startWith(0, Unit) startWith(0, Unit)
when(0) { when(0) {
case Ev("tick") goto(1) case Event("tick", _) goto(1)
} }
when(1) { when(1) {
case Ev("tick") goto(0) case Event("tick", _) goto(0)
} }
whenUnhandled { whenUnhandled {
case Ev("reply") stay replying "reply" case Event("reply", _) stay replying "reply"
} }
initialize initialize
override def preRestart(reason: Throwable, msg: Option[Any]) { target ! "restarted" } override def preRestart(reason: Throwable, msg: Option[Any]) { target ! "restarted" }
@ -32,10 +31,10 @@ object FSMTransitionSpec {
class OtherFSM(target: ActorRef) extends Actor with FSM[Int, Int] { class OtherFSM(target: ActorRef) extends Actor with FSM[Int, Int] {
startWith(0, 0) startWith(0, 0)
when(0) { when(0) {
case Ev("tick") goto(1) using (1) case Event("tick", _) goto(1) using (1)
} }
when(1) { when(1) {
case Ev(_) stay case _ stay
} }
onTransition { onTransition {
case 0 -> 1 target ! ((stateData, nextStateData)) case 0 -> 1 target ! ((stateData, nextStateData))
@ -56,6 +55,8 @@ class FSMTransitionSpec extends AkkaSpec with ImplicitSender {
"A FSM transition notifier" must { "A FSM transition notifier" must {
"notify listeners" in { "notify listeners" in {
import FSM.{ SubscribeTransitionCallBack, CurrentState, Transition }
val fsm = system.actorOf(Props(new MyFSM(testActor))) val fsm = system.actorOf(Props(new MyFSM(testActor)))
within(1 second) { within(1 second) {
fsm ! SubscribeTransitionCallBack(testActor) fsm ! SubscribeTransitionCallBack(testActor)
@ -77,8 +78,8 @@ class FSMTransitionSpec extends AkkaSpec with ImplicitSender {
})) }))
within(300 millis) { within(300 millis) {
fsm ! SubscribeTransitionCallBack(forward) fsm ! FSM.SubscribeTransitionCallBack(forward)
expectMsg(CurrentState(fsm, 0)) expectMsg(FSM.CurrentState(fsm, 0))
system.stop(forward) system.stop(forward)
fsm ! "tick" fsm ! "tick"
expectNoMsg expectNoMsg

View file

@ -48,6 +48,14 @@ object FSM {
} }
} }
/**
* This extractor is just convenience for matching a (S, S) pair, including a
* reminder what the new state is.
*/
object -> {
def unapply[S](in: (S, S)) = Some(in)
}
case class LogEntry[S, D](stateName: S, stateData: D, event: Any) case class LogEntry[S, D](stateName: S, stateData: D, event: Any)
case class State[S, D](stateName: S, stateData: D, timeout: Option[Duration] = None, stopReason: Option[Reason] = None, replies: List[Any] = Nil) { case class State[S, D](stateName: S, stateData: D, timeout: Option[Duration] = None, stopReason: Option[Reason] = None, replies: List[Any] = Nil) {
@ -174,6 +182,10 @@ trait FSM[S, D] extends Listeners {
type Timeout = Option[Duration] type Timeout = Option[Duration]
type TransitionHandler = PartialFunction[(S, S), Unit] type TransitionHandler = PartialFunction[(S, S), Unit]
// import so that it is visible without an import
val -> = FSM.->
val StateTimeout = FSM.StateTimeout
val log = Logging(context.system, this) val log = Logging(context.system, this)
/** /**
@ -284,14 +296,6 @@ trait FSM[S, D] extends Listeners {
*/ */
protected final def setStateTimeout(state: S, timeout: Timeout): Unit = stateTimeouts(state) = timeout protected final def setStateTimeout(state: S, timeout: Timeout): Unit = stateTimeouts(state) = timeout
/**
* This extractor is just convenience for matching a (S, S) pair, including a
* reminder what the new state is.
*/
object -> {
def unapply[S](in: (S, S)) = Some(in)
}
/** /**
* Set handler which is called upon each state transition, i.e. not when * Set handler which is called upon each state transition, i.e. not when
* staying in the same state. This may use the pair extractor defined in the * staying in the same state. This may use the pair extractor defined in the
@ -533,9 +537,6 @@ trait FSM[S, D] extends Listeners {
} }
case class Event(event: Any, stateData: D) case class Event(event: Any, stateData: D)
object Ev {
def unapply[D](e: Event): Option[Any] = Some(e.event)
}
case class StopEvent[S, D](reason: Reason, currentState: S, stateData: D) case class StopEvent[S, D](reason: Reason, currentState: S, stateData: D)
} }

View file

@ -89,10 +89,10 @@ class TestkitDocSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
val fsm = TestFSMRef(new Actor with FSM[Int, String] { val fsm = TestFSMRef(new Actor with FSM[Int, String] {
startWith(1, "") startWith(1, "")
when(1) { when(1) {
case Ev("go") goto(2) using "go" case Event("go", _) goto(2) using "go"
} }
when(2) { when(2) {
case Ev("back") goto(1) using "back" case Event("back", _) goto(1) using "back"
} }
}) })

View file

@ -12,19 +12,17 @@ import akka.util.duration._
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) @org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class TestFSMRefSpec extends AkkaSpec { class TestFSMRefSpec extends AkkaSpec {
import FSM._
"A TestFSMRef" must { "A TestFSMRef" must {
"allow access to state data" in { "allow access to state data" in {
val fsm = TestFSMRef(new Actor with FSM[Int, String] { val fsm = TestFSMRef(new Actor with FSM[Int, String] {
startWith(1, "") startWith(1, "")
when(1) { when(1) {
case Ev("go") goto(2) using "go" case Event("go", _) goto(2) using "go"
case Ev(StateTimeout) goto(2) using "timeout" case Event(StateTimeout, _) goto(2) using "timeout"
} }
when(2) { when(2) {
case Ev("back") goto(1) using "back" case Event("back", _) goto(1) using "back"
} }
}, "test-fsm-ref-1") }, "test-fsm-ref-1")
fsm.stateName must be(1) fsm.stateName must be(1)