ScopeSelection 1.2.1
dotnet add package ScopeSelection --version 1.2.1
NuGet\Install-Package ScopeSelection -Version 1.2.1
<PackageReference Include="ScopeSelection" Version="1.2.1" />
<PackageVersion Include="ScopeSelection" Version="1.2.1" />
<PackageReference Include="ScopeSelection" />
paket add ScopeSelection --version 1.2.1
#r "nuget: ScopeSelection, 1.2.1"
#:package ScopeSelection@1.2.1
#addin nuget:?package=ScopeSelection&version=1.2.1
#tool nuget:?package=ScopeSelection&version=1.2.1
Scope Selection
A simple, portable library to make selection of subsets easy and abstract.
The Problem
When accessing a semi-hierarchical collection of items, you often want an easy way to tell if an element is in a particular subset.
Consider the following data class to support execution of Cucumber style clauses:
public class Clause
{
public string Feature { get; init; } = "";
public string Scenario { get; init; } = "";
public string Keyword { get; init; } = "";
public IReadOnlyList<string> Tags { get; init; } = [];
public string Payload { get; set; } = "";
}
Compare that with different ways it may be bound:
public class StepBinding
{
public string Feature { get; init; } = "";
public string Scenario { get; init; } = "";
public string Keyword { get; init; } = "";
public IReadOnlyList<string> Tags { get; init; } = [];
public required IBinding { get; set; }
}
public class StepArgumentTransformationBinding
{
public string Feature { get; init; } = "";
public string Scenario { get; init; } = "";
public string Keyword { get; init; } = "";
public IReadOnlyList<string> Tags { get; init; } = [];
public required ITransformation { get; set; }
}
Such structuring proliferates and promotes redundant query logic.
The Solution
This can be solved by introducing an abstraction that encapsulates redundant structure.
public class Clause
{
public required Scope { get; init }
public string Payload { get; set; } = "";
}
public class StepBinding
{
public required Scope { get; init }
public required IBinding { get; set; }
}
public class StepArgumentTransformationBinding
{
public required Scope { get; init }
public required ITransformation { get; set; }
}
Encapsulating redundant structure provides an opportunity to encapsulate redundant logic, too. Instead of sophisticated logic being repeated, you can hide them behind a single method you use in a where LINQ operation.
var Bindings = AllBindings.Where(B => Operation.Scope.IsSatisfiedBy(B.Scope));
At its core, this package provides the abstraction to solve this problem, but it goes a little further.
Built-In Scope Types
While the fundamental purpose of the library is to provide the contract, this package also provides two built-in types of scope:
- A scope that operates by supply and demand of tokens
- A scope that combines two other scopes into a multidimensional scope
Later, an hierarchical built-in may be added.
Supply and Demand
A supply and demand scope space involves explicit declarations involving tokens. These tokens can be of any type.
Following is an example of use.
[TestMethod]
public void SelectItem()
{
var ScopeSpace = ScopeSpaces.SupplyAndDemand<ClauseType>();
var BindingScope = ScopeSpace.Supply(Given);
var Included = ScopeSpace.Demand(Given).IsSatisfiedBy(BindingScope);
Included.ShouldBeTrue();
}
[TestMethod]
public void FailToSelectItem()
{
var ScopeSpace = ScopeSpaces.SupplyAndDemand<ClauseType>();
var BindingScope = ScopeSpace.Supply([Given, Then]);
var Included = ScopeSpace.Demand(When).IsSatisfiedBy(BindingScope);
Included.ShouldBeFalse();
}
Composite
A composite scope space is multi-dimensional.
[TestMethod]
public void SelectItemInCompositeSpace()
{
var ClauseTypes = ScopeSpaces.SupplyAndDemand<ClauseType>();
var Features = ScopeSpaces.SupplyAndDemand<string>();
var CompositeSpace = ScopeSpaces.Composite(ClauseTypes, Features);
var BindingScope = CompositeSpace.Combine(ClauseTypes.Any, Features.Supply("Scope Resolution"));
var Included = CompositeSpace.Combine(ClauseTypes.Demand(Given), Features.Any).IsSatisfiedBy(BindingScope);
Included.ShouldBeTrue();
}
[TestMethod]
public void FailCompositeSelectionDueToOneDimension()
{
var ClauseTypes = ScopeSpaces.SupplyAndDemand<ClauseType>();
var Features = ScopeSpaces.SupplyAndDemand<string>();
var CompositeSpace = ScopeSpaces.Composite(ClauseTypes, Features);
var BindingScope = CompositeSpace.Combine(ClauseTypes.Unspecified, Features.Supply("Scope Resolution"));
var Included = CompositeSpace.Combine(ClauseTypes.Demand(Given), Features.Any).IsSatisfiedBy(BindingScope);
Included.ShouldBeFalse();
}
It does not matter the two underlying dimensions are. You can even have two dimensions from the exact same type of space.
Distinct Scope Spaces
Both the composite and the supply and demand scope spaces are distinct. That means that all scopes must come from the same origin space to be unioned, intersected, and compared.
Scopes from different spaces that have relational operations run on them will generate InvalidOperationExceptions. This mirrors at runtime the behavior you alreay get from the compiler when dealing with scopes of different type.
The Null Scope Space
There is one more built-in type of scope: the null scope space. This models having no scope partitioning at all.
Every scope in this space is always satisfied by every other object in the same space and the spaces are not considered distinct.
Contributing
Feel free to reach out to me on GitHub or via LinkedIn.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Text.Json (>= 10.0.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on ScopeSelection:
| Package | Downloads |
|---|---|
|
LineParser
A parser for small blocks of text that supports recursive, extensible patterns. |
GitHub repositories
This package is not used by any popular GitHub repositories.