I've been messing around with the new Reactive Extensions for a couple weeks and wanted to build something that would allow you to match patterns in an Observable stream.
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.
I came up with the following library and put it up on Codeplex as a project called Fluent State Observer in case I ever need to get to it again. I'm going to paste the project home page content here strictly for SEO purposes.
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
See the Observable Series these tests use
Match Complex Patterns
[TestMethod()]
{
// 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);
}</testelement>
Non-Greedy Matching
Matches only when immediately followed by something.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);
}</testelement>
Specify Reset / Disqualifying Conditions At Each Transition
Match 1, 5, 4, 3, 4, but not 1, 2, 4, 3, 4public 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);
}</testelement>
The Mock Observable in these tests publishes the following series
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
});
That's it. Hope someone finds it useful.
Now Playing: Drake - I'm Going In (Explicit)