refactoring #6 (#7)

refactoring #6

Co-authored-by: Alexander Kozachenko <119358312+Alex-Kozachenko@users.noreply.github.com>
Reviewed-on: #7
This commit is contained in:
Alexander Kozachenko 2023-12-08 01:46:37 +00:00
parent 2314cf58ab
commit 5598d0f898
10 changed files with 113 additions and 111 deletions

View file

@ -3,7 +3,7 @@
<metadata> <metadata>
<id>ProSol.Html.TagsProvider</id> <id>ProSol.Html.TagsProvider</id>
<title>ProSol.Html.TagsProvider</title> <title>ProSol.Html.TagsProvider</title>
<version>2.0.0-rc1.4</version> <version>2.0.0-rc2.0</version>
<authors>Alex Kozachenko</authors> <authors>Alex Kozachenko</authors>
<owners>Alex Kozachenko</owners> <owners>Alex Kozachenko</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>false</requireLicenseAcceptance>
@ -15,7 +15,7 @@
</description> </description>
<dependencies> <dependencies>
<group targetFramework="net8.0" > <group targetFramework="net8.0" >
<dependency id="ProSol.Messaging" version="4.0.0-rc.6.*" /> <dependency id="ProSol.Messaging" version="4.0.0-rc.9.0" />
</group> </group>
</dependencies> </dependencies>
<tags> tool extraction web html observer observer-pattern design-patterns </tags> <tags> tool extraction web html observer observer-pattern design-patterns </tags>

View file

@ -1,20 +1,18 @@
using ProSol.Html.Contracts.Data; using ProSol.Html.Contracts.Data;
using ProSol.Messaging; using ProSol.Messaging;
using ProSol.Messaging.Subscriptions; using ProSol.Messaging.Filtering;
namespace ProSol.Html.Messaging; namespace ProSol.Html.Messaging;
public static class IPublisherExtensions public static class IPublisherExtensions
{ {
public static IPublisher Subscribe( public static IPublisher<TagsProviderMessage> Filter(
this IPublisher publisher, this IPublisher<TagsProviderMessage> publisher,
IPipelineSubscriber<TagsProviderMessage> subscriber, string tagName)
params string[] tagNames) => publisher.Filter([tagName]);
=> publisher.Subscribe(subscriber, x => tagNames.Contains(x.CurrentTag.TagInfo.Name));
public static IPublisher Subscribe( public static IPublisher<TagsProviderMessage> Filter(
this IPublisher publisher, this IPublisher<TagsProviderMessage> publisher,
ISubscriber<TagsProviderMessage> subscriber,
params string[] tagNames) params string[] tagNames)
=> publisher.Subscribe(subscriber, x => tagNames.Contains(x.CurrentTag.TagInfo.Name)); => publisher.Filter(x => tagNames.Contains(x.CurrentTag.TagInfo.Name));
} }

View file

@ -7,7 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ProSol.Messaging" Version="4.0.0-rc.7.4" /> <PackageReference Include="ProSol.Messaging" Version="4.0.0-rc.9.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -10,10 +10,9 @@ namespace ProSol.Html;
/// <remarks> /// <remarks>
/// Push-notification happens only when the closing tag met, so it contains the full data on tag. /// Push-notification happens only when the closing tag met, so it contains the full data on tag.
/// </remarks> /// </remarks>
public class TagsProvider : IPublisher public class TagsProvider : PipelineMessagePublisher<TagsProviderMessage>
{ {
readonly HistoryTracker historyTracker = new(); readonly HistoryTracker historyTracker = new();
readonly PipelineMessagePublisher<TagsProviderMessage> publisher = new();
public void Process(ReadOnlySpan<char> html) public void Process(ReadOnlySpan<char> html)
{ {
@ -26,12 +25,9 @@ public class TagsProvider : IPublisher
charsProcessed += Proceed(currentHtml); charsProcessed += Proceed(currentHtml);
} while (charsProcessed < html.Length); } while (charsProcessed < html.Length);
publisher.Complete(); base.Complete();
} }
public IDisposable Subscribe(ISubscriber observer)
=> publisher.Subscribe(observer);
void Process(ReadOnlySpan<char> currentHtml, int charsProcessed) void Process(ReadOnlySpan<char> currentHtml, int charsProcessed)
{ {
if (TagDetector.Detect(currentHtml) != TagKind.Closing) if (TagDetector.Detect(currentHtml) != TagKind.Closing)
@ -69,7 +65,7 @@ public class TagsProvider : IPublisher
[..history], [..history],
value); value);
publisher.Publish(message); base.Publish(message);
} }
static int Proceed(ReadOnlySpan<char> currentHtml) static int Proceed(ReadOnlySpan<char> currentHtml)

View file

@ -1,18 +1,23 @@
using ProSol.Html.Tests.TestHelpers; using ProSol.Html.Contracts.Data;
using ProSol.Messaging;
using ProSol.Messaging.Translating;
namespace ProSol.Html.Tests.KnownIssues; namespace ProSol.Html.Tests.KnownIssues;
public class TagsProvider_KnownIssues public class TagsProvider_KnownIssues
{ {
private TagsProvider tagsProvider; private TagsProvider tagsProvider;
private TagsProviderListener listener; private DataSubscriber<ProcessedTag> processedTagsListener;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
tagsProvider = new(); tagsProvider = new();
listener = new(); processedTagsListener = new();
listener.Subscribe(tagsProvider);
tagsProvider
.Translate<TagsProviderMessage, ProcessedTag>(x => x.CurrentTag)
.Subscribe(processedTagsListener);
} }
[Test] [Test]
@ -24,6 +29,6 @@ public class TagsProvider_KnownIssues
{ {
var html = "<br />"; var html = "<br />";
tagsProvider.Process(html); tagsProvider.Process(html);
Assert.That(listener.ProcessedTags, Has.Length.EqualTo(0)); Assert.That(processedTagsListener.Messages, Has.Length.EqualTo(0));
} }
} }

View file

@ -1,5 +1,8 @@
using ProSol.Html.Tests.TestHelpers;
using ProSol.Html.Messaging; using ProSol.Html.Messaging;
using ProSol.Messaging.Filtering;
using ProSol.Messaging.Translating;
using ProSol.Html.Contracts.Data;
using ProSol.Messaging;
namespace ProSol.Html.Tests; namespace ProSol.Html.Tests;
@ -9,12 +12,6 @@ public class TagsProvider_FiltersSubscribers_Tests
[Test] [Test]
public void Process_Single_Named_Tag() public void Process_Single_Named_Tag()
{ {
var expected = new string[] { "Rock", "Paper", "Scissors" };
var tagsProvider = new TagsProvider();
var listener = new TagsProviderListener();
tagsProvider.Subscribe(listener, "li");
var html = """ var html = """
<ul> <ul>
<li>Rock</li> <li>Rock</li>
@ -22,38 +19,42 @@ public class TagsProvider_FiltersSubscribers_Tests
<li>Scissors</li> <li>Scissors</li>
</ul> </ul>
"""; """;
var expected = new string[] { "Rock", "Paper", "Scissors" };
var tagsProvider = new TagsProvider();
var data = new DataSubscriber<string>();
tagsProvider
.Filter("li")
.Translate<TagsProviderMessage, ProcessedTag>(x => x.CurrentTag)
.Translate<ProcessedTag, string>(x => html[x.InnerTextRange])
.Subscribe(data);
tagsProvider.Process(html); tagsProvider.Process(html);
var result = GetText(listener, html); Assert.That(data.Messages, Is.EquivalentTo(expected));
Assert.That(result, Is.EquivalentTo(expected));
} }
[Test] [Test]
public void Process_Multiple_Named_Tag() public void Process_Multiple_Named_Tag()
{ {
var expected = new string[] { "Terminal", "tasks", "any", "close" };
var tagsProvider = new TagsProvider();
var listener = new TagsProviderListener();
tagsProvider.Subscribe(listener, "i", "b");
var html = """ var html = """
<b>Terminal</b> will be reused by <b>tasks</b>, press <i>any</i> key to <i>close</i> it. <b>Terminal</b> will be reused by <b>tasks</b>, press <i>any</i> key to <i>close</i> it.
"""; """;
var expected = new string[] { "Terminal", "tasks", "any", "close" };
var tagsProvider = new TagsProvider();
var data = new DataSubscriber<string>();
tagsProvider
.Filter("i", "b")
.Translate<TagsProviderMessage, ProcessedTag>(x => x.CurrentTag)
.Translate<ProcessedTag, string>(x => html[x.InnerTextRange])
.Subscribe(data);
tagsProvider.Process(html); tagsProvider.Process(html);
var result = GetText(listener, html); Assert.That(data.Messages, Is.EquivalentTo(expected));
Assert.That(result, Is.EquivalentTo(expected));
}
static string[] GetText(TagsProviderListener listener, string html)
{
return listener.ProcessedTags
.Select(x => html[x.InnerTextRange]
.ToString())
.ToArray();
} }
} }

View file

@ -1,19 +1,24 @@
using System.Collections.Immutable;
using ProSol.Html; using ProSol.Html;
using ProSol.Html.Tests.TestHelpers; using ProSol.Html.Contracts.Data;
using ProSol.Messaging;
using ProSol.Messaging.Translating;
namespace ProSol.Html.Tests; namespace ProSol.Html.Tests;
public class TagsProvider_MessageHistory_Tests public class TagsProvider_MessageHistory_Tests
{ {
private TagsProvider tagsProvider; private TagsProvider tagsProvider;
private TagsProviderListener listener; private DataSubscriber<string> tagNamesListener;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
tagsProvider = new(); tagsProvider = new();
listener = new(); tagNamesListener = new();
listener.Subscribe(tagsProvider); tagsProvider
.Translate<TagsProviderMessage, string>(x => x.CurrentTag.TagInfo.Name)
.Subscribe(tagNamesListener);
} }
[Test] [Test]
@ -23,10 +28,9 @@ public class TagsProvider_MessageHistory_Tests
var html = $"<main> <div> <p>{text}</p> </div> </main>"; var html = $"<main> <div> <p>{text}</p> </div> </main>";
tagsProvider.Process(html); tagsProvider.Process(html);
var names = tagNamesListener.Messages;
Assert.Multiple( () => { Assert.Multiple( () => {
var names = listener.Messages
.Select(x => x.CurrentTag.TagInfo.Name)
.ToArray();
Assert.That(names[0], Is.EqualTo("p")); Assert.That(names[0], Is.EqualTo("p"));
Assert.That(names[1], Is.EqualTo("div")); Assert.That(names[1], Is.EqualTo("div"));
Assert.That(names[2], Is.EqualTo("main")); Assert.That(names[2], Is.EqualTo("main"));
@ -38,14 +42,20 @@ public class TagsProvider_MessageHistory_Tests
{ {
var text = "LoremIpsum"; var text = "LoremIpsum";
var html = $"<main> <div> <p>{text}</p> </div> </main>"; var html = $"<main> <div> <p>{text}</p> </div> </main>";
var tagsHistoryListener = new DataSubscriber<ImmutableArray<TagInfo>>();
tagsProvider
.Translate<TagsProviderMessage, ImmutableArray<TagInfo>>(x => x.TagsHistory)
.Subscribe(tagsHistoryListener);
tagsProvider.Process(html); tagsProvider.Process(html);
Assert.That(listener.Messages[0].CurrentTag.TagInfo.Name, var names = tagNamesListener.Messages;
Is.EqualTo("p"));
Assert.That(names[0], Is.EqualTo("p"));
Assert.Multiple( () => { Assert.Multiple( () => {
var deepestHistory = listener.Messages[0] var deepestHistory = tagsHistoryListener.Messages[0]
.TagsHistory
.Select(x => x.Name) .Select(x => x.Name)
.ToArray(); .ToArray();
Assert.That(deepestHistory[0], Is.EqualTo("main")); Assert.That(deepestHistory[0], Is.EqualTo("main"));

View file

@ -1,5 +1,7 @@
using ProSol.Html.Tests.TestHelpers;
using ProSol.Html.Messaging; using ProSol.Html.Messaging;
using ProSol.Messaging;
using ProSol.Html.Contracts.Data;
using ProSol.Messaging.Translating;
namespace ProSol.Html.Tests; namespace ProSol.Html.Tests;
@ -11,10 +13,14 @@ public class TagsProvider_MultipleTags_Tests
var html = $"<main> <div> <p>LoremIpsum</p> </div> </main>"; var html = $"<main> <div> <p>LoremIpsum</p> </div> </main>";
var tagsProvider = new TagsProvider(); var tagsProvider = new TagsProvider();
var listener = new TagsProviderListener(); var data = new DataSubscriber<ProcessedTag>();
tagsProvider.Subscribe(listener); tagsProvider
.Translate<TagsProviderMessage, ProcessedTag>(x => x.CurrentTag)
.Subscribe(data);
tagsProvider.Process(html); tagsProvider.Process(html);
var result = listener.ProcessedTags;
var result = data.Messages;
Assert.Multiple(() => Assert.Multiple(() =>
{ {
@ -32,10 +38,14 @@ public class TagsProvider_MultipleTags_Tests
var html = $"<main> <div> <p>LoremIpsum</p> </div> </main>"; var html = $"<main> <div> <p>LoremIpsum</p> </div> </main>";
var tagsProvider = new TagsProvider(); var tagsProvider = new TagsProvider();
var listener = new TagsProviderListener(); var data = new DataSubscriber<ProcessedTag>();
tagsProvider.Subscribe(listener); tagsProvider
.Translate<TagsProviderMessage, ProcessedTag>(x => x.CurrentTag)
.Subscribe(data);
tagsProvider.Process(html); tagsProvider.Process(html);
var result = listener.ProcessedTags;
var result = data.Messages;
Assert.Multiple(() => Assert.Multiple(() =>
{ {
@ -59,10 +69,15 @@ public class TagsProvider_MultipleTags_Tests
"""; """;
var tagsProvider = new TagsProvider(); var tagsProvider = new TagsProvider();
var listener = new TagsProviderListener(); var data = new DataSubscriber<ProcessedTag>();
tagsProvider.Subscribe(listener, "b"); tagsProvider
.Filter("b")
.Translate<TagsProviderMessage, ProcessedTag>(x => x.CurrentTag)
.Subscribe(data);
tagsProvider.Process(html); tagsProvider.Process(html);
var result = listener.ProcessedTags;
var result = data.Messages;
Assert.Multiple(() => Assert.Multiple(() =>
{ {

View file

@ -1,20 +1,24 @@
using ProSol.Html; using ProSol.Html;
using ProSol.Html.Tests.TestHelpers; using ProSol.Html.Contracts.Data;
using ProSol.Messaging;
using ProSol.Messaging.Translating;
namespace ProSol.Html.Tests; namespace ProSol.Html.Tests;
public class TagsProvider_SingleTag_Tests public class TagsProvider_SingleTag_Tests
{ {
private TagsProvider tagsProvider; private TagsProvider tagsProvider;
private TagsProviderListener listener; private DataSubscriber<ProcessedTag> processedTagsListener;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
tagsProvider = new(); tagsProvider = new();
listener = new(); processedTagsListener = new();
listener.Subscribe(tagsProvider); tagsProvider
.Translate<TagsProviderMessage, ProcessedTag>(x => x.CurrentTag)
.Subscribe(processedTagsListener);
} }
[Test] [Test]
@ -23,7 +27,8 @@ public class TagsProvider_SingleTag_Tests
var html = "<main></main>"; var html = "<main></main>";
tagsProvider.Process(html); tagsProvider.Process(html);
var result = listener.ProcessedTags;
var result = processedTagsListener.Messages;
Assert.Multiple(() => Assert.Multiple(() =>
{ {
@ -45,7 +50,8 @@ public class TagsProvider_SingleTag_Tests
var html = "<main>Lorem</main>"; var html = "<main>Lorem</main>";
tagsProvider.Process(html); tagsProvider.Process(html);
var result = listener.ProcessedTags;
var result = processedTagsListener.Messages;
Assert.Multiple(() => Assert.Multiple(() =>
{ {
@ -69,7 +75,8 @@ public class TagsProvider_SingleTag_Tests
var html = "<main id='idmain' class='bar buzz' data-id=id data-value=\"value\">Lorem</main>"; var html = "<main id='idmain' class='bar buzz' data-id=id data-value=\"value\">Lorem</main>";
tagsProvider.Process(html); tagsProvider.Process(html);
var result = listener.ProcessedTags;
var result = processedTagsListener.Messages;
Assert.Multiple(() => Assert.Multiple(() =>
{ {
@ -101,7 +108,8 @@ public class TagsProvider_SingleTag_Tests
var html = "<div>\r\n<!-- <div> Ignored </div> -->\r\n</div>"; var html = "<div>\r\n<!-- <div> Ignored </div> -->\r\n</div>";
tagsProvider.Process(html); tagsProvider.Process(html);
var result = listener.ProcessedTags;
var result = processedTagsListener.Messages;
Assert.Multiple(() => Assert.Multiple(() =>
{ {

View file

@ -1,31 +0,0 @@
using ProSol.Html.Contracts.Data;
using ProSol.Messaging;
namespace ProSol.Html.Tests.TestHelpers;
internal class TagsProviderListener : ISubscriber<TagsProviderMessage>
{
IDisposable? unsubscriber;
HashSet<TagsProviderMessage> messages = new();
public ProcessedTag[] ProcessedTags =>
[.. messages
.Select(x => x.CurrentTag)];
public TagsProviderMessage[] Messages => [.. messages];
public void Subscribe(TagsProvider source)
{
source.Subscribe(this);
}
public void OnCompleted()
{
unsubscriber?.Dispose();
}
public void OnNext(TagsProviderMessage value)
{
messages.Add(value);
}
}