diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..2b5f541 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,30 @@ +#---------------------------------# +# Build Image # +#---------------------------------# +image: Visual Studio 2017 + +#---------------------------------# +# Build Script # +#---------------------------------# +build_script: + - ps: .\build.ps1 -Target AppVeyor + +# Tests +test: off + +#---------------------------------# +# Branches to build # +#---------------------------------# +branches: + # Whitelist + only: + - develop + - master + - /release/.*/ + - /hotfix/.*/ + +#---------------------------------# +# Build Cache # +#---------------------------------# +cache: +- tools -> setup.cake \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..c398278 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +# These owners will be the default owners for everything in the repo and +# will be requested for review when someone opens a pull request. +* @Speeedy01 @marco-bertschi @pascalberger @christianbumann @x-jokay @silanosa @georgesgoetz \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3e759b7..d286e5d 100644 --- a/.gitignore +++ b/.gitignore @@ -299,8 +299,8 @@ __pycache__/ *.pyc # Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config +tools/** +!tools/packages.config # Tabs Studio *.tss @@ -328,3 +328,8 @@ ASALocalRun/ # MFractors (Xamarin productivity tool) working folder .mfractor/ + +# Project specific + +config.wyam.* +BuildArtifacts/ \ No newline at end of file diff --git a/.mergify.yml b/.mergify.yml new file mode 100644 index 0000000..8c38b80 --- /dev/null +++ b/.mergify.yml @@ -0,0 +1,5 @@ +pull_request_rules: + - name: delete head branch after merge + conditions: [] + actions: + delete_head_branch: {} \ No newline at end of file diff --git a/GitReleaseManager.yaml b/GitReleaseManager.yaml new file mode 100644 index 0000000..721c1ba --- /dev/null +++ b/GitReleaseManager.yaml @@ -0,0 +1,12 @@ +issue-labels-include: +- Breaking change +- Feature +- Bug +- Improvement +- Documentation +issue-labels-exclude: +- Build +issue-labels-alias: + - name: Documentation + header: Documentation + plural: Documentation \ No newline at end of file diff --git a/README.md b/README.md index 4911065..a221a7c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,36 @@ -# BBT.Strategy -A strategy pattern implementation +# BBT.StrategyPattern + +An strategy pattern implementation for .NET. + +[![License](http://img.shields.io/:license-mit-blue.svg)](https://github.com/bbtsoftware/BBT.StrategyPattern/blob/master/LICENSE) + +## Information + +| | Stable | Pre-release | +|:--:|:--:|:--:| +|GitHub Release|-|[![GitHub release](https://img.shields.io/github/release/bbtsoftware/BBT.StrategyPattern.svg)](https://github.com/bbtsoftware/BBT.StrategyPattern/releases/latest)| +|NuGet|[![NuGet](https://img.shields.io/nuget/v/BBT.StrategyPattern.svg)](https://www.nuget.org/packages/BBT.StrategyPattern)|[![NuGet](https://img.shields.io/nuget/vpre/BBT.StrategyPattern.svg)](https://www.nuget.org/packages/BBT.StrategyPattern)| + +## Build Status + +|Develop|Master| +|:--:|:--:| +|[![Build status](https://ci.appveyor.com/api/projects/status/bncb5oc7ah2ti95y/branch/develop?svg=true)](https://ci.appveyor.com/project/BBTSoftwareAG/bbt-strategypattern/branch/develop)|[![Build status](https://ci.appveyor.com/api/projects/status/bncb5oc7ah2ti95y/branch/master?svg=true)](https://ci.appveyor.com/project/BBTSoftwareAG/bbt-strategypattern/branch/master)| + +## Code Coverage + +[![Coverage Status](https://coveralls.io/repos/github/bbtsoftware/BBT.StrategyPattern/badge.svg?branch=develop)](https://coveralls.io/github/bbtsoftware/BBT.StrategyPattern?branch=develop) + +## Quick Links + +* [Documentation](https://bbtsoftware.github.io/BBT.StrategyPattern/) + +## Build + +To build this package we are using [Cake](https://cakebuild.net). + +On Windows PowerShell run: + +```powershell +./build +``` diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..bdfb32b --- /dev/null +++ b/build.ps1 @@ -0,0 +1,184 @@ +########################################################################## +# This is the Cake bootstrapper script for PowerShell. +# This file was downloaded from https://github.com/cake-build/resources +# Feel free to change this file to fit your needs. +########################################################################## + +<# +.SYNOPSIS +This is a Powershell script to bootstrap a Cake build. +.DESCRIPTION +This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) +and execute your Cake build script with the parameters you provide. +.PARAMETER Script +The build script to execute. +.PARAMETER Target +The build script target to run. +.PARAMETER Configuration +The build configuration to use. +.PARAMETER Verbosity +Specifies the amount of information to be displayed. +.PARAMETER Experimental +Tells Cake to use the latest Roslyn release. +.PARAMETER WhatIf +Performs a dry run of the build script. +No tasks will be executed. +.PARAMETER Mono +Tells Cake to use the Mono scripting engine. +.PARAMETER SkipToolPackageRestore +Skips restoring of packages. +.PARAMETER ScriptArgs +Remaining arguments are added here. +.LINK +http://cakebuild.net +#> + +[CmdletBinding()] +Param( + [string]$Script = "setup.cake", + [string]$Target = "Default", + [ValidateSet("Release", "Debug")] + [string]$Configuration = "Release", + [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] + [string]$Verbosity = "Verbose", + [switch]$Experimental, + [Alias("DryRun","Noop")] + [switch]$WhatIf, + [switch]$Mono, + [switch]$SkipToolPackageRestore, + [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] + [string[]]$ScriptArgs +) + +[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null +function MD5HashFile([string] $filePath) +{ + if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) + { + return $null + } + + [System.IO.Stream] $file = $null; + [System.Security.Cryptography.MD5] $md5 = $null; + try + { + $md5 = [System.Security.Cryptography.MD5]::Create() + $file = [System.IO.File]::OpenRead($filePath) + return [System.BitConverter]::ToString($md5.ComputeHash($file)) + } + finally + { + if ($file -ne $null) + { + $file.Dispose() + } + } +} + +Write-Host "Preparing to run build script..." + +if(!$PSScriptRoot){ + $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent +} + +$TOOLS_DIR = Join-Path $PSScriptRoot "tools" +$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" +$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" +$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" +$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" +$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" + +# Should we use mono? +$UseMono = ""; +if($Mono.IsPresent) { + Write-Verbose -Message "Using the Mono based scripting engine." + $UseMono = "-mono" +} + +# Should we use the new Roslyn? +$UseExperimental = ""; +if($Experimental.IsPresent -and !($Mono.IsPresent)) { + Write-Verbose -Message "Using experimental version of Roslyn." + $UseExperimental = "-experimental" +} + +# Is this a dry run? +$UseDryRun = ""; +if($WhatIf.IsPresent) { + $UseDryRun = "-dryrun" +} + +# Make sure tools folder exists +if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { + Write-Verbose -Message "Creating tools directory..." + New-Item -Path $TOOLS_DIR -Type directory | out-null +} + +# Make sure that packages.config exist. +if (!(Test-Path $PACKAGES_CONFIG)) { + Write-Verbose -Message "Downloading packages.config..." + try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { + Throw "Could not download packages.config." + } +} + +# Try find NuGet.exe in path if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Trying to find nuget.exe in PATH..." + $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) } + $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 + if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { + Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." + $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName + } +} + +# Try download NuGet.exe if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Downloading NuGet.exe..." + try { + (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) + } catch { + Throw "Could not download NuGet.exe." + } +} + +# Save nuget.exe path to environment to be available to child processed +$ENV:NUGET_EXE = $NUGET_EXE + +# Restore tools from NuGet? +if(-Not $SkipToolPackageRestore.IsPresent) { + Push-Location + Set-Location $TOOLS_DIR + + # Check for changes in packages.config and remove installed tools if true. + [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) + if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or + ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { + Write-Verbose -Message "Missing or changed package.config hash..." + Remove-Item * -Recurse -Exclude packages.config,nuget.exe + } + + Write-Verbose -Message "Restoring tools from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -PreRelease -OutputDirectory `"$TOOLS_DIR`" -Source https://www.myget.org/F/cake/api/v3/index.json" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring NuGet tools." + } + else + { + $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" + } + Write-Verbose -Message ($NuGetOutput | out-string) + Pop-Location +} + +# Make sure that Cake has been installed. +if (!(Test-Path $CAKE_EXE)) { + Throw "Could not find Cake.exe at $CAKE_EXE" +} + +# Start Cake +Write-Host "Running build script..." +Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" +exit $LASTEXITCODE \ No newline at end of file diff --git a/docs/input/_Bottom.cshtml b/docs/input/_Bottom.cshtml new file mode 100644 index 0000000..5b3d2af --- /dev/null +++ b/docs/input/_Bottom.cshtml @@ -0,0 +1,50 @@ +
+ GitHub +
+ + + + diff --git a/docs/input/_Footer.cshtml b/docs/input/_Footer.cshtml new file mode 100644 index 0000000..4ad5bce --- /dev/null +++ b/docs/input/_Footer.cshtml @@ -0,0 +1,5 @@ +

+ Copyright © BBT Software AG and contributors. +
+ Website generated by Wyam +

diff --git a/docs/input/_Navbar.cshtml b/docs/input/_Navbar.cshtml new file mode 100644 index 0000000..0a7d28d --- /dev/null +++ b/docs/input/_Navbar.cshtml @@ -0,0 +1,12 @@ +@{ + List> pages = new List> + { + Tuple.Create("Documentation", Context.GetLink("docs")), + Tuple.Create("API", Context.GetLink("api/BBT.StrategyPattern")) + }; + foreach(Tuple p in pages) + { + string active = Context.GetLink(Document).StartsWith(p.Item2) ? "active" : null; +
  • @Html.Raw(p.Item1)
  • + } +} \ No newline at end of file diff --git a/docs/input/assets/css/fonts/glyphicons-halflings-regular.eot b/docs/input/assets/css/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000..b93a495 Binary files /dev/null and b/docs/input/assets/css/fonts/glyphicons-halflings-regular.eot differ diff --git a/docs/input/assets/css/fonts/glyphicons-halflings-regular.svg b/docs/input/assets/css/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 0000000..94fb549 --- /dev/null +++ b/docs/input/assets/css/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/input/assets/css/fonts/glyphicons-halflings-regular.ttf b/docs/input/assets/css/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000..1413fc6 Binary files /dev/null and b/docs/input/assets/css/fonts/glyphicons-halflings-regular.ttf differ diff --git a/docs/input/assets/css/fonts/glyphicons-halflings-regular.woff b/docs/input/assets/css/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 0000000..9e61285 Binary files /dev/null and b/docs/input/assets/css/fonts/glyphicons-halflings-regular.woff differ diff --git a/docs/input/assets/css/fonts/glyphicons-halflings-regular.woff2 b/docs/input/assets/css/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 0000000..64539b5 Binary files /dev/null and b/docs/input/assets/css/fonts/glyphicons-halflings-regular.woff2 differ diff --git a/docs/input/assets/css/override.less b/docs/input/assets/css/override.less new file mode 100644 index 0000000..3208c66 --- /dev/null +++ b/docs/input/assets/css/override.less @@ -0,0 +1,139 @@ +/* Control the margin for bootstrap alert boxes */ +.alert > p { + margin-top: 0px; +} + +/* Control the look and feel of the copy box applied to code sections */ +.btn-copy[disabled] .clippy { + opacity: .3; +} +pre .btn-copy { + -webkit-transition: opacity 0.3s ease-in-out; + -o-transition: opacity 0.3s ease-in-out; + transition: opacity 0.3s ease-in-out; + opacity: 0; + padding: 2px 6px; + float: right; +} +pre:hover .btn-copy { + opacity: 1; +} +.tooltipped { + position: relative +} +.tooltipped:after { + position: absolute; + z-index: 1000000; + display: none; + padding: 5px 8px; + font: normal normal 11px/1.5 Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; + color: #fff; + text-align: center; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-wrap: break-word; + white-space: pre; + pointer-events: none; + content: attr(aria-label); + background: rgba(0, 0, 0, 0.8); + border-radius: 3px; + -webkit-font-smoothing: subpixel-antialiased +} +.tooltipped:before { + position: absolute; + z-index: 1000001; + display: none; + width: 0; + height: 0; + color: rgba(0, 0, 0, 0.8); + pointer-events: none; + content: ""; + border: 5px solid transparent +} +.tooltipped:hover:before, .tooltipped:hover:after, .tooltipped:active:before, .tooltipped:active:after, .tooltipped:focus:before, .tooltipped:focus:after { + display: inline-block; + text-decoration: none +} +.tooltipped-s:after, .tooltipped-se:after, .tooltipped-sw:after { + top: 100%; + right: 50%; + margin-top: 5px +} +.tooltipped-s:before, .tooltipped-se:before, .tooltipped-sw:before { + top: auto; + right: 50%; + bottom: -5px; + margin-right: -5px; + border-bottom-color: rgba(0, 0, 0, 0.8) +} + +@font-family-sans-serif: "Roboto", Helvetica, Arial, sans-serif; + +/* For Gitter and GitHub */ +.bottom-footer { + margin-bottom: 40px !important; // Make room for Gitter and GitHub buttons +} + +.gitter-open-chat-button { + background-color: #3c8dbc; + font-family: @font-family-sans-serif; + letter-spacing: normal; + right: 90px; +} + +.gitter-open-chat-button:focus, .gitter-open-chat-button:hover, +.github-button:focus, .github-button:hover, +{ + background-color: #4EABDD; + color: #fff; +} + +.gitter-chat-embed { + top: 49px; + border-top: 1px solid #000; + z-index: 10000; +} + +.github-button { + z-index: 100; + position: fixed; + bottom: 0px; + right: 240px; + padding: 1em 3em; + background-color: #367fa9; + border: 0; + border-top-left-radius: 0.5em; + border-top-right-radius: 0.5em; + font-family: sans-serif; + font-size: 9pt; + text-transform: uppercase; + text-align: center; + text-decoration: none; + cursor: pointer; + cursor: hand; + -webkit-transition: all .3s ease; + transition: all .3s ease; + color: #fff; + a, a:active, a:hover, a:focus { + color: #fff; + } +} + +/* For feature list */ + +.feature-list li { + display: block; +} + +.feature-list li:before { + /*Using a Bootstrap glyphicon as the bullet point*/ + content: "\e013"; + font-family: 'Glyphicons Halflings'; + font-size: 12px; + float: left; + margin-top: 1px; + margin-left: -25px; + color: green; +} \ No newline at end of file diff --git a/docs/input/assets/images/clippy.svg b/docs/input/assets/images/clippy.svg new file mode 100644 index 0000000..e1b1703 --- /dev/null +++ b/docs/input/assets/images/clippy.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/input/assets/js/anchor.min.js b/docs/input/assets/js/anchor.min.js new file mode 100644 index 0000000..7f34489 --- /dev/null +++ b/docs/input/assets/js/anchor.min.js @@ -0,0 +1,6 @@ +/** + * AnchorJS - v3.2.2 - 2016-10-05 + * https://github.com/bryanbraun/anchorjs + * Copyright (c) 2016 Bryan Braun; Licensed MIT + */ +!function(A,e){"use strict";"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():(A.AnchorJS=e(),A.anchors=new A.AnchorJS)}(this,function(){"use strict";function A(A){function e(A){A.icon=A.hasOwnProperty("icon")?A.icon:"",A.visible=A.hasOwnProperty("visible")?A.visible:"hover",A.placement=A.hasOwnProperty("placement")?A.placement:"right",A.class=A.hasOwnProperty("class")?A.class:"",A.truncate=A.hasOwnProperty("truncate")?Math.floor(A.truncate):64}function t(A){var e;if("string"==typeof A||A instanceof String)e=[].slice.call(document.querySelectorAll(A));else{if(!(Array.isArray(A)||A instanceof NodeList))throw new Error("The selector provided to AnchorJS was invalid.");e=[].slice.call(A)}return e}function n(){if(null===document.head.querySelector("style.anchorjs")){var A,e=document.createElement("style"),t=" .anchorjs-link { opacity: 0; text-decoration: none; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }",n=" *:hover > .anchorjs-link, .anchorjs-link:focus { opacity: 1; }",i=' @font-face { font-family: "anchorjs-icons"; src: url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype"); }',o=" [data-anchorjs-icon]::after { content: attr(data-anchorjs-icon); }";e.className="anchorjs",e.appendChild(document.createTextNode("")),A=document.head.querySelector('[rel="stylesheet"], style'),void 0===A?document.head.appendChild(e):document.head.insertBefore(e,A),e.sheet.insertRule(t,e.sheet.cssRules.length),e.sheet.insertRule(n,e.sheet.cssRules.length),e.sheet.insertRule(o,e.sheet.cssRules.length),e.sheet.insertRule(i,e.sheet.cssRules.length)}}this.options=A||{},this.elements=[],e(this.options),this.isTouchDevice=function(){return!!("ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch)},this.add=function(A){var i,o,s,c,r,a,h,l,u,d,f,p,w=[];if(e(this.options),p=this.options.visible,"touch"===p&&(p=this.isTouchDevice()?"always":"hover"),A||(A="h1, h2, h3, h4, h5, h6"),i=t(A),0===i.length)return!1;for(n(),o=document.querySelectorAll("[id]"),s=[].map.call(o,function(A){return A.id}),r=0;r-1,t=A.lastChild&&(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ")>-1;return e||t||!1}}return A}); diff --git a/docs/input/assets/js/clipboard.min.js b/docs/input/assets/js/clipboard.min.js new file mode 100644 index 0000000..1d7c5d5 --- /dev/null +++ b/docs/input/assets/js/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v1.5.16 + * https://zenorocha.github.io/clipboard.js + * + * Licensed MIT © Zeno Rocha + */ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Clipboard=e()}}(function(){var e,t,n;return function e(t,n,i){function o(a,c){if(!n[a]){if(!t[a]){var l="function"==typeof require&&require;if(!c&&l)return l(a,!0);if(r)return r(a,!0);var s=new Error("Cannot find module '"+a+"'");throw s.code="MODULE_NOT_FOUND",s}var u=n[a]={exports:{}};t[a][0].call(u.exports,function(e){var n=t[a][1][e];return o(n?n:e)},u,u.exports,e,t,n,i)}return n[a].exports}for(var r="function"==typeof require&&require,a=0;a0&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function e(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function e(){var t=this,n="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=document.body.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[n?"right":"left"]="-9999px";var i=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.addEventListener("focus",window.scrollTo(0,i)),this.fakeElem.style.top=i+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,document.body.appendChild(this.fakeElem),this.selectedText=(0,o.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function e(){this.fakeHandler&&(document.body.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(document.body.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function e(){this.selectedText=(0,o.default)(this.target),this.copyText()}},{key:"copyText",value:function e(){var t=void 0;try{t=document.execCommand(this.action)}catch(e){t=!1}this.handleResult(t)}},{key:"handleResult",value:function e(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function e(){this.target&&this.target.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function e(){this.removeFake()}},{key:"action",set:function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function e(){return this._action}},{key:"target",set:function e(t){if(void 0!==t){if(!t||"object"!==("undefined"==typeof t?"undefined":r(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function e(){return this._target}}]),e}();e.exports=c})},{select:5}],8:[function(t,n,i){!function(o,r){if("function"==typeof e&&e.amd)e(["module","./clipboard-action","tiny-emitter","good-listener"],r);else if("undefined"!=typeof i)r(n,t("./clipboard-action"),t("tiny-emitter"),t("good-listener"));else{var a={exports:{}};r(a,o.clipboardAction,o.tinyEmitter,o.goodListener),o.clipboard=a.exports}}(this,function(e,t,n,i){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function c(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t){var n="data-clipboard-"+e;if(t.hasAttribute(n))return t.getAttribute(n)}var s=o(t),u=o(n),f=o(i),d=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText}},{key:"listenClick",value:function e(t){var n=this;this.listener=(0,f.default)(t,"click",function(e){return n.onClick(e)})}},{key:"onClick",value:function e(t){var n=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new s.default({action:this.action(n),target:this.target(n),text:this.text(n),trigger:n,emitter:this})}},{key:"defaultAction",value:function e(t){return l("action",t)}},{key:"defaultTarget",value:function e(t){var n=l("target",t);if(n)return document.querySelector(n)}},{key:"defaultText",value:function e(t){return l("text",t)}},{key:"destroy",value:function e(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}]),t}(u.default);e.exports=h})},{"./clipboard-action":7,"good-listener":4,"tiny-emitter":6}]},{},[8])(8)}); \ No newline at end of file diff --git a/docs/input/docs/features.md b/docs/input/docs/features.md new file mode 100644 index 0000000..5356bdc --- /dev/null +++ b/docs/input/docs/features.md @@ -0,0 +1,11 @@ +--- +Order: 10 +Title: Features +Description: Feature overview of BBT.StrategyPattern. +--- + +
      +
    • Fully abstract
    • +
    • Works with any IoC framework
    • +
    • Instance creator with IoC
    • +
    diff --git a/docs/input/docs/index.cshtml b/docs/input/docs/index.cshtml new file mode 100644 index 0000000..0610eb5 --- /dev/null +++ b/docs/input/docs/index.cshtml @@ -0,0 +1,13 @@ +--- +Title: Documentation +--- +@foreach(IDocument child in Model.DocumentList(Keys.Children).OrderBy(x => x.Get(DocsKeys.Order, 1000))) +{ +

    @(child.String(Keys.Title))

    + if(child.ContainsKey(DocsKeys.Description)) + { +

    @Html.Raw(child.String(DocsKeys.Description))

    + } + + @Html.Partial("_ChildPages", child) +} \ No newline at end of file diff --git a/docs/input/docs/usage/index.cshtml b/docs/input/docs/usage/index.cshtml new file mode 100644 index 0000000..ed3e2cc --- /dev/null +++ b/docs/input/docs/usage/index.cshtml @@ -0,0 +1,7 @@ +--- +Order: 20 +Description: How to obtain, configure, and use BBT.StrategyPattern. +--- +

    @Html.Raw(Model.String(DocsKeys.Description))

    + +@Html.Partial("_ChildPages") \ No newline at end of file diff --git a/docs/input/docs/usage/use-with-ioc.md b/docs/input/docs/usage/use-with-ioc.md new file mode 100644 index 0000000..f606231 --- /dev/null +++ b/docs/input/docs/usage/use-with-ioc.md @@ -0,0 +1,38 @@ +--- +Order: 20 +Title: Use with IoC +Description: Example how to use BBT.StrategyPattern with IoC. +--- + +```csharp +public void WorksWithIocNinject() +{ + var calc1 = new CalculationInput() { Number1 = 5, Number2 = 3 }; + var op1 = new Operator() { Operation = OperatorEnum.Addition }; + var op2 = new Operator() { Operation = OperatorEnum.Subtraktion }; + + IKernel kernel = new StandardKernel(); + + kernel + .Bind>() + .ToMethod((con) => new NinjectStrategyLocator(kernel)); + + kernel + .Bind() + .To(); + kernel + .Bind() + .To(); + kernel + .Bind>() + .To>(); + + IOperatorStrategy strategy; + + strategy = kernel.Get>().GetStrategy(op1); + strategy.DoCalculate(calc1).Should().Be(8); + + strategy = kernel.Get>().GetStrategy(op2); + strategy.DoCalculate(calc1).Should().Be(2); +} +``` diff --git a/docs/input/docs/usage/use-without-ioc.md b/docs/input/docs/usage/use-without-ioc.md new file mode 100644 index 0000000..2a7fc8a --- /dev/null +++ b/docs/input/docs/usage/use-without-ioc.md @@ -0,0 +1,25 @@ +--- +Order: 10 +Title: Use without IoC +Description: Example how to use BBT.StrategyPattern without IoC. +--- + +```csharp +public void GenericStrategyWorksInMemory() +{ + var calc1 = new CalculationInput() { Number1 = 5, Number2 = 3 }; + var op1 = new Operator() { Operation = OperatorEnum.Addition }; + var op2 = new Operator() { Operation = OperatorEnum.Subtraktion }; + + var factory = new MemoryOperatorStrategyLocator(); + var strategyProvider = new GenericStrategyProvider(factory); + + IOperatorStrategy strategy; + + strategy = strategyProvider.GetStrategy(op1); + strategy.DoCalculate(calc1).Should().Be(8); + + strategy = strategyProvider.GetStrategy(op2); + strategy.DoCalculate(calc1).Should().Be(2); +} +``` diff --git a/docs/input/index.cshtml b/docs/input/index.cshtml new file mode 100644 index 0000000..4352bae --- /dev/null +++ b/docs/input/index.cshtml @@ -0,0 +1,36 @@ +--- +Title: BBT.StrategyPattern +NoSidebar: true +NoContainer: true +NoGutter: true +--- + +
    +
    +

    BBT.StrategyPattern

    +

    + Strategy pattern implementation for .NET
    +

    + Learn more + API documentation +
    +
    + +
    +

    + GitHub + GitHub release (latest SemVer) + Nuget +

    + +

    + BBT.StrategyPattern a strategy pattern implementation for .NET. +

    + +

    Resources about strategy pattern

    + + +
    \ No newline at end of file diff --git a/docs/packages.xml b/docs/packages.xml new file mode 100644 index 0000000..d85bac4 --- /dev/null +++ b/docs/packages.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuspec/nuget/BBT.StrategyPattern.nuspec b/nuspec/nuget/BBT.StrategyPattern.nuspec new file mode 100644 index 0000000..24a9816 --- /dev/null +++ b/nuspec/nuget/BBT.StrategyPattern.nuspec @@ -0,0 +1,25 @@ + + + + BBT.StrategyPattern + BBT StrategyPattern + 0.0.0 + BBT Software AG + bbtsoftware + A strategy pattern implementation for .NET. + A strategy pattern implementation for .NET. + MIT + https://github.com/bbtsoftware/BBT.StrategyPattern/ + https://raw.githubusercontent.com/bbtsoftware/BBT.StrategyPattern/dfa1b06283f8e4d7dbd3793a3a4c2be7e2cff0c9/nuspec/nuget/icon.png + false + + Copyright © BBT Software AG + Strategy Pattern + https://github.com/bbtsoftware/BBT.StrategyPattern/releases/tag/1.0.0 + + + + + + + diff --git a/nuspec/nuget/icon.png b/nuspec/nuget/icon.png new file mode 100644 index 0000000..9925180 Binary files /dev/null and b/nuspec/nuget/icon.png differ diff --git a/setup.cake b/setup.cake new file mode 100644 index 0000000..4c01b0c --- /dev/null +++ b/setup.cake @@ -0,0 +1,34 @@ +#load nuget:?package=Cake.Recipe&version=1.0.0 + +////////////////////////////////////////////////////////////////////// +// PARAMETERS +////////////////////////////////////////////////////////////////////// + +Environment.SetVariableNames(); + +BuildParameters.SetParameters( + context: Context, + buildSystem: BuildSystem, + sourceDirectoryPath: "./src", + title: "BBT.StrategyPattern", + repositoryOwner: "bbtsoftware", + repositoryName: "BBT.StrategyPattern", + appVeyorAccountName: "BBTSoftwareAG", + shouldPublishMyGet: false, + shouldRunCodecov: true, + shouldDeployGraphDocumentation: false); + +BuildParameters.PrintParameters(Context); + +ToolSettings.SetToolSettings( + context: Context, + dupFinderExcludePattern: new string[] { BuildParameters.RootDirectoryPath + "/src/BBT.StrategyPattern.Tests/*.cs" }, + testCoverageFilter: "+[*]* -[xunit.*]* -[*.Tests]* -[FluentAssertions]*", + testCoverageExcludeByAttribute: "*.ExcludeFromCodeCoverage*", + testCoverageExcludeByFile: "*/*Designer.cs;*/*.g.cs;*/*.g.i.cs"); + +////////////////////////////////////////////////////////////////////// +// EXECUTION +////////////////////////////////////////////////////////////////////// + +Build.RunDotNetCore(); \ No newline at end of file diff --git a/src/BBT.StrategyPattern.Tests.ruleset b/src/BBT.StrategyPattern.Tests.ruleset new file mode 100644 index 0000000..3f69a17 --- /dev/null +++ b/src/BBT.StrategyPattern.Tests.ruleset @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/BBT.StrategyPattern.Tests/BBT.StrategyPattern.Tests.csproj b/src/BBT.StrategyPattern.Tests/BBT.StrategyPattern.Tests.csproj new file mode 100644 index 0000000..fe3e9e6 --- /dev/null +++ b/src/BBT.StrategyPattern.Tests/BBT.StrategyPattern.Tests.csproj @@ -0,0 +1,42 @@ + + + + netcoreapp2.1 + false + BBT.StrategyPattern.Tests + BBT Software AG + BBT.StrategyPattern + Tests for BBT.StrategyPattern + Copyright © BBT Software AG + ..\BBT.StrategyPattern.Tests.ruleset + bin\$(Configuration)\ + + + + full + + + pdbonly + + + + + + + + + all + + + + + + + + + + System + + + + diff --git a/src/BBT.StrategyPattern.Tests/Data/CalculationInput.cs b/src/BBT.StrategyPattern.Tests/Data/CalculationInput.cs new file mode 100644 index 0000000..d31de2b --- /dev/null +++ b/src/BBT.StrategyPattern.Tests/Data/CalculationInput.cs @@ -0,0 +1,12 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern.Tests.Data +{ + public class CalculationInput + { + public double Number1 { get; set; } + + public double Number2 { get; set; } + + } +} diff --git a/src/BBT.StrategyPattern.Tests/Data/Operator.cs b/src/BBT.StrategyPattern.Tests/Data/Operator.cs new file mode 100644 index 0000000..4a05439 --- /dev/null +++ b/src/BBT.StrategyPattern.Tests/Data/Operator.cs @@ -0,0 +1,9 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern.Tests.Data +{ + public class Operator + { + public OperatorEnum Operation { get; set; } + } +} diff --git a/src/BBT.StrategyPattern.Tests/Data/OperatorEnum.cs b/src/BBT.StrategyPattern.Tests/Data/OperatorEnum.cs new file mode 100644 index 0000000..0d92e36 --- /dev/null +++ b/src/BBT.StrategyPattern.Tests/Data/OperatorEnum.cs @@ -0,0 +1,11 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern.Tests.Data +{ + public enum OperatorEnum + { + None = 0, + Addition = 1, + Subtraktion = 2, + } +} diff --git a/src/BBT.StrategyPattern.Tests/ExampleStrategyImpl/AdditionStrategy.cs b/src/BBT.StrategyPattern.Tests/ExampleStrategyImpl/AdditionStrategy.cs new file mode 100644 index 0000000..62176b8 --- /dev/null +++ b/src/BBT.StrategyPattern.Tests/ExampleStrategyImpl/AdditionStrategy.cs @@ -0,0 +1,22 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern.Tests.ExampleStrategyImpl +{ + using BBT.StrategyPattern.Tests.Data; + using FluentAssertions; + + public class AdditionStrategy : IOperatorStrategy + { + public double DoCalculate(CalculationInput calc) + { + return calc.Number1 + calc.Number2; + } + + public bool IsResponsible(Operator criterion) + { + criterion.Should().NotBeNull(); + + return criterion.Operation == OperatorEnum.Addition; + } + } +} diff --git a/src/BBT.StrategyPattern.Tests/ExampleStrategyImpl/IOperatorStrategy.cs b/src/BBT.StrategyPattern.Tests/ExampleStrategyImpl/IOperatorStrategy.cs new file mode 100644 index 0000000..5707b8d --- /dev/null +++ b/src/BBT.StrategyPattern.Tests/ExampleStrategyImpl/IOperatorStrategy.cs @@ -0,0 +1,11 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern.Tests.ExampleStrategyImpl +{ + using BBT.StrategyPattern.Tests.Data; + + public interface IOperatorStrategy : IGenericStrategy + { + double DoCalculate(CalculationInput calc); + } +} diff --git a/src/BBT.StrategyPattern.Tests/ExampleStrategyImpl/SubstractionStrategy.cs b/src/BBT.StrategyPattern.Tests/ExampleStrategyImpl/SubstractionStrategy.cs new file mode 100644 index 0000000..e4103ed --- /dev/null +++ b/src/BBT.StrategyPattern.Tests/ExampleStrategyImpl/SubstractionStrategy.cs @@ -0,0 +1,22 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern.Tests.ExampleStrategyImpl +{ + using BBT.StrategyPattern.Tests.Data; + using FluentAssertions; + + public class SubstractionStrategy : IOperatorStrategy + { + public double DoCalculate(CalculationInput calc) + { + return calc.Number1 - calc.Number2; + } + + public bool IsResponsible(Operator criterion) + { + criterion.Should().NotBeNull(); + + return criterion.Operation == OperatorEnum.Subtraktion; + } + } +} diff --git a/src/BBT.StrategyPattern.Tests/WithIoc/NinjectStrategyLocator.cs b/src/BBT.StrategyPattern.Tests/WithIoc/NinjectStrategyLocator.cs new file mode 100644 index 0000000..e221e48 --- /dev/null +++ b/src/BBT.StrategyPattern.Tests/WithIoc/NinjectStrategyLocator.cs @@ -0,0 +1,23 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern.Tests.WithIoc +{ + using System; + using System.Collections.Generic; + using Ninject; + + public class NinjectStrategyLocator : IStrategyLocator + { + public NinjectStrategyLocator(IKernel kernel) + { + this.Kernel = kernel ?? throw new ArgumentNullException(nameof(kernel)); + } + + public IKernel Kernel { get; } + + public IEnumerable GetAllStrategies() + { + return Kernel.GetAll(); + } + } +} diff --git a/src/BBT.StrategyPattern.Tests/WithIocTest.cs b/src/BBT.StrategyPattern.Tests/WithIocTest.cs new file mode 100644 index 0000000..bd3cf65 --- /dev/null +++ b/src/BBT.StrategyPattern.Tests/WithIocTest.cs @@ -0,0 +1,43 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern.Tests +{ + using BBT.StrategyPattern.Tests.Data; + using BBT.StrategyPattern.Tests.ExampleStrategyImpl; + using BBT.StrategyPattern.Tests.WithIoc; + using FluentAssertions; + using Ninject; + using Xunit; + + public class WithIocTest + { + [Fact] + public void WorksWithIocNinject() + { + // Prepare data + var calc1 = new CalculationInput() { Number1 = 5, Number2 = 3 }; + var op1 = new Operator() { Operation = OperatorEnum.Addition }; + var op2 = new Operator() { Operation = OperatorEnum.Subtraktion }; + + + // IoC registrations + IKernel kernel = new StandardKernel(); + + kernel.Bind>().ToMethod((con) => new NinjectStrategyLocator(kernel)); + + kernel.Bind().To(); + kernel.Bind().To(); + + kernel.Bind>().To>(); + + // Use strategy + IOperatorStrategy strategy; + + strategy = kernel.Get>().GetStrategy(op1); + strategy.DoCalculate(calc1).Should().Be(8); + + strategy = kernel.Get>().GetStrategy(op2); + strategy.DoCalculate(calc1).Should().Be(2); + } + } +} diff --git a/src/BBT.StrategyPattern.Tests/WithoutIoc/MemoryOperatorStrategyLocator.cs b/src/BBT.StrategyPattern.Tests/WithoutIoc/MemoryOperatorStrategyLocator.cs new file mode 100644 index 0000000..d224c3e --- /dev/null +++ b/src/BBT.StrategyPattern.Tests/WithoutIoc/MemoryOperatorStrategyLocator.cs @@ -0,0 +1,19 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern.Tests.WithoutIoc +{ + using System.Collections.Generic; + using BBT.StrategyPattern.Tests.ExampleStrategyImpl; + + public class MemoryOperatorStrategyLocator : IStrategyLocator + { + public IEnumerable GetAllStrategies() + { + return new List() + { + new AdditionStrategy(), + new SubstractionStrategy(), + }; + } + } +} diff --git a/src/BBT.StrategyPattern.Tests/WithoutIocTest.cs b/src/BBT.StrategyPattern.Tests/WithoutIocTest.cs new file mode 100644 index 0000000..cdf3ef9 --- /dev/null +++ b/src/BBT.StrategyPattern.Tests/WithoutIocTest.cs @@ -0,0 +1,32 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern.Tests +{ + using BBT.StrategyPattern.Tests.Data; + using BBT.StrategyPattern.Tests.ExampleStrategyImpl; + using BBT.StrategyPattern.Tests.WithoutIoc; + using FluentAssertions; + using Xunit; + + public class WithoutIocTest + { + [Fact] + public void GenericStrategyWorksInMemory() + { + var calc1 = new CalculationInput() { Number1 = 5, Number2 = 3 }; + var op1 = new Operator() { Operation = OperatorEnum.Addition }; + var op2 = new Operator() { Operation = OperatorEnum.Subtraktion }; + + var factory = new MemoryOperatorStrategyLocator(); + var strategyProvider = new GenericStrategyProvider(factory); + + IOperatorStrategy strategy; + + strategy = strategyProvider.GetStrategy(op1); + strategy.DoCalculate(calc1).Should().Be(8); + + strategy = strategyProvider.GetStrategy(op2); + strategy.DoCalculate(calc1).Should().Be(2); + } + } +} diff --git a/src/BBT.StrategyPattern.ruleset b/src/BBT.StrategyPattern.ruleset new file mode 100644 index 0000000..a4324ea --- /dev/null +++ b/src/BBT.StrategyPattern.ruleset @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/BBT.StrategyPattern.sln b/src/BBT.StrategyPattern.sln new file mode 100644 index 0000000..6f9c470 --- /dev/null +++ b/src/BBT.StrategyPattern.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.271 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BBT.StrategyPattern", "BBT.StrategyPattern\BBT.StrategyPattern.csproj", "{2F38B821-95F8-4560-B08E-9796C44D0C86}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BBT.StrategyPattern.Tests", "BBT.StrategyPattern.Tests\BBT.StrategyPattern.Tests.csproj", "{86D8402D-88CF-4887-A9BC-5662FC23BAFE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2F38B821-95F8-4560-B08E-9796C44D0C86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2F38B821-95F8-4560-B08E-9796C44D0C86}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F38B821-95F8-4560-B08E-9796C44D0C86}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2F38B821-95F8-4560-B08E-9796C44D0C86}.Release|Any CPU.Build.0 = Release|Any CPU + {86D8402D-88CF-4887-A9BC-5662FC23BAFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86D8402D-88CF-4887-A9BC-5662FC23BAFE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86D8402D-88CF-4887-A9BC-5662FC23BAFE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86D8402D-88CF-4887-A9BC-5662FC23BAFE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9E9EFC94-8A6D-473C-BA4C-2C793E565BA6} + EndGlobalSection +EndGlobal diff --git a/src/BBT.StrategyPattern.sln.DotSettings b/src/BBT.StrategyPattern.sln.DotSettings new file mode 100644 index 0000000..7cc51a4 --- /dev/null +++ b/src/BBT.StrategyPattern.sln.DotSettings @@ -0,0 +1,3 @@ + + DO_NOT_SHOW + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> \ No newline at end of file diff --git a/src/BBT.StrategyPattern/AssemblyInfo.cs b/src/BBT.StrategyPattern/AssemblyInfo.cs new file mode 100644 index 0000000..b5249c5 --- /dev/null +++ b/src/BBT.StrategyPattern/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly: System.CLSCompliant(true)] diff --git a/src/BBT.StrategyPattern/BBT.StrategyPattern.csproj b/src/BBT.StrategyPattern/BBT.StrategyPattern.csproj new file mode 100644 index 0000000..2a607b9 --- /dev/null +++ b/src/BBT.StrategyPattern/BBT.StrategyPattern.csproj @@ -0,0 +1,39 @@ + + + + netstandard2.0 + BBT.StrategyPattern + BBT Software AG + BBT.StrategyPattern + A strategy pattern implementation for .NET + Copyright © BBT Software AG + ..\BBT.StrategyPattern.ruleset + bin\$(Configuration)\BBT.StrategyPattern.XML + bin\$(Configuration)\ + true + + + + full + + + + pdbonly + + + + + all + + + all + + + + + + <_Parameter1>$(MSBuildProjectName).Tests + + + + \ No newline at end of file diff --git a/src/BBT.StrategyPattern/GenericInstanceCreator.cs b/src/BBT.StrategyPattern/GenericInstanceCreator.cs new file mode 100644 index 0000000..d0a20d0 --- /dev/null +++ b/src/BBT.StrategyPattern/GenericInstanceCreator.cs @@ -0,0 +1,23 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern +{ + /// + /// Generic implementation of . + /// + /// Interface type which is returned. + /// Class which is instantiated. + public class GenericInstanceCreator : IInstanceCreator + where TInterface : class + where TClass : TInterface, new() + { + /// + /// See . + /// + /// A new instance of . + public TInterface Create() + { + return new TClass(); + } + } +} diff --git a/src/BBT.StrategyPattern/GenericStrategyProvider.cs b/src/BBT.StrategyPattern/GenericStrategyProvider.cs new file mode 100644 index 0000000..35b6af0 --- /dev/null +++ b/src/BBT.StrategyPattern/GenericStrategyProvider.cs @@ -0,0 +1,47 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern +{ + using System; + using System.Globalization; + using System.Linq; + + /// + /// See . + /// + /// See link above. + /// See link above. + public class GenericStrategyProvider + : IGenericStrategyProvider + where TStrategy : IGenericStrategy + { + private readonly IStrategyLocator strategyLocator; + + /// + /// Initializes a new instance of the class. + /// + /// The which can locate the strategies of which the responsible on is provided. + public GenericStrategyProvider(IStrategyLocator strategyLocator) + { + this.strategyLocator = strategyLocator ?? throw new ArgumentNullException(nameof(strategyLocator)); + } + + /// + /// See . + /// + /// See . + /// See . + public TStrategy GetStrategy(TCriterion criterion) + { + var strategies = this.strategyLocator.GetAllStrategies(); + + // If no strategies for TStrategy can be found. + if (!strategies.Any()) + { + throw new InvalidOperationException($"No strategies of {typeof(TStrategy).Name} are available from the locator."); + } + + return strategies.Single(x => x.IsResponsible(criterion)); + } + } +} \ No newline at end of file diff --git a/src/BBT.StrategyPattern/IGenericStrategy.cs b/src/BBT.StrategyPattern/IGenericStrategy.cs new file mode 100644 index 0000000..6634119 --- /dev/null +++ b/src/BBT.StrategyPattern/IGenericStrategy.cs @@ -0,0 +1,18 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern +{ + /// + /// The generic strategy for criteria . + /// + /// The type of criterium. + public interface IGenericStrategy + { + /// + /// Gets a value indicating whether this strategy is responsible for . + /// + /// The criterion () which is used to determine if this strategy is responsible. + /// True if the strategy is deemed responsible. + bool IsResponsible(T criterion); + } +} diff --git a/src/BBT.StrategyPattern/IGenericStrategyProvider.cs b/src/BBT.StrategyPattern/IGenericStrategyProvider.cs new file mode 100644 index 0000000..02270fb --- /dev/null +++ b/src/BBT.StrategyPattern/IGenericStrategyProvider.cs @@ -0,0 +1,21 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern +{ + /// + /// Generic strategy factory for criteria of type + /// and strategies of type . + /// + /// The type of strategy. + /// The type of criterium. + public interface IGenericStrategyProvider + where TStrategy : IGenericStrategy + { + /// + /// Gets the strategy corresponding to . + /// + /// Criterion for which the strategy must be responsible. + /// A strategy matching . If no or more than one strategies are found an exception is thrown. + TStrategy GetStrategy(TCriterion criterion); + } +} diff --git a/src/BBT.StrategyPattern/IInstanceCreator.cs b/src/BBT.StrategyPattern/IInstanceCreator.cs new file mode 100644 index 0000000..49206c9 --- /dev/null +++ b/src/BBT.StrategyPattern/IInstanceCreator.cs @@ -0,0 +1,20 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern +{ + /// + /// Helper interface to instantiate instances. + /// + /// The interface type. + /// The class type, must inherit from . + public interface IInstanceCreator + where TInterface : class + where TClass : TInterface, new() + { + /// + /// Creates an instance of type . + /// + /// Returns a new instance of . + TInterface Create(); + } +} diff --git a/src/BBT.StrategyPattern/IStrategyLocator.cs b/src/BBT.StrategyPattern/IStrategyLocator.cs new file mode 100644 index 0000000..15cb831 --- /dev/null +++ b/src/BBT.StrategyPattern/IStrategyLocator.cs @@ -0,0 +1,19 @@ +// Copyright © BBT Software AG. All rights reserved. + +namespace BBT.StrategyPattern +{ + using System.Collections.Generic; + + /// + /// Defines how strategies are located. + /// + /// Strategy type to locate. + public interface IStrategyLocator + { + /// + /// Returns all strategies of . + /// + /// See above. + IEnumerable GetAllStrategies(); + } +} diff --git a/tools/packages.config b/tools/packages.config new file mode 100644 index 0000000..e7f7fdd --- /dev/null +++ b/tools/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file