Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 3.0.0 #170

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 4 additions & 3 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ dotnet_code_quality_unused_parameters = all:suggestion
#### C# Coding Conventions ####

# var preferences
csharp_style_var_elsewhere = false:silent
csharp_style_var_for_built_in_types = false:silent
csharp_style_var_when_type_is_apparent = false:silent
csharp_style_var_elsewhere = true:silent
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent

# Expression-bodied members
csharp_style_expression_bodied_accessors = true:silent
Expand Down Expand Up @@ -231,6 +231,7 @@ dotnet_style_namespace_match_folder = true:suggestion
csharp_style_prefer_switch_expression = true:suggestion
csharp_style_prefer_pattern_matching = true:silent
csharp_style_prefer_not_pattern = true:suggestion
csharp_style_prefer_primary_constructors = true:suggestion

[*.vb]
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion:suggestion
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
namespace Rules.Framework.InMemory.Sample.Engine
{
using System.Collections.Generic;
using global::Rules.Framework.InMemory.Sample.Enums;

internal interface IContentTypes
internal interface IRuleSpecificationsProvider
{
RulesetNames[] Rulesets { get; }

IEnumerable<RuleSpecification> GetRulesSpecifications();
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
namespace Rules.Framework.InMemory.Sample.Engine
{
using global::Rules.Framework;
using global::Rules.Framework.Builder;
using global::Rules.Framework.Builder.Generic;
using global::Rules.Framework.InMemory.Sample.Enums;

internal class RuleSpecification
{
public RuleAddPriorityOption RuleAddPriorityOption { get; set; }

public RuleBuilderResult<ContentTypes, ConditionTypes> RuleBuilderResult { get; set; }
public RuleBuilderResult<RulesetNames, ConditionNames> RuleBuilderResult { get; set; }
}
}
18 changes: 11 additions & 7 deletions samples/Rules.Framework.InMemory.Sample/Engine/RulesBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ namespace Rules.Framework.InMemory.Sample.Engine
{
using System.Collections.Generic;
using System.Threading.Tasks;
using global::Rules.Framework.InMemory.Sample.Enums;
using global::Rules.Framework.InMemory.Sample.Exceptions;

internal class RulesBuilder
{
private readonly IEnumerable<IContentTypes> contentTypes;
private readonly IEnumerable<IRuleSpecificationsProvider> ruleSpecificationsRegistrars;

public RulesBuilder(IEnumerable<IContentTypes> contentTypes) => this.contentTypes = contentTypes;
public RulesBuilder(IEnumerable<IRuleSpecificationsProvider> ruleSpecificationsProviders) => this.ruleSpecificationsRegistrars = ruleSpecificationsProviders;

public async Task BuildAsync(RulesEngine<ContentTypes, ConditionTypes> rulesEngine)
public async Task BuildAsync(IRulesEngine rulesEngine)
{
foreach (var contentType in contentTypes)
foreach (var ruleSpecificationsProvider in ruleSpecificationsRegistrars)
{
var rulesSpecifications = contentType.GetRulesSpecifications();
foreach (var ruleset in ruleSpecificationsProvider.Rulesets)
{
await rulesEngine.CreateRulesetAsync(ruleset.ToString());
}

var rulesSpecifications = ruleSpecificationsProvider.GetRulesSpecifications();

foreach (var ruleSpecification in rulesSpecifications)
{
Expand All @@ -28,7 +32,7 @@ public async Task BuildAsync(RulesEngine<ContentTypes, ConditionTypes> rulesEngi
.AddRuleAsync(
ruleSpecification.RuleBuilderResult.Rule,
ruleSpecification.RuleAddPriorityOption
).ConfigureAwait(false);
);

if (!ruleOperationResult.IsSuccess)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,17 @@ namespace Rules.Framework.InMemory.Sample.Engine
using System;
using System.Threading;
using System.Threading.Tasks;
using global::Rules.Framework.InMemory.Sample.Enums;
using global::Rules.Framework.Providers.InMemory;

internal class RulesEngineProvider
{
private readonly Lazy<Task<RulesEngine<ContentTypes, ConditionTypes>>> lazyRulesEngine;
private readonly Lazy<Task<IRulesEngine>> lazyRulesEngine;

public RulesEngineProvider(RulesBuilder rulesBuilder)
{
lazyRulesEngine = new Lazy<Task<RulesEngine<ContentTypes, ConditionTypes>>>(async () =>
lazyRulesEngine = new Lazy<Task<IRulesEngine>>(async () =>
{
var rulesEngine = RulesEngineBuilder
.CreateRulesEngine()
.WithContentType<ContentTypes>()
.WithConditionType<ConditionTypes>()
.SetInMemoryDataSource()
.Configure(opt => opt.PriorityCriteria = PriorityCriterias.BottommostRuleWins)
.Build();
Expand All @@ -28,7 +24,7 @@ public RulesEngineProvider(RulesBuilder rulesBuilder)
}, LazyThreadSafetyMode.ExecutionAndPublication);
}

public Task<RulesEngine<ContentTypes, ConditionTypes>> GetRulesEngineAsync()
public Task<IRulesEngine> GetRulesEngineAsync()
=> lazyRulesEngine.Value;
}
}
18 changes: 7 additions & 11 deletions samples/Rules.Framework.InMemory.Sample/Engine/RulesService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ namespace Rules.Framework.InMemory.Sample.Engine
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using global::Rules.Framework.InMemory.Sample.Enums;
using global::Rules.Framework.InMemory.Sample.Exceptions;
Expand All @@ -11,32 +10,29 @@ internal class RulesService
{
private readonly RulesEngineProvider rulesEngineProvider;

public RulesService(IEnumerable<IContentTypes> contentTypes)
public RulesService(IEnumerable<IRuleSpecificationsProvider> ruleSpecificationsProviders)
{
this.rulesEngineProvider = new RulesEngineProvider(new RulesBuilder(contentTypes));
this.rulesEngineProvider = new RulesEngineProvider(new RulesBuilder(ruleSpecificationsProviders));
}

public async Task<T> MatchOneAsync<T>(
ContentTypes contentType,
RulesetNames ruleset,
DateTime dateTime,
IDictionary<ConditionTypes, object> conditions)
IDictionary<ConditionNames, object> conditions)
{
var rulesConditions = (conditions is null) ? new Condition<ConditionTypes>[] { } :
conditions.Select(x => new Condition<ConditionTypes>(x.Key, x.Value))
.ToArray();

var rulesEngine = await
rulesEngineProvider
.GetRulesEngineAsync()
.ConfigureAwait(false);

var match = await rulesEngine
.MatchOneAsync(contentType, dateTime, rulesConditions)
.MakeGeneric<RulesetNames, ConditionNames>()
.MatchOneAsync(ruleset, dateTime, conditions)
.ConfigureAwait(false);

if (match is null)
{
var message = $"Error trying to match one rule. No rule was found {contentType} {dateTime} {string.Join(", ", conditions)}.";
var message = $"Error trying to match one rule. No rule was found {ruleset} {dateTime} {string.Join(", ", conditions)}.";

throw new RulesNotFoundException(message);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
namespace Rules.Framework.InMemory.Sample.Enums
{
internal enum ConditionTypes
internal enum ConditionNames
{
/// <summary>
/// no condition type defined
/// no condition defined
/// </summary>
None = 0,

/// <summary>
/// condition type to filter by royal numbers
/// condition to filter by royal numbers
/// </summary>
RoyalNumber = 1,

/// <summary>
/// condition type to filter if the number can be divided by 3
/// condition to filter if the number can be divided by 3
/// </summary>
CanNumberBeDividedBy3 = 2,

/// <summary>
/// condition type to filter if the number is prime
/// condition to filter if the number is prime
/// </summary>
IsPrimeNumber = 3,

/// <summary>
/// condition type to filter number sums
/// condition to filter number sums
/// </summary>
SumAll = 4
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace Rules.Framework.InMemory.Sample.Enums
{
internal enum ContentTypes
internal enum RulesetNames
{
None = 0,

/// <summary>
/// this content verifies if number is cool or not
/// this ruleset contains rules that verify if a number is cool or not
/// </summary>
TestNumber = 1,
}
Expand Down
22 changes: 10 additions & 12 deletions samples/Rules.Framework.InMemory.Sample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ namespace Rules.Framework.InMemory.Sample
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using global::Rules.Framework.InMemory.Sample.Engine;
using global::Rules.Framework.InMemory.Sample.Enums;
using global::Rules.Framework.InMemory.Sample.Helper;
using global::Rules.Framework.InMemory.Sample.Rules;

internal class Program
{
private static void Main(string[] args)
private static async Task Main(string[] args)
{
var rulesService = new RulesService(new List<IContentTypes>()
var rulesService = new RulesService(new List<IRuleSpecificationsProvider>()
{
new TestNumberRules()
});
Expand All @@ -31,18 +32,15 @@ private static void Main(string[] args)
break;
}

var conditions = new Dictionary<ConditionTypes, object> {
{ ConditionTypes.IsPrimeNumber, value.IsPrime() },
{ ConditionTypes.CanNumberBeDividedBy3, value.CanNumberBeDividedBy3() },
{ ConditionTypes.SumAll, value.SumAll() },
{ ConditionTypes.RoyalNumber, value }
var conditions = new Dictionary<ConditionNames, object> {
{ ConditionNames.IsPrimeNumber, value.IsPrime() },
{ ConditionNames.CanNumberBeDividedBy3, value.CanNumberBeDividedBy3() },
{ ConditionNames.SumAll, value.SumAll() },
{ ConditionNames.RoyalNumber, value }
};

var result = rulesService
.MatchOneAsync<string>(ContentTypes.TestNumber, targetDate, conditions)
.ConfigureAwait(false)
.GetAwaiter()
.GetResult();
var result = await rulesService
.MatchOneAsync<string>(RulesetNames.TestNumber, targetDate, conditions);

Console.WriteLine($"The result is: {result}");
}
Expand Down
59 changes: 27 additions & 32 deletions samples/Rules.Framework.InMemory.Sample/Rules/TestNumberRules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ namespace Rules.Framework.InMemory.Sample.Rules
{
using System;
using System.Collections.Generic;
using global::Rules.Framework.Builder;
using global::Rules.Framework.Core;
using global::Rules.Framework.Builder.Generic;
using global::Rules.Framework.InMemory.Sample.Engine;
using global::Rules.Framework.InMemory.Sample.Enums;

internal class TestNumberRules : IContentTypes
internal class TestNumberRules : IRuleSpecificationsProvider
{
public readonly List<RuleSpecification> rulesSpecifications;

Expand All @@ -16,6 +15,8 @@ public TestNumberRules()
this.rulesSpecifications = new List<RuleSpecification>();
}

public RulesetNames[] Rulesets => new[] { RulesetNames.TestNumber, };

public IEnumerable<RuleSpecification> GetRulesSpecifications()
{
Add(CreateRuleForCoolNumbers(), RuleAddPriorityOption.ByPriorityNumber(3));
Expand All @@ -26,47 +27,41 @@ public IEnumerable<RuleSpecification> GetRulesSpecifications()
}

private void Add(
RuleBuilderResult<ContentTypes, ConditionTypes> rule,
RuleBuilderResult<RulesetNames, ConditionNames> rule,
RuleAddPriorityOption ruleAddPriorityOption) => rulesSpecifications.Add(
new RuleSpecification
{
RuleBuilderResult = rule,
RuleAddPriorityOption = ruleAddPriorityOption,
});

private RuleBuilderResult<ContentTypes, ConditionTypes> CreateDefaultRule() =>
RuleBuilder
.NewRule<ContentTypes, ConditionTypes>()
.WithName("Default rule for test number")
.WithContent(ContentTypes.TestNumber, ":| default nothing special about this number")
.WithDateBegin(new DateTime(2019, 01, 01))
private RuleBuilderResult<RulesetNames, ConditionNames> CreateDefaultRule() => Rule.Create<RulesetNames, ConditionNames>("Default rule for test number")
.InRuleset(RulesetNames.TestNumber)
.SetContent(":| default nothing special about this number")
.Since(new DateTime(2019, 01, 01))
.Build();

private RuleBuilderResult<ContentTypes, ConditionTypes> CreateRuleForCoolNumbers() =>
RuleBuilder
.NewRule<ContentTypes, ConditionTypes>()
.WithName("Rule for cool numbers")
.WithContent(ContentTypes.TestNumber, ":D this number is so COOL!")
.WithDateBegin(new DateTime(2019, 01, 01))
.WithCondition(c => c
.Or(o => o
.Value(ConditionTypes.RoyalNumber, Operators.Equal, 7)
.And(a => a
.Value(ConditionTypes.IsPrimeNumber, Operators.Equal, 7)
.Value(ConditionTypes.SumAll, Operators.StartsWith, "5"))))
private RuleBuilderResult<RulesetNames, ConditionNames> CreateRuleForCoolNumbers() => Rule.Create<RulesetNames, ConditionNames>("Rule for cool numbers")
.InRuleset(RulesetNames.TestNumber)
.SetContent(":D this number is so COOL!")
.Since(new DateTime(2019, 01, 01))
.ApplyWhen(c => c
.Or(o => o
.Value(ConditionNames.RoyalNumber, Operators.Equal, 7)
.And(a => a
.Value(ConditionNames.IsPrimeNumber, Operators.Equal, 7)
.Value(ConditionNames.SumAll, Operators.StartsWith, "5"))))
.Build();

private RuleBuilderResult<ContentTypes, ConditionTypes> CreateRuleForSosoNumbers() =>
RuleBuilder
.NewRule<ContentTypes, ConditionTypes>()
.WithName("Rule for so so numbers")
.WithContent(ContentTypes.TestNumber, ":) this number is so so")
.WithDateBegin(new DateTime(2019, 01, 01))
.WithCondition(c => c
private RuleBuilderResult<RulesetNames, ConditionNames> CreateRuleForSosoNumbers() => Rule.Create<RulesetNames, ConditionNames>("Rule for so so numbers")
.InRuleset(RulesetNames.TestNumber)
.SetContent(":) this number is so so")
.Since(new DateTime(2019, 01, 01))
.ApplyWhen(c => c
.Or(o => o
.Value(ConditionTypes.CanNumberBeDividedBy3, Operators.Equal, true)
.Value(ConditionTypes.IsPrimeNumber, Operators.Equal, false)
.Value(ConditionTypes.SumAll, Operators.StartsWith, "9")))
.Value(ConditionNames.CanNumberBeDividedBy3, Operators.Equal, true)
.Value(ConditionNames.IsPrimeNumber, Operators.Equal, false)
.Value(ConditionNames.SumAll, Operators.StartsWith, "9")))
.Build();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
namespace Rules.Framework.WebUI.Sample.Engine
{
using System.Collections.Generic;
using global::Rules.Framework.WebUI.Sample.Enums;

internal interface IContentTypes
internal interface IRuleSpecificationsProvider
{
RulesetNames[] Rulesets { get; }

IEnumerable<RuleSpecification> GetRulesSpecifications();
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
namespace Rules.Framework.WebUI.Sample.Engine
{
using global::Rules.Framework;
using global::Rules.Framework.Builder;
using global::Rules.Framework.Builder.Generic;
using global::Rules.Framework.WebUI.Sample.Enums;

internal sealed class RuleSpecification : RuleSpecificationBase<ContentTypes, ConditionTypes>
internal sealed class RuleSpecification : RuleSpecificationBase<RulesetNames, ConditionNames>
{
public RuleSpecification(
RuleBuilderResult<ContentTypes, ConditionTypes> ruleBuilderResult,
RuleBuilderResult<RulesetNames, ConditionNames> ruleBuilderResult,
RuleAddPriorityOption ruleAddPriorityOption)
: base(ruleBuilderResult, ruleAddPriorityOption)
{
Expand Down
Loading
Loading