Skip to content

Commit e9e0df5

Browse files
[FSSDK-11544] experiment core and holdout introduction
1 parent c6548a8 commit e9e0df5

File tree

8 files changed

+551
-0
lines changed

8 files changed

+551
-0
lines changed

OptimizelySDK.Net35/OptimizelySDK.Net35.csproj

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@
8888
<Compile Include="..\OptimizelySDK\Entity\Experiment.cs">
8989
<Link>Entity\Experiment.cs</Link>
9090
</Compile>
91+
<Compile Include="..\OptimizelySDK\Entity\ExperimentCoreExtensions.cs">
92+
<Link>Entity\ExperimentCoreExtensions.cs</Link>
93+
</Compile>
94+
<Compile Include="..\OptimizelySDK\Entity\Holdout.cs">
95+
<Link>Entity\Holdout.cs</Link>
96+
</Compile>
97+
<Compile Include="..\OptimizelySDK\Entity\IExperimentCore.cs">
98+
<Link>Entity\IExperimentCore.cs</Link>
99+
</Compile>
91100
<Compile Include="..\OptimizelySDK\Entity\FeatureDecision.cs">
92101
<Link>Entity\FeatureDecision.cs</Link>
93102
</Compile>

OptimizelySDK.Net40/OptimizelySDK.Net40.csproj

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@
9090
<Compile Include="..\OptimizelySDK\Entity\Experiment.cs">
9191
<Link>Entity\Experiment.cs</Link>
9292
</Compile>
93+
<Compile Include="..\OptimizelySDK\Entity\ExperimentCoreExtensions.cs">
94+
<Link>Entity\ExperimentCoreExtensions.cs</Link>
95+
</Compile>
96+
<Compile Include="..\OptimizelySDK\Entity\Holdout.cs">
97+
<Link>Entity\Holdout.cs</Link>
98+
</Compile>
99+
<Compile Include="..\OptimizelySDK\Entity\IExperimentCore.cs">
100+
<Link>Entity\IExperimentCore.cs</Link>
101+
</Compile>
93102
<Compile Include="..\OptimizelySDK\Entity\FeatureDecision.cs">
94103
<Link>Entity\FeatureDecision.cs</Link>
95104
</Compile>

OptimizelySDK.NetStandard16/OptimizelySDK.NetStandard16.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
<Compile Include="..\OptimizelySDK\Entity\Event.cs" />
2727
<Compile Include="..\OptimizelySDK\Entity\EventTags.cs" />
2828
<Compile Include="..\OptimizelySDK\Entity\Experiment.cs" />
29+
<Compile Include="..\OptimizelySDK\Entity\ExperimentCoreExtensions.cs" />
30+
<Compile Include="..\OptimizelySDK\Entity\Holdout.cs" />
31+
<Compile Include="..\OptimizelySDK\Entity\IExperimentCore.cs" />
2932
<Compile Include="..\OptimizelySDK\Entity\FeatureDecision.cs" />
3033
<Compile Include="..\OptimizelySDK\Entity\ForcedVariation.cs" />
3134
<Compile Include="..\OptimizelySDK\Entity\Group.cs" />

OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,15 @@
178178
<Compile Include="..\OptimizelySDK\Entity\Experiment.cs">
179179
<Link>Entity\Experiment.cs</Link>
180180
</Compile>
181+
<Compile Include="..\OptimizelySDK\Entity\ExperimentCoreExtensions.cs">
182+
<Link>Entity\ExperimentCoreExtensions.cs</Link>
183+
</Compile>
184+
<Compile Include="..\OptimizelySDK\Entity\Holdout.cs">
185+
<Link>Entity\Holdout.cs</Link>
186+
</Compile>
187+
<Compile Include="..\OptimizelySDK\Entity\IExperimentCore.cs">
188+
<Link>Entity\IExperimentCore.cs</Link>
189+
</Compile>
181190
<Compile Include="..\OptimizelySDK\Entity\FeatureDecision.cs">
182191
<Link>Entity\FeatureDecision.cs</Link>
183192
</Compile>
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright 2017-2019, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
using System.Linq;
18+
19+
namespace OptimizelySDK.Entity
20+
{
21+
/// <summary>
22+
/// Extension methods providing common functionality for IExperimentCore implementations
23+
/// </summary>
24+
public static class ExperimentCoreExtensions
25+
{
26+
/// <summary>
27+
/// Get variation by ID
28+
/// </summary>
29+
/// <param name="experimentCore">The experiment or holdout instance</param>
30+
/// <param name="id">Variation ID to search for</param>
31+
/// <returns>Variation with the specified ID, or null if not found</returns>
32+
public static Variation GetVariation(this IExperimentCore experimentCore, string id)
33+
{
34+
if (experimentCore?.Variations == null || string.IsNullOrEmpty(id))
35+
{
36+
return null;
37+
}
38+
39+
return experimentCore.Variations.FirstOrDefault(v => v.Id == id);
40+
}
41+
42+
/// <summary>
43+
/// Get variation by key
44+
/// </summary>
45+
/// <param name="experimentCore">The experiment or holdout instance</param>
46+
/// <param name="key">Variation key to search for</param>
47+
/// <returns>Variation with the specified key, or null if not found</returns>
48+
public static Variation GetVariationByKey(this IExperimentCore experimentCore, string key)
49+
{
50+
if (experimentCore?.Variations == null || string.IsNullOrEmpty(key))
51+
{
52+
return null;
53+
}
54+
55+
return experimentCore.Variations.FirstOrDefault(v => v.Key == key);
56+
}
57+
58+
/// <summary>
59+
/// Replace audience IDs with audience names in a condition string
60+
/// </summary>
61+
/// <param name="experimentCore">The experiment or holdout instance</param>
62+
/// <param name="conditionString">String containing audience conditions</param>
63+
/// <param name="audiencesMap">Map of audience ID to audience name</param>
64+
/// <returns>String with audience IDs replaced by names</returns>
65+
public static string ReplaceAudienceIdsWithNames(this IExperimentCore experimentCore,
66+
string conditionString, System.Collections.Generic.Dictionary<string, string> audiencesMap)
67+
{
68+
if (string.IsNullOrEmpty(conditionString) || audiencesMap == null)
69+
{
70+
return conditionString ?? string.Empty;
71+
}
72+
73+
const string beginWord = "AUDIENCE(";
74+
const string endWord = ")";
75+
var keyIdx = 0;
76+
var audienceId = string.Empty;
77+
var collect = false;
78+
var replaced = string.Empty;
79+
80+
foreach (var ch in conditionString)
81+
{
82+
// Extract audience id in parenthesis (example: AUDIENCE("35") => "35")
83+
if (collect)
84+
{
85+
if (ch.ToString() == endWord)
86+
{
87+
// Output the extracted audienceId
88+
var audienceName = audiencesMap.ContainsKey(audienceId) ? audiencesMap[audienceId] : audienceId;
89+
replaced += $"\"{audienceName}\"";
90+
collect = false;
91+
audienceId = string.Empty;
92+
}
93+
else
94+
{
95+
audienceId += ch;
96+
}
97+
continue;
98+
}
99+
100+
// Walk-through until finding a matching keyword "AUDIENCE("
101+
if (ch == beginWord[keyIdx])
102+
{
103+
keyIdx++;
104+
if (keyIdx == beginWord.Length)
105+
{
106+
keyIdx = 0;
107+
collect = true;
108+
}
109+
continue;
110+
}
111+
else
112+
{
113+
if (keyIdx > 0)
114+
{
115+
replaced += beginWord.Substring(0, keyIdx);
116+
}
117+
keyIdx = 0;
118+
}
119+
120+
// Pass through other characters
121+
replaced += ch;
122+
}
123+
124+
return replaced;
125+
}
126+
}
127+
}

0 commit comments

Comments
 (0)