Skip to content

Commit a6a386a

Browse files
authored
Merge pull request #40 from solidify-project/feature/model
Feature/model
2 parents 87e9afc + 530f77c commit a6a386a

2 files changed

Lines changed: 213 additions & 40 deletions

File tree

src/SolidifyProject.Engine.Infrastructure/Models/PageModel.cs

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,14 @@ public sealed class PageModel : TextContentModel
4444

4545
public dynamic Model { get; set; }
4646

47-
public override void Parse()
47+
public PageModel()
4848
{
4949
Custom = new ExpandoObject();
5050
Model = new ExpandoObject();
51-
51+
}
52+
53+
public override void Parse()
54+
{
5255
var lines = ContentRaw.Split(END_OF_LINE, StringSplitOptions.None);
5356

5457
var attributeLines = lines
@@ -62,12 +65,18 @@ public override void Parse()
6265

6366
var contentLines = lines.SkipWhile(x => !SEPARATOR.Equals(x)).Skip(1);
6467
ParseContent(contentLines);
65-
6668
}
6769

6870
public void MapDataToModel(ExpandoObject data)
6971
{
70-
mapDataToPageModel(Model, data);
72+
if (Model is ExpandoObject)
73+
{
74+
MapDataToPageModel(Model, data);
75+
}
76+
else
77+
{
78+
Model = getValueFromDataObject(Model, data);
79+
}
7180
}
7281

7382
private void ParseAttributeLine(string line)
@@ -110,6 +119,12 @@ private void ParseAttributeLine(string line)
110119
return;
111120
}
112121

122+
if (MODEL_ATTRIBUTE_PREFIX.Any(x => x.Equals(attributeName, StringComparison.OrdinalIgnoreCase)))
123+
{
124+
Model = attributeValue;
125+
return;
126+
}
127+
113128
if (CUSTOM_ATTRIBUTE_PREFIX_SEPARATOR.Any(x => attributeName.Contains(x)))
114129
{
115130
var customAttributeNames = attributeName.Split(CUSTOM_ATTRIBUTE_PREFIX_SEPARATOR, StringSplitOptions.RemoveEmptyEntries);
@@ -134,57 +149,50 @@ private void ParseAttributeLine(string line)
134149
return;
135150
}
136151

137-
if (CUSTOM_ATTRIBUTE_PREFIX_SEPARATOR.Any(x => attributeName.Contains(x)))
138-
{
139-
var modelAttributeNames = attributeName.Split(CUSTOM_ATTRIBUTE_PREFIX_SEPARATOR, StringSplitOptions.RemoveEmptyEntries);
140-
if (modelAttributeNames.Length >= 2 && MODEL_ATTRIBUTE_PREFIX.Any(x => x.Equals(modelAttributeNames[0], StringComparison.InvariantCultureIgnoreCase)))
141-
{
142-
ParseCustomAttribute(Model, modelAttributeNames.Skip(1), attributeValue);
143-
}
144-
else
145-
{
146-
throw new ArgumentException($"Unknown name format of custom attribute \"{attributeName}\" at line \"{line}\"");
147-
}
148-
149-
return;
150-
}
151152

152153
throw new ArgumentException($"Unknown attribute \"{attributeName}\" at line \"{line}\"");
153154
}
154155

155156
private void ParseCustomAttribute(ExpandoObject obj, IEnumerable<string> attributeNames, string attributeValue)
156157
{
157-
ICollection<KeyValuePair<string, object>> node = obj;
158+
IDictionary<string, object> node = obj;
158159
var currentSection = attributeNames.First();
159-
object currentValue;
160-
160+
161161
if (attributeNames.Count() > 1)
162162
{
163-
var subNode = new ExpandoObject();
164-
currentValue = subNode;
165-
ParseCustomAttribute(subNode, attributeNames.Skip(1), attributeValue);
163+
ExpandoObject currentNode;
164+
if (node.ContainsKey(currentSection))
165+
{
166+
currentNode = node[currentSection] as ExpandoObject;
167+
}
168+
else
169+
{
170+
currentNode = new ExpandoObject();
171+
node.Add(new KeyValuePair<string, object>(currentSection, currentNode));
172+
}
173+
174+
ParseCustomAttribute(currentNode, attributeNames.Skip(1), attributeValue);
166175
}
167176
else
168177
{
169-
currentValue = attributeValue;
178+
node.Add(new KeyValuePair<string, object>(currentSection, attributeValue));
170179
}
171-
172-
node.Add(new KeyValuePair<string, object>(currentSection, currentValue));
173180
}
174181

175182
private void ParseContent(IEnumerable<string> lines)
176183
{
177184
Content = string.Join("\r\n", lines);
178185
}
179186

180-
private void mapDataToPageModel(ExpandoObject model, ExpandoObject data)
187+
private void MapDataToPageModel(ExpandoObject model, ExpandoObject data)
181188
{
182189
IDictionary<string, object> modelDict = model;
183-
foreach (var keyValuePair in model)
190+
Dictionary<string, object> objectToIterate = model.ToDictionary(k => k.Key, v => v.Value);
191+
foreach (var keyValuePair in objectToIterate)
184192
{
185193
if (keyValuePair.Value is ExpandoObject expObject)
186194
{
187-
mapDataToPageModel(expObject, data);
195+
MapDataToPageModel(expObject, data);
188196
}
189197
else
190198
{
@@ -205,7 +213,7 @@ private object getValueFromDataObject(string path, ExpandoObject data)
205213
{
206214
if (attributeNames.Length == 1)
207215
{
208-
return null;
216+
return data;
209217
}
210218

211219
attributeNames = attributeNames.Skip(1).ToArray();
@@ -214,14 +222,15 @@ private object getValueFromDataObject(string path, ExpandoObject data)
214222
object value = data;
215223
foreach (var attribute in attributeNames)
216224
{
217-
if (value is IDictionary<string,object> dict)
218-
{
219-
value = dict[attribute];
220-
}
221-
else
225+
IDictionary<string, object> dict = value as IDictionary<string, object>;
226+
227+
if (dict == null)
222228
{
223-
return null;
229+
dict = value.GetType().GetProperties()
230+
.ToDictionary(x => x.Name, x => x.GetValue(value, null));
224231
}
232+
233+
value = dict[attribute];
225234
}
226235

227236
return value;

src/Test/SolidifyProject.Engine.Test.Unit/Infrastructure/Models/PageModelTest.cs

Lines changed: 167 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using NUnit.Framework;
1+
using System.Collections.Generic;
2+
using System.Dynamic;
3+
using NUnit.Framework;
24
using SolidifyProject.Engine.Infrastructure.Models;
35

46
namespace SolidifyProject.Engine.Test.Unit.Infrastructure.Models
@@ -49,8 +51,8 @@ public void ParseCustomAttributesTest()
4951
};
5052

5153
var actualModel = new PageModel { ContentRaw = @"
52-
custom.image: logo.png
53-
custom.description: this is description
54+
Custom.image: logo.png
55+
Custom.description: this is description
5456
custom.root.SomeThing: bla-bla-bla
5557
custom.l1.l2.l3.l4: hello
5658
---
@@ -63,5 +65,167 @@ public void ParseCustomAttributesTest()
6365
Assert.AreEqual(expectedModel.Custom.root.SomeThing, actualModel.Custom.root.SomeThing);
6466
Assert.AreEqual(expectedModel.Custom.l1.l2.l3.l4, actualModel.Custom.l1.l2.l3.l4);
6567
}
68+
69+
[Test]
70+
public void ParseModelSimpleTest()
71+
{
72+
ICollection<KeyValuePair<string, object>> data = new ExpandoObject();
73+
data.Add(new KeyValuePair<string, object>("goods", new List<string>
74+
{
75+
"apple",
76+
"peach",
77+
"mango"
78+
}));
79+
data.Add(new KeyValuePair<string, object>("banner", new
80+
{
81+
url = "http://mydomain.com/banner.png"
82+
}));
83+
data.Add(new KeyValuePair<string, object>("other", new { }));
84+
85+
var actualModel = new PageModel { ContentRaw = @"
86+
Model: Data
87+
---
88+
"};
89+
90+
actualModel.Parse();
91+
actualModel.MapDataToModel((ExpandoObject)data);
92+
93+
Assert.AreEqual(((dynamic)data).goods.Count, actualModel.Model.goods.Count);
94+
Assert.AreEqual(((dynamic)data).goods[0], actualModel.Model.goods[0]);
95+
Assert.AreEqual(((dynamic)data).goods[1], actualModel.Model.goods[1]);
96+
Assert.AreEqual(((dynamic)data).goods[2], actualModel.Model.goods[2]);
97+
98+
Assert.AreEqual(((dynamic)data).banner.url, actualModel.Model.banner.url);
99+
}
100+
101+
[Test]
102+
public void ParseModelSingleItemTest()
103+
{
104+
ICollection<KeyValuePair<string, object>> data = new ExpandoObject();
105+
data.Add(new KeyValuePair<string, object>("goods", new List<string>
106+
{
107+
"apple",
108+
"peach",
109+
"mango"
110+
}));
111+
data.Add(new KeyValuePair<string, object>("banner", new
112+
{
113+
url = "http://mydomain.com/banner.png"
114+
}));
115+
data.Add(new KeyValuePair<string, object>("other", new { }));
116+
117+
var actualModel = new PageModel { ContentRaw = @"
118+
Model.goods: Data.goods
119+
---
120+
"};
121+
122+
actualModel.Parse();
123+
actualModel.MapDataToModel((ExpandoObject)data);
124+
125+
Assert.AreEqual(((dynamic)data).goods.Count, actualModel.Model.goods.Count);
126+
Assert.AreEqual(((dynamic)data).goods[0], actualModel.Model.goods[0]);
127+
Assert.AreEqual(((dynamic)data).goods[1], actualModel.Model.goods[1]);
128+
Assert.AreEqual(((dynamic)data).goods[2], actualModel.Model.goods[2]);
129+
}
130+
131+
[Test]
132+
public void ParseModelMultipleItemsTest()
133+
{
134+
ICollection<KeyValuePair<string, object>> data = new ExpandoObject();
135+
data.Add(new KeyValuePair<string, object>("goods", new List<string>
136+
{
137+
"apple",
138+
"peach",
139+
"mango"
140+
}));
141+
data.Add(new KeyValuePair<string, object>("banner", new
142+
{
143+
url = "http://mydomain.com/banner.png"
144+
}));
145+
data.Add(new KeyValuePair<string, object>("other", new { }));
146+
147+
var actualModel = new PageModel { ContentRaw = @"
148+
Model.goods: Data.goods
149+
model.bannerUrl: Data.banner.url
150+
---
151+
"};
152+
153+
actualModel.Parse();
154+
actualModel.MapDataToModel((ExpandoObject)data);
155+
156+
Assert.AreEqual(((dynamic)data).goods.Count, actualModel.Model.goods.Count);
157+
Assert.AreEqual(((dynamic)data).goods[0], actualModel.Model.goods[0]);
158+
Assert.AreEqual(((dynamic)data).goods[1], actualModel.Model.goods[1]);
159+
Assert.AreEqual(((dynamic)data).goods[2], actualModel.Model.goods[2]);
160+
Assert.AreEqual(((dynamic)data).banner.url, actualModel.Model.bannerUrl);
161+
}
162+
163+
[Test]
164+
public void ParseModelMultipleDuplicateItemsTest()
165+
{
166+
ICollection<KeyValuePair<string, object>> data = new ExpandoObject();
167+
data.Add(new KeyValuePair<string, object>("goods", new List<string>
168+
{
169+
"apple",
170+
"peach",
171+
"mango"
172+
}));
173+
data.Add(new KeyValuePair<string, object>("banner", new
174+
{
175+
url = "http://mydomain.com/banner.png"
176+
}));
177+
data.Add(new KeyValuePair<string, object>("other", new { }));
178+
179+
var actualModel = new PageModel { ContentRaw = @"
180+
Model.goods1: Data.goods
181+
model.goods2: Data.goods
182+
---
183+
"};
184+
185+
actualModel.Parse();
186+
actualModel.MapDataToModel((ExpandoObject)data);
187+
188+
Assert.AreEqual(((dynamic)data).goods.Count, actualModel.Model.goods1.Count);
189+
Assert.AreEqual(((dynamic)data).goods[0], actualModel.Model.goods1[0]);
190+
Assert.AreEqual(((dynamic)data).goods[1], actualModel.Model.goods1[1]);
191+
Assert.AreEqual(((dynamic)data).goods[2], actualModel.Model.goods1[2]);
192+
193+
Assert.AreEqual(((dynamic)data).goods.Count, actualModel.Model.goods2.Count);
194+
Assert.AreEqual(((dynamic)data).goods[0], actualModel.Model.goods2[0]);
195+
Assert.AreEqual(((dynamic)data).goods[1], actualModel.Model.goods2[1]);
196+
Assert.AreEqual(((dynamic)data).goods[2], actualModel.Model.goods2[2]);
197+
}
198+
199+
[Test]
200+
public void ParseModelComplexMultipleItemsTest()
201+
{
202+
ICollection<KeyValuePair<string, object>> data = new ExpandoObject();
203+
data.Add(new KeyValuePair<string, object>("goods", new List<string>
204+
{
205+
"apple",
206+
"peach",
207+
"mango"
208+
}));
209+
data.Add(new KeyValuePair<string, object>("banner", new
210+
{
211+
url = "http://mydomain.com/banner.png"
212+
}));
213+
data.Add(new KeyValuePair<string, object>("other", new { }));
214+
215+
var actualModel = new PageModel { ContentRaw = @"
216+
Model.category.goods: Data.goods
217+
model.bannerUrl: Data.banner.url
218+
---
219+
"};
220+
221+
actualModel.Parse();
222+
actualModel.MapDataToModel((ExpandoObject)data);
223+
224+
Assert.AreEqual(((dynamic)data).goods.Count, actualModel.Model.category.goods.Count);
225+
Assert.AreEqual(((dynamic)data).goods[0], actualModel.Model.category.goods[0]);
226+
Assert.AreEqual(((dynamic)data).goods[1], actualModel.Model.category.goods[1]);
227+
Assert.AreEqual(((dynamic)data).goods[2], actualModel.Model.category.goods[2]);
228+
Assert.AreEqual(((dynamic)data).banner.url, actualModel.Model.bannerUrl);
229+
}
66230
}
67231
}

0 commit comments

Comments
 (0)