Description

The Fluent State Observer helps perform actions based on a pattern in an IObservable "stream".

This library is developed in C# and uses the Reactive (Rx) Extensions library for it's implementation of the IObservable pattern and helper extensions for creating anonymous observers.

For more detailed information about the Reactive Extensions, check out the Reactive Extensions API In-Depth Intro Video and other In-Depth Reactive Extension videos

This project is developed by Jacob Gable.

Example Uses

The following examples are from the test project. The test project includes a mocked IObservable that pumps out TestElements in succession. The call to obs.ProcessBlocks() begins the stream of Observable items.

See the Observable Series these tests use

Match Complex Patterns
[TestMethod()]
public void Should_Match_FollowedBy_Patterns()
{
    // New up with a Mock IObservable that just pumps out items in this pattern ( 1, 2, 2, 3, 1, 2, 3, 4 )
    var obs = TestObservables.BasicObservable();
    var target = new FluentStateObserver<TestElement>(obs);

    bool didMatch = false;
    target
        .StartsWith(x => x.TypeOfElement == ElementType.TestType1)
        .FollowedBy(x => x.TypeOfElement == ElementType.TestType3)
        .EndsWith(x => x.TypeOfElement == ElementType.TestType4)
        .OnMatch(x => didMatch = true);

    obs.ProcessBlocks();

    Assert.IsTrue(didMatch);
} 


Non-Greedy Matching
Matches only when immediately followed by something.
[TestMethod()]
public void Should_Match_FollowedImmediately_Patterns()
{
    var obs = TestObservables.BasicObservable();
    var target = new FluentStateObserver<TestElement>(obs);

    bool didMatch = false;
    target
        .StartsWith(x => x.TypeOfElement == ElementType.TestType1)
        .FollowedImmediatelyBy(x => x.TypeOfElement == ElementType.TestType2)
        .EndsWith(x => x.TypeOfElement == ElementType.TestType4)
        .OnMatch(x => didMatch = true);

    obs.ProcessBlocks();

    Assert.IsTrue(didMatch);
}


Specify Reset / Disqualifying Conditions At Each Transition
Match 1, 5, 4, 3, 4, but not 1, 2, 4, 3, 4
[TestMethod()]
public void Should_Reset_When_A_Reset_Condition_Is_Satisfied()
{
    var obs = TestObservables.BasicObservable();
    var target = new FluentStateObserver<TestElement>(obs);

    int matches = 0;
    target
        .StartsWith(x => x.TypeOfElement == ElementType.TestType1)                
        .FollowedBy(x => x.TypeOfElement == ElementType.TestType3)
        .ResetOn(x => x.TypeOfElement == ElementType.TestType2)
        .EndsWith(x => x.TypeOfElement == ElementType.TestType4)
        .OnMatch(x => matches++);

    obs.ProcessBlocks();

    Assert.AreEqual(0, matches);
}



The Mock Observable in these tests publishes the following series
// Basically, [ 1, 2, 2, 3, 1, 2, 3, 4 ]
new TestElement() 
{ 
    Message = "Message 1", 
    TypeOfElement = ElementType.TestType1 
});

new TestElement() 
{ 
    Message = "Message 2", 
    TypeOfElement = ElementType.TestType2
});

new TestElement() 
{ 
    Message = "Message 2", 
    TypeOfElement = ElementType.TestType2
});

new TestElement() 
{ 
    Message = "Message 3", 
    TypeOfElement = ElementType.TestType3 
});

new TestElement() 
{ 
    Message = "Message 1", 
    TypeOfElement = ElementType.TestType1
});

new TestElement() 
{ 
    Message = "Message 2", 
    TypeOfElement = ElementType.TestType2
});

new TestElement() 
{ 
    Message = "Message 3", 
    TypeOfElement = ElementType.TestType3
});

new TestElement() 
{ 
    Message = "Message 4", 
    TypeOfElement = ElementType.TestType4
});

Last edited Jan 10, 2010 at 1:21 AM by jgable, version 5