From 08839b3cea4b8d051632f706538b6931df82843b Mon Sep 17 00:00:00 2001 From: Roland Date: Mon, 30 Apr 2012 17:44:03 +0200 Subject: [PATCH 1/4] FSM inherits log instead of having its own, see #1899 --- akka-actor/src/main/scala/akka/actor/FSM.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/FSM.scala b/akka-actor/src/main/scala/akka/actor/FSM.scala index b277142e76..f7ca40771f 100644 --- a/akka-actor/src/main/scala/akka/actor/FSM.scala +++ b/akka-actor/src/main/scala/akka/actor/FSM.scala @@ -172,7 +172,7 @@ object FSM { * timerActive_? ("tock") * */ -trait FSM[S, D] extends Listeners { +trait FSM[S, D] extends Listeners with ActorLogging { this: Actor ⇒ import FSM._ @@ -186,8 +186,6 @@ trait FSM[S, D] extends Listeners { val -> = FSM.-> val StateTimeout = FSM.StateTimeout - val log = Logging(context.system, this) - /** * **************************************** * DSL From 6f19e404111cc9fa1382e1b2867ac41a74502d6a Mon Sep 17 00:00:00 2001 From: Roland Date: Mon, 7 May 2012 13:32:54 +0200 Subject: [PATCH 2/4] add FSM.transform, but needs docs (see #1966) --- .../test/scala/akka/actor/FSMActorSpec.scala | 19 +++++++++++++++++++ .../src/main/scala/akka/actor/FSM.scala | 3 +++ 2 files changed, 22 insertions(+) diff --git a/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala index 3a2c1bb627..a84e23799a 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala @@ -262,6 +262,25 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im expectMsg(1 second, IndexedSeq(LogEntry(1, 1, "log"), LogEntry(1, 1, "count"), LogEntry(1, 2, "log"))) } + "allow transforming of state results" in { + import akka.actor.FSM._ + val fsmref = system.actorOf(Props(new Actor with FSM[Int, Int] { + startWith(0, 0) + when(0)(transform { + case Event("go", _) ⇒ stay + } { + case x ⇒ goto(1) + }) + when(1) { + case _ ⇒ stay + } + })) + fsmref ! SubscribeTransitionCallBack(testActor) + fsmref ! "go" + expectMsg(CurrentState(fsmref, 0)) + expectMsg(Transition(fsmref, 0, 1)) + } + } } diff --git a/akka-actor/src/main/scala/akka/actor/FSM.scala b/akka-actor/src/main/scala/akka/actor/FSM.scala index f7ca40771f..45a8e7d67c 100644 --- a/akka-actor/src/main/scala/akka/actor/FSM.scala +++ b/akka-actor/src/main/scala/akka/actor/FSM.scala @@ -253,6 +253,9 @@ trait FSM[S, D] extends Listeners with ActorLogging { */ protected final def stop(reason: Reason, stateData: D): State = stay using stateData withStopReason (reason) + protected final def transform(func: StateFunction)(andThen: PartialFunction[State, State]): StateFunction = + func andThen (andThen orElse { case x ⇒ x }) + /** * Schedule named timer to deliver message after given delay, possibly repeating. * @param name identifier to be used with cancelTimer() From 838eaa4345861ebf9eb3e576e40c6a4faf118a9b Mon Sep 17 00:00:00 2001 From: Roland Date: Mon, 7 May 2012 17:52:14 +0200 Subject: [PATCH 3/4] make all FSM doc code snippets compiled, see #1871 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - also remove gratuitious (aka wrong) type parameters from StopEvent - document new “transform” funcitonality --- .../src/main/scala/akka/actor/FSM.scala | 8 +- .../code/akka/docs/actor/FSMDocSpec.scala | 117 ++++++++++++- akka-docs/scala/fsm.rst | 163 +++++++----------- 3 files changed, 184 insertions(+), 104 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/FSM.scala b/akka-actor/src/main/scala/akka/actor/FSM.scala index 45a8e7d67c..fbe6622c68 100644 --- a/akka-actor/src/main/scala/akka/actor/FSM.scala +++ b/akka-actor/src/main/scala/akka/actor/FSM.scala @@ -328,7 +328,7 @@ trait FSM[S, D] extends Listeners with ActorLogging { * Convenience wrapper for using a total function instead of a partial * function literal. To be used with onTransition. */ - implicit protected final def total2pf(transitionHandler: (S, S) ⇒ Unit) = + implicit protected final def total2pf(transitionHandler: (S, S) ⇒ Unit): TransitionHandler = new TransitionHandler { def isDefinedAt(in: (S, S)) = true def apply(in: (S, S)) { transitionHandler(in._1, in._2) } @@ -337,7 +337,7 @@ trait FSM[S, D] extends Listeners with ActorLogging { /** * Set handler which is called upon termination of this FSM actor. */ - protected final def onTermination(terminationHandler: PartialFunction[StopEvent[S, D], Unit]): Unit = + protected final def onTermination(terminationHandler: PartialFunction[StopEvent, Unit]): Unit = terminateEvent = terminationHandler /** @@ -416,7 +416,7 @@ trait FSM[S, D] extends Listeners with ActorLogging { /* * termination handling */ - private var terminateEvent: PartialFunction[StopEvent[S, D], Unit] = NullFunction + private var terminateEvent: PartialFunction[StopEvent, Unit] = NullFunction /* * transition handling @@ -539,7 +539,7 @@ trait FSM[S, D] extends Listeners with ActorLogging { case class Event(event: Any, stateData: D) - case class StopEvent[S, D](reason: Reason, currentState: S, stateData: D) + case class StopEvent(reason: Reason, currentState: S, stateData: D) } /** diff --git a/akka-docs/scala/code/akka/docs/actor/FSMDocSpec.scala b/akka-docs/scala/code/akka/docs/actor/FSMDocSpec.scala index 684d0eea3e..3e17c38cc4 100644 --- a/akka-docs/scala/code/akka/docs/actor/FSMDocSpec.scala +++ b/akka-docs/scala/code/akka/docs/actor/FSMDocSpec.scala @@ -37,11 +37,15 @@ class FSMDocSpec extends AkkaSpec { //#simple-fsm class Buncher extends Actor with FSM[State, Data] { + //#fsm-body startWith(Idle, Uninitialized) + //#when-syntax when(Idle) { - case Event(SetTarget(ref), Uninitialized) ⇒ stay using Todo(ref, Vector.empty) + case Event(SetTarget(ref), Uninitialized) ⇒ + stay using Todo(ref, Vector.empty) } + //#when-syntax //#transition-elided onTransition { @@ -51,10 +55,13 @@ class FSMDocSpec extends AkkaSpec { } } //#transition-elided + //#when-syntax when(Active, stateTimeout = 1 second) { - case Event(Flush | FSM.StateTimeout, t: Todo) ⇒ goto(Idle) using t.copy(queue = Vector.empty) + case Event(Flush | StateTimeout, t: Todo) ⇒ + goto(Idle) using t.copy(queue = Vector.empty) } + //#when-syntax //#unhandled-elided whenUnhandled { @@ -67,10 +74,116 @@ class FSMDocSpec extends AkkaSpec { stay } //#unhandled-elided + //#fsm-body initialize } //#simple-fsm + object DemoCode { + trait StateType + case object SomeState extends StateType + case object Processing extends StateType + case object Error extends StateType + case object Idle extends StateType + case object Active extends StateType + + class Dummy extends Actor with FSM[StateType, Int] { + class X + val newData = 42 + object WillDo + object Tick + + //#modifier-syntax + when(SomeState) { + case Event(msg, _) ⇒ + goto(Processing) using (newData) forMax (5 seconds) replying (WillDo) + } + //#modifier-syntax + + //#transition-syntax + onTransition { + case Idle -> Active ⇒ setTimer("timeout", Tick, 1 second, true) + case Active -> _ ⇒ cancelTimer("timeout") + case x -> Idle ⇒ log.info("entering Idle from " + x) + } + //#transition-syntax + + //#alt-transition-syntax + onTransition(handler _) + + def handler(from: StateType, to: StateType) { + // handle it here ... + } + //#alt-transition-syntax + + //#stop-syntax + when(Error) { + case Event("stop", _) ⇒ + // do cleanup ... + stop() + } + //#stop-syntax + + //#transform-syntax + when(SomeState)(transform { + case Event(bytes: Array[Byte], read) ⇒ stay using (read + bytes.length) + case Event(bytes: List[Byte], read) ⇒ stay using (read + bytes.size) + } { + case s @ FSM.State(state, read, timeout, stopReason, replies) if read > 1000 ⇒ + goto(Processing) + }) + //#transform-syntax + + //#alt-transform-syntax + val processingTrigger: PartialFunction[State, State] = { + case s @ FSM.State(state, read, timeout, stopReason, replies) if read > 1000 ⇒ + goto(Processing) + } + + when(SomeState)(transform { + case Event(bytes: Array[Byte], read) ⇒ stay using (read + bytes.length) + case Event(bytes: List[Byte], read) ⇒ stay using (read + bytes.size) + }(processingTrigger)) + //#alt-transform-syntax + + //#termination-syntax + onTermination { + case StopEvent(FSM.Normal, state, data) ⇒ // ... + case StopEvent(FSM.Shutdown, state, data) ⇒ // ... + case StopEvent(FSM.Failure(cause), state, data) ⇒ // ... + } + //#termination-syntax + + //#unhandled-syntax + whenUnhandled { + case Event(x: X, data) ⇒ + log.info("Received unhandled event: " + x) + stay + case Event(msg, _) ⇒ + log.warning("Received unknown event: " + msg) + goto(Error) + } + //#unhandled-syntax + + } + + //#logging-fsm + import akka.actor.LoggingFSM + class MyFSM extends Actor with LoggingFSM[StateType, Data] { + //#body-elided + override def logDepth = 12 + onTermination { + case StopEvent(FSM.Failure(_), state, data) ⇒ + val lastEvents = getLog.mkString("\n\t") + log.warning("Failure in state " + state + " with data " + data + "\n" + + "Events leading up to this point:\n\t" + lastEvents) + } + // ... + //#body-elided + } + //#logging-fsm + + } //#fsm-code-elided "batch correctly" in { diff --git a/akka-docs/scala/fsm.rst b/akka-docs/scala/fsm.rst index 0dcc12ed67..3b60058701 100644 --- a/akka-docs/scala/fsm.rst +++ b/akka-docs/scala/fsm.rst @@ -118,19 +118,11 @@ The FSM Trait and Object The :class:`FSM` trait may only be mixed into an :class:`Actor`. Instead of extending :class:`Actor`, the self type approach was chosen in order to make it -obvious that an actor is actually created. Importing all members of the -:obj:`FSM` object is recommended if you want to directly access the symbols -like :obj:`StateTimeout`. This import is usually placed inside the state -machine definition: +obvious that an actor is actually created: -.. code-block:: scala - - class MyFSM extends Actor with FSM[State, Data] { - import FSM._ - - ... - - } +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: simple-fsm + :exclude: fsm-body The :class:`FSM` trait takes two type parameters: @@ -153,7 +145,7 @@ Defining States A state is defined by one or more invocations of the method - :func:`when([, stateTimeout = ])(stateFunction)`. + :func:`when([, stateTimeout = ])(stateFunction)`. The given name must be an object which is type-compatible with the first type parameter given to the :class:`FSM` trait. This object is used as a hash key, @@ -165,27 +157,18 @@ If the :meth:`stateTimeout` parameter is given, then all transitions into this state, including staying, receive this timeout by default. Initiating the transition with an explicit timeout may be used to override this default, see `Initiating Transitions`_ for more information. The state timeout of any state -may be changed during action processing with :func:`setStateTimeout(state, -duration)`. This enables runtime configuration e.g. via external message. +may be changed during action processing with +:func:`setStateTimeout(state, duration)`. This enables runtime configuration +e.g. via external message. -The :meth:`stateFunction` argument is a :class:`PartialFunction[Event, State]`, +The :meth:`stateFunction` argument is a :class:`PartialFunction[Event, State]`, which is conveniently given using the partial function literal syntax as demonstrated below: -.. code-block:: scala +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: when-syntax - when(Idle) { - case Event(Start(msg), _) => - goto(Timer) using (msg, sender) - } - - when(Timer, stateTimeout = 12 seconds) { - case Event(StateTimeout, (msg, sender)) => - sender ! msg - goto(Idle) - } - -The :class:`Event(msg: Any, data: D)` case class is parameterized with the data +The :class:`Event(msg: Any, data: D)` case class is parameterized with the data type held by the FSM for convenient pattern matching. Defining the Initial State @@ -193,7 +176,7 @@ Defining the Initial State Each FSM needs a starting point, which is declared using - :func:`startWith(state, data[, timeout])` + :func:`startWith(state, data[, timeout])` The optionally given timeout argument overrides any specification given for the desired initial state. If you want to cancel a default timeout, use @@ -206,16 +189,8 @@ If a state doesn't handle a received event a warning is logged. If you want to do something else in this case you can specify that with :func:`whenUnhandled(stateFunction)`: -.. code-block:: scala - - whenUnhandled { - case Event(x : X, data) => - log.info(this, "Received unhandled event: " + x) - stay - case Event(msg, _) => - log.warn(this, "Received unknown event: " + x) - goto(Error) - } +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: unhandled-syntax **IMPORTANT**: This handler is not stacked, meaning that each invocation of :func:`whenUnhandled` replaces the previously installed handler. @@ -230,7 +205,8 @@ The state definition can either be the current state, as described by the :func:`goto(state)`. The resulting object allows further qualification by way of the modifiers described in the following: -:meth:`forMax(duration)` +* :meth:`forMax(duration)` + This modifier sets a state timeout on the next state. This means that a timer is started which upon expiry sends a :obj:`StateTimeout` message to the FSM. This timer is canceled upon reception of any other message in the meantime; @@ -241,23 +217,21 @@ of the modifiers described in the following: specified for the target state. If you want to cancel the default timeout, use :obj:`Duration.Inf`. -:meth:`using(data)` +* :meth:`using(data)` + This modifier replaces the old state data with the new data given. If you follow the advice :ref:`above `, this is the only place where internal state data are ever modified. -:meth:`replying(msg)` +* :meth:`replying(msg)` + This modifier sends a reply to the currently processed message and otherwise does not modify the state transition. All modifier can be chained to achieve a nice and concise description: -.. code-block:: scala - - when(State) { - case Event(msg, _) => - goto(Processing) using (msg) forMax (5 seconds) replying (WillDo) - } +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: modifier-syntax The parentheses are not actually needed in all cases, but they visually distinguish between modifiers and their arguments and therefore make the code @@ -267,7 +241,7 @@ even more pleasant to read for foreigners. Please note that the ``return`` statement may not be used in :meth:`when` blocks or similar; this is a Scala restriction. Either refactor your code - using ``if () ... else ...`` or move it into a method definition. + using ``if () ... else ...`` or move it into a method definition. Monitoring Transitions ---------------------- @@ -293,13 +267,8 @@ The handler is a partial function which takes a pair of states as input; no resulting state is needed as it is not possible to modify the transition in progress. -.. code-block:: scala - - onTransition { - case Idle -> Active => setTimer("timeout") - case Active -> _ => cancelTimer("timeout") - case x -> Idle => log.info("entering Idle from "+x) - } +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: transition-syntax The convenience extractor :obj:`->` enables decomposition of the pair of states with a clear visual reminder of the transition's direction. As usual in pattern @@ -311,13 +280,8 @@ It is also possible to pass a function object accepting two states to :func:`onTransition`, in case your transition handling logic is implemented as a method: -.. code-block:: scala - - onTransition(handler _) - - private def handler(from: State, to: State) { - ... - } +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: alt-transition-syntax The handlers registered with this method are stacked, so you can intersperse :func:`onTransition` blocks with :func:`when` blocks as suits your design. It @@ -338,8 +302,8 @@ External Monitoring External actors may be registered to be notified of state transitions by sending a message :class:`SubscribeTransitionCallBack(actorRef)`. The named -actor will be sent a :class:`CurrentState(self, stateName)` message immediately -and will receive :class:`Transition(actorRef, oldState, newState)` messages +actor will be sent a :class:`CurrentState(self, stateName)` message immediately +and will receive :class:`Transition(actorRef, oldState, newState)` messages whenever a new state is reached. External monitors may be unregistered by sending :class:`UnsubscribeTransitionCallBack(actorRef)` to the FSM actor. @@ -347,13 +311,33 @@ Registering a not-running listener generates a warning and fails gracefully. Stopping a listener without unregistering will remove the listener from the subscription list upon the next transition. +Transforming State +------------------ + +The partial functions supplied as argument to the ``when()`` blocks can be +transformed using Scala’s full supplement of functional programming tools. In +order to retain type inference, there is a helper function which may be used in +case some common handling logic shall be applied to different clauses: + +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: transform-syntax + +It goes without saying that the arguments to this method may also be stored, to +be used several times, e.g. when applying the same transformation to several +``when()`` blocks: + +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: alt-transform-syntax + +The parentheses are required by Scala’s syntax rules. + Timers ------ Besides state timeouts, FSM manages timers identified by :class:`String` names. You may set a timer using - :func:`setTimer(name, msg, interval, repeat)` + :func:`setTimer(name, msg, interval, repeat)` where :obj:`msg` is the message object which will be sent after the duration :obj:`interval` has elapsed. If :obj:`repeat` is :obj:`true`, then the timer is @@ -376,7 +360,7 @@ Termination from Inside The FSM is stopped by specifying the result state as - :func:`stop([reason[, data]])` + :func:`stop([reason[, data]])` The reason must be one of :obj:`Normal` (which is the default), :obj:`Shutdown` or :obj:`Failure(reason)`, and the second argument may be given to change the @@ -389,25 +373,15 @@ state data which is available during termination handling. the same way as a state transition (but note that the ``return`` statement may not be used within a :meth:`when` block). -.. code-block:: scala - - when(A) { - case Event(Stop, _) => - doCleanup() - stop() - } +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: stop-syntax You can use :func:`onTermination(handler)` to specify custom code that is executed when the FSM is stopped. The handler is a partial function which takes -a :class:`StopEvent(reason, stateName, stateData)` as argument: +a :class:`StopEvent(reason, stateName, stateData)` as argument: -.. code-block:: scala - - onTermination { - case StopEvent(Normal, s, d) => ... - case StopEvent(Shutdown, _, _) => ... - case StopEvent(Failure(cause), s, d) => ... - } +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: termination-syntax As for the :func:`whenUnhandled` case, this handler is not stacked, so each invocation of :func:`onTermination` replaces the previously installed handler. @@ -419,7 +393,7 @@ When an :class:`ActorRef` associated to a FSM is stopped using the :meth:`stop()` method, its :meth:`postStop` hook will be executed. The default implementation by the :class:`FSM` trait is to execute the :meth:`onTermination` handler if that is prepared to handle a -:obj:`StopEvent(Shutdown, ...)`. +:obj:`StopEvent(Shutdown, ...)`. .. warning:: @@ -438,11 +412,11 @@ Event Tracing ------------- The setting ``akka.actor.debug.fsm`` in :ref:`configuration` enables logging of an -event trace by :class:`LoggingFSM` instances:: +event trace by :class:`LoggingFSM` instances: - class MyFSM extends Actor with LoggingFSM[X, Z] { - ... - } +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: logging-fsm + :exclude: body-elided This FSM will log at DEBUG level: @@ -459,17 +433,10 @@ Rolling Event Log The :class:`LoggingFSM` trait adds one more feature to the FSM: a rolling event log which may be used during debugging (for tracing how the FSM entered a -certain failure state) or for other creative uses:: +certain failure state) or for other creative uses: - class MyFSM extends Actor with LoggingFSM[X, Z] { - override def logDepth = 12 - onTermination { - case StopEvent(Failure(_), state, data) => - log.warning(this, "Failure in state "+state+" with data "+data+"\n"+ - "Events leading up to this point:\n\t"+getLog.mkString("\n\t")) - } - ... - } +.. includecode:: code/akka/docs/actor/FSMDocSpec.scala + :include: logging-fsm The :meth:`logDepth` defaults to zero, which turns off the event log. From c3f7aac8f3342c5b47e9dac6988b422ff7cbe289 Mon Sep 17 00:00:00 2001 From: Roland Date: Mon, 7 May 2012 18:21:26 +0200 Subject: [PATCH 4/4] make transform DSL nicer, see #1966 --- .../src/test/scala/akka/actor/FSMActorSpec.scala | 2 +- akka-actor/src/main/scala/akka/actor/FSM.scala | 12 ++++++++---- .../scala/code/akka/docs/actor/FSMDocSpec.scala | 4 ++-- akka-docs/scala/fsm.rst | 2 -- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala index a84e23799a..ef49cbc18d 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala @@ -268,7 +268,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im startWith(0, 0) when(0)(transform { case Event("go", _) ⇒ stay - } { + } using { case x ⇒ goto(1) }) when(1) { diff --git a/akka-actor/src/main/scala/akka/actor/FSM.scala b/akka-actor/src/main/scala/akka/actor/FSM.scala index fbe6622c68..db89f58946 100644 --- a/akka-actor/src/main/scala/akka/actor/FSM.scala +++ b/akka-actor/src/main/scala/akka/actor/FSM.scala @@ -217,8 +217,8 @@ trait FSM[S, D] extends Listeners with ActorLogging { * @param timeout state timeout for the initial state, overriding the default timeout for that state */ protected final def startWith(stateName: S, - stateData: D, - timeout: Timeout = None): Unit = + stateData: D, + timeout: Timeout = None): Unit = currentState = FSM.State(stateName, stateData, timeout) /** @@ -253,8 +253,12 @@ trait FSM[S, D] extends Listeners with ActorLogging { */ protected final def stop(reason: Reason, stateData: D): State = stay using stateData withStopReason (reason) - protected final def transform(func: StateFunction)(andThen: PartialFunction[State, State]): StateFunction = - func andThen (andThen orElse { case x ⇒ x }) + protected final class TransformHelper(func: StateFunction) { + def using(andThen: PartialFunction[State, State]): StateFunction = + func andThen (andThen orElse { case x ⇒ x }) + } + + protected final def transform(func: StateFunction): TransformHelper = new TransformHelper(func) /** * Schedule named timer to deliver message after given delay, possibly repeating. diff --git a/akka-docs/scala/code/akka/docs/actor/FSMDocSpec.scala b/akka-docs/scala/code/akka/docs/actor/FSMDocSpec.scala index 3e17c38cc4..158f8979a0 100644 --- a/akka-docs/scala/code/akka/docs/actor/FSMDocSpec.scala +++ b/akka-docs/scala/code/akka/docs/actor/FSMDocSpec.scala @@ -128,7 +128,7 @@ class FSMDocSpec extends AkkaSpec { when(SomeState)(transform { case Event(bytes: Array[Byte], read) ⇒ stay using (read + bytes.length) case Event(bytes: List[Byte], read) ⇒ stay using (read + bytes.size) - } { + } using { case s @ FSM.State(state, read, timeout, stopReason, replies) if read > 1000 ⇒ goto(Processing) }) @@ -143,7 +143,7 @@ class FSMDocSpec extends AkkaSpec { when(SomeState)(transform { case Event(bytes: Array[Byte], read) ⇒ stay using (read + bytes.length) case Event(bytes: List[Byte], read) ⇒ stay using (read + bytes.size) - }(processingTrigger)) + } using processingTrigger) //#alt-transform-syntax //#termination-syntax diff --git a/akka-docs/scala/fsm.rst b/akka-docs/scala/fsm.rst index 3b60058701..807cd7567c 100644 --- a/akka-docs/scala/fsm.rst +++ b/akka-docs/scala/fsm.rst @@ -329,8 +329,6 @@ be used several times, e.g. when applying the same transformation to several .. includecode:: code/akka/docs/actor/FSMDocSpec.scala :include: alt-transform-syntax -The parentheses are required by Scala’s syntax rules. - Timers ------