diff --git a/src/Automatonymous.Tests/Condition_Specs.cs b/src/Automatonymous.Tests/Condition_Specs.cs index 6316925..e44f339 100644 --- a/src/Automatonymous.Tests/Condition_Specs.cs +++ b/src/Automatonymous.Tests/Condition_Specs.cs @@ -44,6 +44,15 @@ public async Task Should_allow_if_condition_to_be_evaluated() Assert.That(_instance.CurrentState, Is.Not.EqualTo(_machine.ShouldNotBeHere)); } + [Test] + public async Task Should_evaluate_else_statement_when_if_condition__is_false() + { + await _machine.RaiseEvent(_instance, _machine.ExplicitFilterStarted, new StartedExplicitFilter()); + + Assert.That(_instance.ShouldBeCalled, Is.True); + } + + [SetUp] public void Specifying_an_event_activity() { @@ -59,6 +68,8 @@ class Instance { public bool InitializeOnly { get; set; } public State CurrentState { get; set; } + + public bool ShouldBeCalled { get; set; } } @@ -75,10 +86,13 @@ public InstanceStateMachine() During(Initial, When(ExplicitFilterStarted, context => true) - .If(context => false, binder => binder - .Then(context => Console.WriteLine("Should not be here!")) - .TransitionTo(ShouldNotBeHere)) - .If(context => true, binder => binder.Then(context => Console.WriteLine("Initializing Only!")))); + .IfElse(context => false, + binder => binder + .Then(context => Console.WriteLine("Should not be here!")) + .TransitionTo(ShouldNotBeHere), + binder => binder + .Then(context => context.Instance.ShouldBeCalled = true) + .Then(context => Console.WriteLine("Initializing Only!")))); During(Running, When(Finish) @@ -136,6 +150,14 @@ public async Task Should_allow_if_condition_to_be_evaluated() Assert.That(_instance.CurrentState, Is.Not.EqualTo(_machine.ShouldNotBeHere)); } + [Test] + public async Task Should_evaluate_else_statement_when_if_condition__is_false() + { + await _machine.RaiseEvent(_instance, _machine.ExplicitFilterStarted, new StartedExplicitFilter()); + + Assert.That(_instance.ShouldBeCalled, Is.True); + } + [SetUp] public void Specifying_an_event_activity() { @@ -151,6 +173,7 @@ class Instance { public bool InitializeOnly { get; set; } public State CurrentState { get; set; } + public bool ShouldBeCalled { get; set; } } @@ -167,10 +190,13 @@ public InstanceStateMachine() During(Initial, When(ExplicitFilterStarted, context => true) - .IfAsync(context => Task.FromResult(false), binder => binder - .Then(context => Console.WriteLine("Should not be here!")) - .TransitionTo(ShouldNotBeHere)) - .IfAsync(context => Task.FromResult(true), binder => binder.Then(context => Console.WriteLine("Initializing Only!")))); + .IfElseAsync(context => Task.FromResult(false), + binder => binder + .Then(context => Console.WriteLine("Should not be here!")) + .TransitionTo(ShouldNotBeHere), + binder => binder + .Then(context => context.Instance.ShouldBeCalled = true) + .Then(context => Console.WriteLine("Initializing Only!")))); During(Running, When(Finish) diff --git a/src/Automatonymous.Tests/Exception_Specs.cs b/src/Automatonymous.Tests/Exception_Specs.cs index 00ffc45..e710de5 100644 --- a/src/Automatonymous.Tests/Exception_Specs.cs +++ b/src/Automatonymous.Tests/Exception_Specs.cs @@ -51,7 +51,12 @@ public Instance() public bool ShouldNotBeCalled { get; set; } public bool CalledThenClause { get; set; } - public bool CalledSecondThenClause { get; set; } + public bool CalledThenClauseAsync { get; set; } + + public bool ThenShouldNotBeCalled { get; set; } + public bool ElseShouldBeCalled { get; set; } + public bool ThenAsyncShouldNotBeCalled { get; set; } + public bool ElseAsyncShouldBeCalled { get; set; } } @@ -70,7 +75,15 @@ public InstanceStateMachine() .Then(context => context.Instance.CalledThenClause = true) ) .IfAsync(context => Task.FromResult(true), b => b - .Then(context => context.Instance.CalledSecondThenClause = true) + .Then(context => context.Instance.CalledThenClauseAsync = true) + ) + .IfElse(context => false, + b => b.Then(context => context.Instance.ThenShouldNotBeCalled = true), + b => b.Then(context => context.Instance.ElseShouldBeCalled = true) + ) + .IfElseAsync(context => Task.FromResult(false), + b => b.Then(context => context.Instance.ThenAsyncShouldNotBeCalled = true), + b => b.Then(context => context.Instance.ElseAsyncShouldBeCalled = true) ) .Then(context => { @@ -142,7 +155,31 @@ public void Should_have_called_the_first_if_block() [Test] public void Should_have_called_the_async_if_block() { - Assert.IsTrue(_instance.CalledSecondThenClause); + Assert.IsTrue(_instance.CalledThenClauseAsync); + } + + [Test] + public void Should_not_have_called_the_false_condition_then_block() + { + Assert.IsFalse(_instance.ThenShouldNotBeCalled); + } + + [Test] + public void Should_not_have_called_the_false_async_condition_then_block() + { + Assert.IsFalse(_instance.ThenAsyncShouldNotBeCalled); + } + + [Test] + public void Should_have_called_the_false_condition_else_block() + { + Assert.IsTrue(_instance.ElseShouldBeCalled); + } + + [Test] + public void Should_have_called_the_false_async_condition_else_block() + { + Assert.IsTrue(_instance.ElseAsyncShouldBeCalled); } } @@ -316,6 +353,11 @@ public Instance() public bool CalledThenClause { get; set; } public bool CalledSecondThenClause { get; set; } + + public bool ThenShouldNotBeCalled { get; set; } + public bool ElseShouldBeCalled { get; set; } + public bool ThenAsyncShouldNotBeCalled { get; set; } + public bool ElseAsyncShouldBeCalled { get; set; } } @@ -343,6 +385,14 @@ public InstanceStateMachine() .IfAsync(context => Task.FromResult(true), b => b .Then(context => context.Instance.CalledSecondThenClause = true) ) + .IfElse(context => false, + b => b.Then(context => context.Instance.ThenShouldNotBeCalled = true), + b => b.Then(context => context.Instance.ElseShouldBeCalled = true) + ) + .IfElseAsync(context => Task.FromResult(false), + b => b.Then(context => context.Instance.ThenAsyncShouldNotBeCalled = true), + b => b.Then(context => context.Instance.ElseAsyncShouldBeCalled = true) + ) .Then(context => { context.Instance.ExceptionMessage = context.Exception.Message; @@ -398,5 +448,30 @@ public void Should_have_called_the_async_if_block() { Assert.IsTrue(_instance.CalledSecondThenClause); } + + [Test] + public void Should_not_have_called_the_false_condition_then_block() + { + Assert.IsFalse(_instance.ThenShouldNotBeCalled); + } + + [Test] + public void Should_not_have_called_the_false_async_condition_then_block() + { + Assert.IsFalse(_instance.ThenAsyncShouldNotBeCalled); + } + + [Test] + public void Should_have_called_the_false_condition_else_block() + { + Assert.IsTrue(_instance.ElseShouldBeCalled); + } + + [Test] + public void Should_have_called_the_false_async_condition_else_block() + { + Assert.IsTrue(_instance.ElseAsyncShouldBeCalled); + } } + } \ No newline at end of file diff --git a/src/Automatonymous/Activities/ConditionActivity.cs b/src/Automatonymous/Activities/ConditionActivity.cs index 4edf61c..138fefa 100644 --- a/src/Automatonymous/Activities/ConditionActivity.cs +++ b/src/Automatonymous/Activities/ConditionActivity.cs @@ -20,31 +20,37 @@ public class ConditionActivity : Activity where TInstance : class { - readonly Behavior _behavior; + readonly Behavior _thenBehavior; + readonly Behavior _elseBehavior; readonly StateMachineAsyncCondition _condition; - public ConditionActivity(StateMachineAsyncCondition condition, Behavior behavior) + public ConditionActivity(StateMachineAsyncCondition condition, Behavior thenBehavior, Behavior elseBehavior) { _condition = condition; - _behavior = behavior; + _thenBehavior = thenBehavior; + _elseBehavior = elseBehavior; } void IProbeSite.Probe(ProbeContext context) { var scope = context.CreateScope("condition"); - _behavior.Probe(scope); + _thenBehavior.Probe(scope); + _elseBehavior.Probe(scope); } void Visitable.Accept(StateMachineVisitor visitor) { - visitor.Visit(this, x => _behavior.Accept(visitor)); + visitor.Visit(this, x => _thenBehavior.Accept(visitor)); + visitor.Visit(this, x => _elseBehavior.Accept(visitor)); } async Task Activity.Execute(BehaviorContext context, Behavior next) { if (await _condition(context).ConfigureAwait(false)) - await _behavior.Execute(context).ConfigureAwait(false); + await _thenBehavior.Execute(context).ConfigureAwait(false); + else + await _elseBehavior.Execute(context).ConfigureAwait(false); await next.Execute(context).ConfigureAwait(false); } @@ -52,7 +58,9 @@ async Task Activity.Execute(BehaviorContext context, Behav async Task Activity.Execute(BehaviorContext context, Behavior next) { if (await _condition(context).ConfigureAwait(false)) - await _behavior.Execute(context).ConfigureAwait(false); + await _thenBehavior.Execute(context).ConfigureAwait(false); + else + await _elseBehavior.Execute(context).ConfigureAwait(false); await next.Execute(context).ConfigureAwait(false); } @@ -74,25 +82,29 @@ public class ConditionActivity : Activity where TInstance : class { - readonly Behavior _behavior; + readonly Behavior _thenBehavior; + readonly Behavior _elseBehavior; readonly StateMachineAsyncCondition _condition; - public ConditionActivity(StateMachineAsyncCondition condition, Behavior behavior) + public ConditionActivity(StateMachineAsyncCondition condition, Behavior thenBehavior, Behavior elseBehavior) { _condition = condition; - _behavior = behavior; + _thenBehavior = thenBehavior; + _elseBehavior = elseBehavior; } void IProbeSite.Probe(ProbeContext context) { var scope = context.CreateScope("condition"); - _behavior.Probe(scope); + _thenBehavior.Probe(scope); + _elseBehavior.Probe(scope); } void Visitable.Accept(StateMachineVisitor visitor) { - visitor.Visit(this, x => _behavior.Accept(visitor)); + visitor.Visit(this, x => _thenBehavior.Accept(visitor)); + visitor.Visit(this, x => _elseBehavior.Accept(visitor)); } Task Activity.Execute(BehaviorContext context, Behavior next) @@ -106,7 +118,9 @@ async Task Activity.Execute(BehaviorContext context, if (behaviorContext != null) { if (await _condition(behaviorContext).ConfigureAwait(false)) - await _behavior.Execute(behaviorContext).ConfigureAwait(false); + await _thenBehavior.Execute(behaviorContext).ConfigureAwait(false); + else + await _elseBehavior.Execute(behaviorContext).ConfigureAwait(false); } await next.Execute(context).ConfigureAwait(false); diff --git a/src/Automatonymous/Activities/ConditionExceptionActivity.cs b/src/Automatonymous/Activities/ConditionExceptionActivity.cs index 92446f1..7f07494 100644 --- a/src/Automatonymous/Activities/ConditionExceptionActivity.cs +++ b/src/Automatonymous/Activities/ConditionExceptionActivity.cs @@ -22,25 +22,30 @@ public class ConditionExceptionActivity : where TInstance : class where TConditionException : Exception { - readonly Behavior _behavior; + readonly Behavior _thenBehavior; + readonly Behavior _elseBehavior; readonly StateMachineAsyncExceptionCondition _condition; - public ConditionExceptionActivity(StateMachineAsyncExceptionCondition condition, Behavior behavior) + public ConditionExceptionActivity(StateMachineAsyncExceptionCondition condition, + Behavior thenBehavior, Behavior elseBehavior) { _condition = condition; - _behavior = behavior; + _thenBehavior = thenBehavior; + _elseBehavior = elseBehavior; } void IProbeSite.Probe(ProbeContext context) { var scope = context.CreateScope("condition"); - _behavior.Probe(scope); + _thenBehavior.Probe(scope); + _elseBehavior.Probe(scope); } void Visitable.Accept(StateMachineVisitor visitor) { - visitor.Visit(this, x => _behavior.Accept(visitor)); + visitor.Visit(this, x => _thenBehavior.Accept(visitor)); + visitor.Visit(this, x => _elseBehavior.Accept(visitor)); } Task Activity.Execute(BehaviorContext context, Behavior next) @@ -60,7 +65,11 @@ async Task Activity.Faulted(BehaviorExceptionContext.Faulted(BehaviorExceptionContext : where TInstance : class where TConditionException : Exception { - readonly Behavior _behavior; + readonly Behavior _thenBehavior; + readonly Behavior _elseBehavior; readonly StateMachineAsyncExceptionCondition _condition; - public ConditionExceptionActivity(StateMachineAsyncExceptionCondition condition, Behavior behavior) + public ConditionExceptionActivity(StateMachineAsyncExceptionCondition condition, + Behavior thenBehavior, Behavior elseBehavior) { _condition = condition; - _behavior = behavior; + _thenBehavior = thenBehavior; + _elseBehavior = elseBehavior; } void IProbeSite.Probe(ProbeContext context) { var scope = context.CreateScope("condition"); - _behavior.Probe(scope); + _thenBehavior.Probe(scope); + _elseBehavior.Probe(scope); } void Visitable.Accept(StateMachineVisitor visitor) { - visitor.Visit(this, x => _behavior.Accept(visitor)); + visitor.Visit(this, x => _thenBehavior.Accept(visitor)); + visitor.Visit(this, x => _elseBehavior.Accept(visitor)); } Task Activity.Execute(BehaviorContext context, Behavior next) @@ -133,7 +151,11 @@ async Task Activity.Faulted(BehaviorExceptionContext If( StateMachineExceptionCondition condition, Func, ExceptionActivityBinder> activityCallback) { - ExceptionActivityBinder binder = new CatchExceptionActivityBinder(_machine, _event); - - binder = activityCallback(binder); - - var conditionBinder = new ConditionalExceptionActivityBinder(_event, condition, binder); - - return new CatchExceptionActivityBinder(_machine, _event, _activities, conditionBinder); + return IfElse(condition, activityCallback, _ => _); } public ExceptionActivityBinder IfAsync( StateMachineAsyncExceptionCondition condition, Func, ExceptionActivityBinder> activityCallback) { - ExceptionActivityBinder binder = new CatchExceptionActivityBinder(_machine, _event); + return IfElseAsync(condition, activityCallback, _ => _); + } - binder = activityCallback(binder); + public ExceptionActivityBinder IfElse(StateMachineExceptionCondition condition, + Func, ExceptionActivityBinder> thenActivityCallback, + Func, ExceptionActivityBinder> elseActivityCallback) + { + var thenBinder = GetBinder(thenActivityCallback); + var elseBinder = GetBinder(elseActivityCallback); + + var conditionBinder = new ConditionalExceptionActivityBinder(_event, condition, thenBinder, elseBinder); - var conditionBinder = new ConditionalExceptionActivityBinder(_event, condition, binder); + return new CatchExceptionActivityBinder(_machine, _event, _activities, conditionBinder); + } + + public ExceptionActivityBinder IfElseAsync(StateMachineAsyncExceptionCondition condition, + Func, ExceptionActivityBinder> thenActivityCallback, + Func, ExceptionActivityBinder> elseActivityCallback) + { + var thenBinder = GetBinder(thenActivityCallback); + var elseBinder = GetBinder(elseActivityCallback); + + var conditionBinder = new ConditionalExceptionActivityBinder(_event, condition, thenBinder, elseBinder); return new CatchExceptionActivityBinder(_machine, _event, _activities, conditionBinder); } + + private ExceptionActivityBinder GetBinder(Func, ExceptionActivityBinder> callback) + { + ExceptionActivityBinder thenBinder = new CatchExceptionActivityBinder(_machine, _event); + return callback(thenBinder); + } } @@ -171,27 +189,43 @@ public ExceptionActivityBinder Catch( public ExceptionActivityBinder If(StateMachineExceptionCondition condition, Func, ExceptionActivityBinder> activityCallback) { - ExceptionActivityBinder binder = - new CatchExceptionActivityBinder(_machine, _event); + return IfElse(condition, activityCallback, _ => _); + } - binder = activityCallback(binder); + public ExceptionActivityBinder IfAsync(StateMachineAsyncExceptionCondition condition, + Func, ExceptionActivityBinder> activityCallback) + { + return IfElseAsync(condition, activityCallback, _ => _); + } + + public ExceptionActivityBinder IfElse(StateMachineExceptionCondition condition, + Func, ExceptionActivityBinder> thenActivityCallback, + Func, ExceptionActivityBinder> elseActivityCallback) + { + var thenBinder = GetBinder(thenActivityCallback); + var elseBinder = GetBinder(elseActivityCallback); - var conditionBinder = new ConditionalExceptionActivityBinder(_event, condition, binder); + var conditionBinder = new ConditionalExceptionActivityBinder(_event, condition, thenBinder, elseBinder); return new CatchExceptionActivityBinder(_machine, _event, _activities, conditionBinder); } - public ExceptionActivityBinder IfAsync(StateMachineAsyncExceptionCondition condition, - Func, ExceptionActivityBinder> activityCallback) + public ExceptionActivityBinder IfElseAsync(StateMachineAsyncExceptionCondition condition, + Func, ExceptionActivityBinder> thenActivityCallback, + Func, ExceptionActivityBinder> elseActivityCallback) { - ExceptionActivityBinder binder = - new CatchExceptionActivityBinder(_machine, _event); - - binder = activityCallback(binder); + var thenBinder = GetBinder(thenActivityCallback); + var elseBinder = GetBinder(elseActivityCallback); - var conditionBinder = new ConditionalExceptionActivityBinder(_event, condition, binder); + var conditionBinder = new ConditionalExceptionActivityBinder(_event, condition, thenBinder, elseBinder); return new CatchExceptionActivityBinder(_machine, _event, _activities, conditionBinder); } + + private ExceptionActivityBinder GetBinder(Func, ExceptionActivityBinder> callback) + { + ExceptionActivityBinder binder = new CatchExceptionActivityBinder(_machine, _event); + return callback(binder); + } } } \ No newline at end of file diff --git a/src/Automatonymous/Binders/ConditionalActivityBinder.cs b/src/Automatonymous/Binders/ConditionalActivityBinder.cs index 7608ce6..0962c66 100644 --- a/src/Automatonymous/Binders/ConditionalActivityBinder.cs +++ b/src/Automatonymous/Binders/ConditionalActivityBinder.cs @@ -21,18 +21,24 @@ public class ConditionalActivityBinder : ActivityBinder where TInstance : class { - readonly EventActivities _activities; + readonly EventActivities _thenActivities; + readonly EventActivities _elseActivities; readonly StateMachineAsyncCondition _condition; readonly Event _event; - public ConditionalActivityBinder(Event @event, StateMachineCondition condition, EventActivities activities) - : this(@event, context => Task.FromResult(condition(context)), activities) + + + public ConditionalActivityBinder(Event @event, StateMachineCondition condition, + EventActivities thenActivities, EventActivities elseActivities) + : this(@event, context => Task.FromResult(condition(context)), thenActivities, elseActivities) { } - public ConditionalActivityBinder(Event @event, StateMachineAsyncCondition condition, EventActivities activities) + public ConditionalActivityBinder(Event @event, StateMachineAsyncCondition condition, + EventActivities thenActivities, EventActivities elseActivities) { - _activities = activities; + _thenActivities = thenActivities; + _elseActivities = elseActivities; _condition = condition; _event = @event; } @@ -45,30 +51,34 @@ public bool IsStateTransitionEvent(State state) public void Bind(State state) { - var builder = new ActivityBehaviorBuilder(); - - foreach (var activity in _activities.GetStateActivityBinders()) - { - activity.Bind(builder); - } + var thenBehavior = GetBehavior(_thenActivities); + var elseBehavior = GetBehavior(_elseActivities); - var conditionActivity = new ConditionActivity(_condition, builder.Behavior); + var conditionActivity = new ConditionActivity(_condition, thenBehavior, elseBehavior); state.Bind(_event, conditionActivity); } public void Bind(BehaviorBuilder builder) { - var stateBuilder = new ActivityBehaviorBuilder(); + var thenBehavior = GetBehavior(_thenActivities); + var elseBehavior = GetBehavior(_elseActivities); + + var conditionActivity = new ConditionActivity(_condition, thenBehavior, elseBehavior); + + builder.Add(conditionActivity); + } + + private static Behavior GetBehavior(EventActivities activities) + { + var builder = new ActivityBehaviorBuilder(); - foreach (var activity in _activities.GetStateActivityBinders()) + foreach (var activity in activities.GetStateActivityBinders()) { - activity.Bind(stateBuilder); + activity.Bind(builder); } - var conditionActivity = new ConditionActivity(_condition, stateBuilder.Behavior); - - builder.Add(conditionActivity); + return builder.Behavior; } } @@ -77,20 +87,22 @@ public class ConditionalActivityBinder : ActivityBinder where TInstance : class { - readonly EventActivities _activities; + readonly EventActivities _thenActivities; + readonly EventActivities _elseActivities; readonly StateMachineAsyncCondition _condition; readonly Event _event; public ConditionalActivityBinder(Event @event, StateMachineCondition condition, - EventActivities activities) - : this(@event, context => Task.FromResult(condition(context)), activities) + EventActivities thenActivities, EventActivities elseActivities) + : this(@event, context => Task.FromResult(condition(context)), thenActivities, elseActivities) { } public ConditionalActivityBinder(Event @event, StateMachineAsyncCondition condition, - EventActivities activities) + EventActivities thenActivities, EventActivities elseActivities) { - _activities = activities; + _thenActivities = thenActivities; + _elseActivities = elseActivities; _condition = condition; _event = @event; } @@ -103,30 +115,34 @@ public bool IsStateTransitionEvent(State state) public void Bind(State state) { - var builder = new ActivityBehaviorBuilder(); - - foreach (var activity in _activities.GetStateActivityBinders()) - { - activity.Bind(builder); - } + var thenBehavior = GetBehavior(_thenActivities); + var elseBehavior = GetBehavior(_elseActivities); - var conditionActivity = new ConditionActivity(_condition, builder.Behavior); + var conditionActivity = new ConditionActivity(_condition, thenBehavior, elseBehavior); state.Bind(_event, conditionActivity); } public void Bind(BehaviorBuilder builder) { - var stateBuilder = new ActivityBehaviorBuilder(); + var thenBehavior = GetBehavior(_thenActivities); + var elseBehavior = GetBehavior(_elseActivities); + + var conditionActivity = new ConditionActivity(_condition, thenBehavior, elseBehavior); + + builder.Add(conditionActivity); + } + + private static Behavior GetBehavior(EventActivities activities) + { + var builder = new ActivityBehaviorBuilder(); - foreach (var activity in _activities.GetStateActivityBinders()) + foreach (var activity in activities.GetStateActivityBinders()) { - activity.Bind(stateBuilder); + activity.Bind(builder); } - var conditionActivity = new ConditionActivity(_condition, stateBuilder.Behavior); - - builder.Add(conditionActivity); + return builder.Behavior; } } } \ No newline at end of file diff --git a/src/Automatonymous/Binders/ConditionalExceptionActivityBinder.cs b/src/Automatonymous/Binders/ConditionalExceptionActivityBinder.cs index 9a82b35..fe329f6 100644 --- a/src/Automatonymous/Binders/ConditionalExceptionActivityBinder.cs +++ b/src/Automatonymous/Binders/ConditionalExceptionActivityBinder.cs @@ -23,18 +23,22 @@ public class ConditionalExceptionActivityBinder : where TInstance : class where TException : Exception { - readonly EventActivities _activities; + readonly EventActivities _thenActivities; + readonly EventActivities _elseActivities; readonly StateMachineAsyncExceptionCondition _condition; readonly Event _event; - public ConditionalExceptionActivityBinder(Event @event, StateMachineExceptionCondition condition, EventActivities activities) - :this(@event, context => Task.FromResult(condition(context)), activities) + public ConditionalExceptionActivityBinder(Event @event, StateMachineExceptionCondition condition, + EventActivities thenActivities, EventActivities elseActivities) + :this(@event, context => Task.FromResult(condition(context)), thenActivities, elseActivities) { } - public ConditionalExceptionActivityBinder(Event @event, StateMachineAsyncExceptionCondition condition, EventActivities activities) + public ConditionalExceptionActivityBinder(Event @event, StateMachineAsyncExceptionCondition condition, + EventActivities thenActivities, EventActivities elseActivities) { - _activities = activities; + _thenActivities = thenActivities; + _elseActivities = elseActivities; _condition = condition; _event = @event; } @@ -47,30 +51,33 @@ public bool IsStateTransitionEvent(State state) public void Bind(State state) { - var catchBuilder = new CatchBehaviorBuilder(); + var thenBehavior = GetBehavior(_thenActivities); + var elseBehavior = GetBehavior(_elseActivities); - foreach (var activity in _activities.GetStateActivityBinders()) - { - activity.Bind(catchBuilder); - } - - var conditionActivity = new ConditionExceptionActivity(_condition, catchBuilder.Behavior); + var conditionActivity = new ConditionExceptionActivity(_condition, thenBehavior, elseBehavior); state.Bind(_event, conditionActivity); } public void Bind(BehaviorBuilder builder) + { + var thenBehavior = GetBehavior(_thenActivities); + var elseBehavior = GetBehavior(_elseActivities); + + var conditionActivity = new ConditionExceptionActivity(_condition, thenBehavior, elseBehavior); + + builder.Add(conditionActivity); + } + + private Behavior GetBehavior(EventActivities activities) { var catchBuilder = new CatchBehaviorBuilder(); - foreach (var activity in _activities.GetStateActivityBinders()) + foreach (var activity in activities.GetStateActivityBinders()) { activity.Bind(catchBuilder); } - - var conditionActivity = new ConditionExceptionActivity(_condition, catchBuilder.Behavior); - - builder.Add(conditionActivity); + return catchBuilder.Behavior; } } @@ -80,19 +87,22 @@ public class ConditionalExceptionActivityBinder : where TInstance : class where TException : Exception { - readonly EventActivities _activities; + readonly EventActivities _thenActivities; + readonly EventActivities _elseActivities; readonly StateMachineAsyncExceptionCondition _condition; readonly Event _event; - public ConditionalExceptionActivityBinder(Event @event, StateMachineExceptionCondition condition, EventActivities activities) - : this(@event, context => Task.FromResult(condition(context)), activities) + public ConditionalExceptionActivityBinder(Event @event, StateMachineExceptionCondition condition, + EventActivities thenActivities, EventActivities elseActivities) + : this(@event, context => Task.FromResult(condition(context)), thenActivities, elseActivities) { } public ConditionalExceptionActivityBinder(Event @event, StateMachineAsyncExceptionCondition condition, - EventActivities activities) + EventActivities thenActivities, EventActivities elseActivities) { - _activities = activities; + _thenActivities = thenActivities; + _elseActivities = elseActivities; _condition = condition; _event = @event; } @@ -105,30 +115,34 @@ public bool IsStateTransitionEvent(State state) public void Bind(State state) { - var catchBuilder = new CatchBehaviorBuilder(); + var thenBehavior = GetBehavior(_thenActivities); + var elseBehavior = GetBehavior(_elseActivities); - foreach (var activity in _activities.GetStateActivityBinders()) - { - activity.Bind(catchBuilder); - } - - var conditionActivity = new ConditionExceptionActivity(_condition, catchBuilder.Behavior); + var conditionActivity = new ConditionExceptionActivity(_condition, thenBehavior, elseBehavior); state.Bind(_event, conditionActivity); } public void Bind(BehaviorBuilder builder) + { + var thenBehavior = GetBehavior(_thenActivities); + var elseBehavior = GetBehavior(_elseActivities); + + var conditionActivity = new ConditionExceptionActivity(_condition, thenBehavior, elseBehavior); + + builder.Add(conditionActivity); + } + + private Behavior GetBehavior(EventActivities activities) { var catchBuilder = new CatchBehaviorBuilder(); - foreach (var activity in _activities.GetStateActivityBinders()) + foreach (var activity in activities.GetStateActivityBinders()) { activity.Bind(catchBuilder); } - var conditionActivity = new ConditionExceptionActivity(_condition, catchBuilder.Behavior); - - builder.Add(conditionActivity); + return catchBuilder.Behavior; } } } \ No newline at end of file diff --git a/src/Automatonymous/Binders/DataEventActivityBinder.cs b/src/Automatonymous/Binders/DataEventActivityBinder.cs index fa299b9..e947f5e 100644 --- a/src/Automatonymous/Binders/DataEventActivityBinder.cs +++ b/src/Automatonymous/Binders/DataEventActivityBinder.cs @@ -85,27 +85,46 @@ EventActivityBinder EventActivityBinder.Catc EventActivityBinder EventActivityBinder.If(StateMachineCondition condition, Func, EventActivityBinder> activityCallback) { - EventActivityBinder binder = new DataEventActivityBinder(_machine, _event); + return IfElse(condition, activityCallback, _ => _); + } - binder = activityCallback(binder); + EventActivityBinder EventActivityBinder.IfAsync(StateMachineAsyncCondition condition, + Func, EventActivityBinder> activityCallback) + { + return IfElseAsync(condition, activityCallback, _ => _); + } - var conditionBinder = new ConditionalActivityBinder(_event, condition, binder); + public EventActivityBinder IfElse(StateMachineCondition condition, + Func, EventActivityBinder> thenActivityCallback, + Func, EventActivityBinder> elseActivityCallback) + { + var thenBinder = GetBinder(thenActivityCallback); + var elseBinder = GetBinder(elseActivityCallback); + + var conditionBinder = new ConditionalActivityBinder(_event, condition, thenBinder, elseBinder); return new DataEventActivityBinder(_machine, _event, _filter, _activities, conditionBinder); } - EventActivityBinder EventActivityBinder.IfAsync(StateMachineAsyncCondition condition, - Func, EventActivityBinder> activityCallback) + public EventActivityBinder IfElseAsync(StateMachineAsyncCondition condition, + Func, EventActivityBinder> thenActivityCallback, + Func, EventActivityBinder> elseActivityCallback) { - EventActivityBinder binder = new DataEventActivityBinder(_machine, _event); + var thenBinder = GetBinder(thenActivityCallback); + var elseBinder = GetBinder(elseActivityCallback); - binder = activityCallback(binder); - - var conditionBinder = new ConditionalActivityBinder(_event, condition, binder); + var conditionBinder = new ConditionalActivityBinder(_event, condition, thenBinder, elseBinder); return new DataEventActivityBinder(_machine, _event, _filter, _activities, conditionBinder); } + private EventActivityBinder GetBinder(Func, EventActivityBinder> activityCallback) + { + EventActivityBinder binder = new DataEventActivityBinder(_machine, _event); + + return activityCallback(binder); + } + StateMachine EventActivityBinder.StateMachine => _machine; public IEnumerable> GetStateActivityBinders() @@ -125,9 +144,10 @@ ActivityBinder CreateStateActivityBinder(Activity a ActivityBinder CreateConditionalActivityBinder() { - EventActivityBinder binder = new DataEventActivityBinder(_machine, _event, _activities); + EventActivityBinder thenBinder = new DataEventActivityBinder(_machine, _event, _activities); + EventActivityBinder elseBinder = new DataEventActivityBinder(_machine, _event); - var conditionBinder = new ConditionalActivityBinder(_event, context => _filter(context), binder); + var conditionBinder = new ConditionalActivityBinder(_event, context => _filter(context), thenBinder, elseBinder); return conditionBinder; } diff --git a/src/Automatonymous/Binders/EventActivityBinder.cs b/src/Automatonymous/Binders/EventActivityBinder.cs index 56c3f90..74928ac 100644 --- a/src/Automatonymous/Binders/EventActivityBinder.cs +++ b/src/Automatonymous/Binders/EventActivityBinder.cs @@ -52,6 +52,28 @@ EventActivityBinder If(StateMachineCondition condition, /// EventActivityBinder IfAsync(StateMachineAsyncCondition condition, Func, EventActivityBinder> activityCallback); + + /// + /// Create a conditional branch of activities for processing + /// + /// + /// + /// + /// + EventActivityBinder IfElse(StateMachineCondition condition, + Func, EventActivityBinder> thenActivityCallback, + Func, EventActivityBinder> elseActivityCallback); + + /// + /// Create a conditional branch of activities for processing + /// + /// + /// + /// + /// + EventActivityBinder IfElseAsync(StateMachineAsyncCondition condition, + Func, EventActivityBinder> thenActivityCallback, + Func, EventActivityBinder> elseActivityCallback); } @@ -94,5 +116,27 @@ EventActivityBinder If(StateMachineCondition /// EventActivityBinder IfAsync(StateMachineAsyncCondition condition, Func, EventActivityBinder> activityCallback); + + /// + /// Create a conditional branch of activities for processing + /// + /// + /// + /// + /// + EventActivityBinder IfElse(StateMachineCondition condition, + Func, EventActivityBinder> thenActivityCallback, + Func, EventActivityBinder> elseActivityCallback); + + /// + /// Create a conditional branch of activities for processing + /// + /// + /// + /// + /// + EventActivityBinder IfElseAsync(StateMachineAsyncCondition condition, + Func, EventActivityBinder> thenActivityCallback, + Func, EventActivityBinder> elseActivityCallback); } } \ No newline at end of file diff --git a/src/Automatonymous/Binders/ExceptionActivityBinder.cs b/src/Automatonymous/Binders/ExceptionActivityBinder.cs index aaafe35..7178ac0 100644 --- a/src/Automatonymous/Binders/ExceptionActivityBinder.cs +++ b/src/Automatonymous/Binders/ExceptionActivityBinder.cs @@ -53,6 +53,28 @@ ExceptionActivityBinder If(StateMachineExceptionCondition /// ExceptionActivityBinder IfAsync(StateMachineAsyncExceptionCondition condition, Func, ExceptionActivityBinder> activityCallback); + + /// + /// Create a conditional branch of activities for processing + /// + /// + /// + /// + /// + ExceptionActivityBinder IfElse(StateMachineExceptionCondition condition, + Func, ExceptionActivityBinder> thenActivityCallback, + Func, ExceptionActivityBinder> elseActivityCallback); + + /// + /// Create a conditional branch of activities for processing + /// + /// + /// + /// + /// + ExceptionActivityBinder IfElseAsync(StateMachineAsyncExceptionCondition condition, + Func, ExceptionActivityBinder> thenActivityCallback, + Func, ExceptionActivityBinder> elseActivityCallback); } @@ -96,5 +118,27 @@ ExceptionActivityBinder If(StateMachineExceptionCo /// ExceptionActivityBinder IfAsync(StateMachineAsyncExceptionCondition condition, Func, ExceptionActivityBinder> activityCallback); + + /// + /// Create a conditional branch of activities for processing + /// + /// + /// + /// + /// + ExceptionActivityBinder IfElse(StateMachineExceptionCondition condition, + Func, ExceptionActivityBinder> thenActivityCallback, + Func, ExceptionActivityBinder> elseActivityCallback); + + /// + /// Create a conditional branch of activities for processing + /// + /// + /// + /// + /// + ExceptionActivityBinder IfElseAsync(StateMachineAsyncExceptionCondition condition, + Func, ExceptionActivityBinder> thenActivityCallback, + Func, ExceptionActivityBinder> elseActivityCallback); } } \ No newline at end of file diff --git a/src/Automatonymous/Binders/TriggerEventActivityBinder.cs b/src/Automatonymous/Binders/TriggerEventActivityBinder.cs index 946f984..2b36e9a 100644 --- a/src/Automatonymous/Binders/TriggerEventActivityBinder.cs +++ b/src/Automatonymous/Binders/TriggerEventActivityBinder.cs @@ -79,27 +79,45 @@ EventActivityBinder EventActivityBinder.Catch( EventActivityBinder EventActivityBinder.If(StateMachineCondition condition, Func, EventActivityBinder> activityCallback) { - EventActivityBinder binder = new TriggerEventActivityBinder(_machine, _event); + return IfElse(condition, activityCallback, _ => _); + } - binder = activityCallback(binder); + EventActivityBinder EventActivityBinder.IfAsync(StateMachineAsyncCondition condition, + Func, EventActivityBinder> activityCallback) + { + return IfElseAsync(condition, activityCallback, _ => _); + } + + public EventActivityBinder IfElse(StateMachineCondition condition, + Func, EventActivityBinder> thenActivityCallback, + Func, EventActivityBinder> elseActivityCallback) + { + var thenBinder = GetBinder(thenActivityCallback); + var elseBinder = GetBinder(elseActivityCallback); - var conditionBinder = new ConditionalActivityBinder(_event, condition, binder); + var conditionBinder = new ConditionalActivityBinder(_event, condition, thenBinder, elseBinder); return new TriggerEventActivityBinder(_machine, _event, _filter, _activities, conditionBinder); } - EventActivityBinder EventActivityBinder.IfAsync(StateMachineAsyncCondition condition, - Func, EventActivityBinder> activityCallback) + public EventActivityBinder IfElseAsync(StateMachineAsyncCondition condition, + Func, EventActivityBinder> thenActivityCallback, + Func, EventActivityBinder> elseActivityCallback) { - EventActivityBinder binder = new TriggerEventActivityBinder(_machine, _event); - - binder = activityCallback(binder); + var thenBinder = GetBinder(thenActivityCallback); + var elseBinder = GetBinder(elseActivityCallback); - var conditionBinder = new ConditionalActivityBinder(_event, condition, binder); + var conditionBinder = new ConditionalActivityBinder(_event, condition, thenBinder, elseBinder); return new TriggerEventActivityBinder(_machine, _event, _filter, _activities, conditionBinder); } + private EventActivityBinder GetBinder(Func, EventActivityBinder> activityCallback) + { + EventActivityBinder binder = new TriggerEventActivityBinder(_machine, _event); + return activityCallback(binder); + } + StateMachine EventActivityBinder.StateMachine => _machine; public IEnumerable> GetStateActivityBinders() @@ -112,9 +130,10 @@ public IEnumerable> GetStateActivityBinders() ActivityBinder CreateConditionalActivityBinder() { - EventActivityBinder binder = new TriggerEventActivityBinder(_machine, _event, _activities); + EventActivityBinder thenBinder = new TriggerEventActivityBinder(_machine, _event, _activities); + EventActivityBinder elseBinder = new TriggerEventActivityBinder(_machine, _event); - var conditionBinder = new ConditionalActivityBinder(_event, context => _filter(context), binder); + var conditionBinder = new ConditionalActivityBinder(_event, context => _filter(context), thenBinder, elseBinder); return conditionBinder; }