-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add LoadUtils, with the abstracted parenting code.
- Loading branch information
Showing
5 changed files
with
259 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
using System.Collections.Generic; | ||
using DarkConfig; | ||
using System; | ||
|
||
namespace DarkConfig { | ||
public class LoadUtils { | ||
public static void SetParentDefaults<K, V>( | ||
ref Dictionary<K, V> container, | ||
DocNode doc, | ||
Func<V, K> getBasedOn, | ||
string[] unparentableFieldNames = null) { | ||
// clear existing values before the reify; because later we bake them | ||
var fields = typeof(V).GetFields(); | ||
if(container != null) { | ||
foreach(var kv in container) { | ||
foreach(var field in fields) { | ||
field.SetValue(kv.Value, GetDefault(field.FieldType)); | ||
} | ||
} | ||
} | ||
|
||
Config.Reify(ref container, doc); | ||
|
||
var parentRelationships = new Dictionary<V, V>(); | ||
|
||
// hook up parent references | ||
foreach (var kv in container) { | ||
var val = kv.Value; | ||
var basedOn = getBasedOn(val); | ||
if(basedOn == null) continue; | ||
if (!container.ContainsKey(basedOn)) { | ||
Config.Log(LogVerbosity.Error, | ||
string.Format("In file {0}, {1} is based on {2}, which doesn't exist", | ||
doc.SourceInformation, val, basedOn)); | ||
continue; | ||
} | ||
|
||
parentRelationships[val] = container[basedOn]; | ||
} | ||
|
||
// set fields from the parents | ||
foreach (var kv in container) { | ||
var val = kv.Value; | ||
foreach (var field in fields) { | ||
if (field.IsSpecialName) continue; | ||
if(unparentableFieldNames != null) { | ||
bool shouldNotParentThisField = false; | ||
for(int i = 0; i < unparentableFieldNames.Length; i++) { | ||
if(field.Name == unparentableFieldNames[i]) { | ||
shouldNotParentThisField = true; | ||
break; | ||
} | ||
} | ||
if(shouldNotParentThisField) continue; | ||
} | ||
|
||
var fieldValue = GetParentedFieldValue(field, val, parentRelationships, 0); | ||
field.SetValue(val, fieldValue); | ||
} | ||
} | ||
} | ||
|
||
static object GetParentedFieldValue<V>( | ||
System.Reflection.FieldInfo field, | ||
V conf, | ||
Dictionary<V, V> parentRelationships, | ||
int recursionDepth) { | ||
|
||
var fieldValue = field.GetValue(conf); | ||
V parent; | ||
if(!parentRelationships.TryGetValue(conf, out parent)) return fieldValue; | ||
if(parent == null) return fieldValue; | ||
if (recursionDepth > 100) { | ||
Config.Log(LogVerbosity.Error, | ||
string.Format("Might be a loop in the basedOn references at: {0}, parent {1}", conf, parent)); | ||
return fieldValue; | ||
} | ||
if (fieldValue == null) { | ||
// need to get the default from the parent | ||
return GetParentedFieldValue(field, parent, parentRelationships, recursionDepth + 1); | ||
} else { | ||
return fieldValue; | ||
} | ||
} | ||
|
||
static object GetDefault(System.Type type) { | ||
if(type.IsValueType) return System.Activator.CreateInstance(type); | ||
return null; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
using System.Collections.Generic; | ||
using DarkConfig; | ||
using NUnit.Framework; | ||
|
||
[TestFixture] | ||
class LoadUtilsFacts { | ||
class TestClass { | ||
public int? intKey = null; | ||
public string stringKey = null; | ||
|
||
public string basedOn = null; | ||
|
||
public static string getBasedOn(TestClass c) { | ||
return c.basedOn; | ||
} | ||
} | ||
|
||
const string c_filename = "LoadUtilsFacts_TestFileName"; | ||
|
||
DocNode FromString(string s) { | ||
return Config.LoadDocFromString(s, c_filename); | ||
} | ||
|
||
[Test] | ||
public void LoadUtils_SetParentDefaults_LoadSimple() { | ||
var doc = FromString(@" | ||
basic: | ||
intKey: 1 | ||
stringKey: 2 | ||
"); | ||
|
||
Dictionary<string, TestClass> d = null; | ||
LoadUtils.SetParentDefaults(ref d, doc, TestClass.getBasedOn); | ||
Assert.AreEqual(1, d.Count); | ||
Assert.AreEqual(1, d["basic"].intKey.Value); | ||
Assert.AreEqual("2", d["basic"].stringKey); | ||
} | ||
|
||
[Test] | ||
public void LoadUtils_SetParentDefaults_LoadParented() { | ||
var doc = FromString(@" | ||
default: | ||
intKey: 0 | ||
stringKey: a | ||
basic: | ||
basedOn: default | ||
intKey: 1 | ||
"); | ||
|
||
Dictionary<string, TestClass> d = null; | ||
LoadUtils.SetParentDefaults(ref d, doc, TestClass.getBasedOn); | ||
Assert.AreEqual(2, d.Count); | ||
Assert.AreEqual(1, d["basic"].intKey.Value); | ||
Assert.AreEqual("a", d["basic"].stringKey); | ||
} | ||
|
||
[Test] | ||
public void LoadUtils_SetParentDefaults_LoadParentedRecursive() { | ||
var doc = FromString(@" | ||
default: | ||
intKey: 0 | ||
stringKey: a | ||
basic: | ||
basedOn: default | ||
intKey: 1 | ||
deeper: | ||
basedOn: basic | ||
intKey: 2 | ||
"); | ||
|
||
Dictionary<string, TestClass> d = null; | ||
LoadUtils.SetParentDefaults(ref d, doc, TestClass.getBasedOn); | ||
Assert.AreEqual(3, d.Count); | ||
Assert.AreEqual(2, d["deeper"].intKey.Value); | ||
Assert.AreEqual("a", d["deeper"].stringKey); | ||
} | ||
|
||
|
||
[Test] | ||
public void LoadUtils_SetParentDefaults_LoadNullableRecursive() { | ||
var doc = FromString(@" | ||
default: | ||
intKey: 0 | ||
stringKey: a | ||
basic: | ||
basedOn: default | ||
stringKey: basicString | ||
deeper: | ||
basedOn: basic | ||
stringKey: deeperString | ||
"); | ||
|
||
Dictionary<string, TestClass> d = null; | ||
LoadUtils.SetParentDefaults(ref d, doc, TestClass.getBasedOn); | ||
Assert.AreEqual(3, d.Count); | ||
Assert.AreEqual(0, d["deeper"].intKey.Value); | ||
Assert.AreEqual("deeperString", d["deeper"].stringKey); | ||
} | ||
|
||
[Test] | ||
public void LoadUtils_SetParentDefaults_LoadParentedTwice() { | ||
var doc = FromString(@" | ||
default: | ||
intKey: 0 | ||
stringKey: a | ||
basic: | ||
basedOn: default | ||
intKey: 1 | ||
"); | ||
|
||
Dictionary<string, TestClass> d = null; | ||
LoadUtils.SetParentDefaults(ref d, doc, TestClass.getBasedOn); | ||
var doc2 = FromString(@" | ||
default: | ||
intKey: 1 | ||
stringKey: b | ||
basic: | ||
basedOn: default | ||
"); | ||
LoadUtils.SetParentDefaults(ref d, doc2, TestClass.getBasedOn); | ||
Assert.AreEqual(2, d.Count); | ||
Assert.AreEqual(1, d["basic"].intKey.Value); | ||
Assert.AreEqual("b", d["basic"].stringKey); | ||
} | ||
|
||
|
||
[Test] | ||
public void LoadUtils_SetParentDefaults_IgnoreFields() { | ||
var doc = FromString(@" | ||
default: | ||
intKey: 0 | ||
stringKey: a | ||
basic: | ||
basedOn: default | ||
"); | ||
|
||
Dictionary<string, TestClass> d = null; | ||
LoadUtils.SetParentDefaults(ref d, doc, TestClass.getBasedOn, | ||
new string[] {"basedOn", "intKey"}); | ||
Assert.AreEqual(null, d["basic"].intKey); | ||
Assert.AreEqual("a", d["basic"].stringKey); | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters