Kaynağa Gözat

Added PropertyTableAssigner.

Marco Mastropaolo 10 yıl önce
ebeveyn
işleme
41aaeefd2b

+ 87 - 0
src/MoonSharp.Interpreter.Tests/EndToEnd/ConfigPropertyAssignerTests.cs

@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using MoonSharp.Interpreter.Interop;
+using NUnit.Framework;
+
+namespace MoonSharp.Interpreter.Tests.EndToEnd
+{
+	[TestFixture]
+	public class ConfigPropertyAssignerTests
+	{
+		private class MyClass
+		{
+			[MoonSharpProperty]
+			public string MyString { get; set; }
+
+			[MoonSharpProperty("number")]
+			public int MyNumber { get; private set; }
+
+			[MoonSharpProperty]
+			internal Table SomeTable { get; private set; }
+
+			[MoonSharpProperty]
+			public DynValue NativeValue { get; private set; }
+		}
+
+		private MyClass Test(string tableDef)
+		{
+			Script s = new Script(CoreModules.None);
+
+			DynValue table = s.DoString("return " + tableDef);
+
+			Assert.AreEqual(DataType.Table, table.Type);
+
+			PropertyTableAssigner<MyClass> pta = new PropertyTableAssigner<MyClass>("class");
+
+			MyClass o = new MyClass();
+
+			pta.AssignObject(o, table.Table);
+
+			return o;
+		}
+
+		[Test]
+		public void ConfigProp_SimpleAssign()
+		{
+			MyClass x = Test(@"
+				{
+				class = 'oohoh',
+				myString = 'ciao',
+				number = 3,
+				some_table = {},
+				nativeValue = function() end,
+				}");
+
+			Assert.AreEqual(x.MyNumber, 3);
+			Assert.AreEqual(x.MyString, "ciao");
+			Assert.AreEqual(x.NativeValue.Type, DataType.Function);
+			Assert.IsNotNull(x.SomeTable);
+
+		}
+
+
+		[Test]
+		[ExpectedException(typeof(ScriptRuntimeException))]
+		public void ConfigProp_ThrowsOnInvalid()
+		{
+			MyClass x = Test(@"
+				{
+				class = 'oohoh',
+				myString = 'ciao',
+				number = 3,
+				some_table = {},
+				invalid = 3,
+				nativeValue = function() end,
+				}");
+
+			Assert.AreEqual(x.MyNumber, 3);
+			Assert.AreEqual(x.MyString, "ciao");
+			Assert.AreEqual(x.NativeValue.Type, DataType.Function);
+			Assert.IsNotNull(x.SomeTable);
+
+		}
+
+	}
+}

+ 1 - 0
src/MoonSharp.Interpreter.Tests/MoonSharp.Interpreter.Tests.net35-client.csproj

@@ -119,6 +119,7 @@
     <Compile Include="EndToEnd\CollectionsBaseInterfGenRegisteredTests.cs" />
     <Compile Include="EndToEnd\CollectionsBaseGenRegisteredTests.cs" />
     <Compile Include="EndToEnd\CollectionsRegisteredTests.cs" />
+    <Compile Include="EndToEnd\ConfigPropertyAssignerTests.cs" />
     <Compile Include="EndToEnd\CoroutineTests.cs" />
     <Compile Include="EndToEnd\DynamicTests.cs" />
     <Compile Include="EndToEnd\ErrorHandlingTests.cs" />

+ 3 - 0
src/MoonSharp.Interpreter.Tests/_Projects/MoonSharp.Interpreter.Tests.Embeddable.portable40/MoonSharp.Interpreter.Tests.Embeddable.portable40.csproj

@@ -76,6 +76,9 @@
     <Compile Include="..\..\EndToEnd\CollectionsRegisteredTests.cs">
       <Link>CollectionsRegisteredTests.cs</Link>
     </Compile>
+    <Compile Include="..\..\EndToEnd\ConfigPropertyAssignerTests.cs">
+      <Link>ConfigPropertyAssignerTests.cs</Link>
+    </Compile>
     <Compile Include="..\..\EndToEnd\CoroutineTests.cs">
       <Link>CoroutineTests.cs</Link>
     </Compile>

+ 3 - 0
src/MoonSharp.Interpreter.Tests/_Projects/MoonSharp.Interpreter.Tests.net40-client/MoonSharp.Interpreter.Tests.net40-client.csproj

@@ -92,6 +92,9 @@
     <Compile Include="..\..\EndToEnd\CollectionsRegisteredTests.cs">
       <Link>CollectionsRegisteredTests.cs</Link>
     </Compile>
+    <Compile Include="..\..\EndToEnd\ConfigPropertyAssignerTests.cs">
+      <Link>ConfigPropertyAssignerTests.cs</Link>
+    </Compile>
     <Compile Include="..\..\EndToEnd\CoroutineTests.cs">
       <Link>CoroutineTests.cs</Link>
     </Compile>

+ 3 - 0
src/MoonSharp.Interpreter.Tests/_Projects/MoonSharp.Interpreter.Tests.portable40/MoonSharp.Interpreter.Tests.portable40.csproj

@@ -92,6 +92,9 @@
     <Compile Include="..\..\EndToEnd\CollectionsRegisteredTests.cs">
       <Link>CollectionsRegisteredTests.cs</Link>
     </Compile>
+    <Compile Include="..\..\EndToEnd\ConfigPropertyAssignerTests.cs">
+      <Link>ConfigPropertyAssignerTests.cs</Link>
+    </Compile>
     <Compile Include="..\..\EndToEnd\CoroutineTests.cs">
       <Link>CoroutineTests.cs</Link>
     </Compile>

+ 39 - 0
src/MoonSharp.Interpreter/Interop/Attributes/MoonSharpPropertyAttribute.cs

@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter
+{
+
+	/// <summary>
+	/// Marks a property as a configruation property
+	/// </summary>
+	[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = true)]
+	public sealed class MoonSharpPropertyAttribute : Attribute
+	{
+		/// <summary>
+		/// The metamethod name (like '__div', '__ipairs', etc.)
+		/// </summary>
+		public string Name { get; private set; }
+
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="MoonSharpPropertyAttribute"/> class.
+		/// </summary>
+		public MoonSharpPropertyAttribute()
+		{
+
+		}
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="MoonSharpPropertyAttribute"/> class.
+		/// </summary>
+		/// <param name="name">The name for this property</param>
+		public MoonSharpPropertyAttribute(string name)
+		{
+			Name = name;
+		}
+	}
+
+}

+ 5 - 26
src/MoonSharp.Interpreter/Interop/BasicDescriptors/DispatchingUserDataDescriptor.cs

@@ -385,45 +385,24 @@ namespace MoonSharp.Interpreter.Interop.BasicDescriptors
 
 		/// <summary>
 		/// Converts the specified name from underscore_case to camelCase.
-		/// </summary>
+		/// Just a wrapper over the <see cref="DescriptorHelpers"/> method with the same name,
+ 		/// </summary>
 		/// <param name="name">The name.</param>
 		/// <returns></returns>
 		protected static string Camelify(string name)
 		{
-			StringBuilder sb = new StringBuilder(name.Length);
-
-			bool lastWasUnderscore = false;
-			for (int i = 0; i < name.Length; i++)
-			{
-				if (name[i] == '_' && i != 0)
-				{
-					lastWasUnderscore = true;
-				}
-				else
-				{
-					if (lastWasUnderscore)
-						sb.Append(char.ToUpperInvariant(name[i]));
-					else
-						sb.Append(name[i]);
-
-					lastWasUnderscore = false;
-				}
-			}
-
-			return sb.ToString();
+			return DescriptorHelpers.Camelify(name);
 		}
 
 		/// <summary>
 		/// Converts the specified name to one with an uppercase first letter (something to Something).
+		/// Just a wrapper over the <see cref="DescriptorHelpers"/> method with the same name,
 		/// </summary>
 		/// <param name="name">The name.</param>
 		/// <returns></returns>
 		protected static string UpperFirstLetter(string name)
 		{
-			if (!string.IsNullOrEmpty(name))
-				return char.ToUpperInvariant(name[0]) + name.Substring(1);
-
-			return name;
+			return DescriptorHelpers.UpperFirstLetter(name);
 		}
 
 		/// <summary>

+ 46 - 0
src/MoonSharp.Interpreter/Interop/DescriptorHelpers.cs

@@ -114,5 +114,51 @@ namespace MoonSharp.Interpreter.Interop
 		}
 
 
+		/// <summary>
+		/// Converts the specified name from underscore_case to camelCase.
+		/// </summary>
+		/// <param name="name">The name.</param>
+		/// <returns></returns>
+		public static string Camelify(string name)
+		{
+			StringBuilder sb = new StringBuilder(name.Length);
+
+			bool lastWasUnderscore = false;
+			for (int i = 0; i < name.Length; i++)
+			{
+				if (name[i] == '_' && i != 0)
+				{
+					lastWasUnderscore = true;
+				}
+				else
+				{
+					if (lastWasUnderscore)
+						sb.Append(char.ToUpperInvariant(name[i]));
+					else
+						sb.Append(name[i]);
+
+					lastWasUnderscore = false;
+				}
+			}
+
+			return sb.ToString();
+		}
+
+		/// <summary>
+		/// Converts the specified name to one with an uppercase first letter (something to Something).
+		/// </summary>
+		/// <param name="name">The name.</param>
+		/// <returns></returns>
+		public static string UpperFirstLetter(string name)
+		{
+			if (!string.IsNullOrEmpty(name))
+				return char.ToUpperInvariant(name[0]) + name.Substring(1);
+
+			return name;
+		}
+
+
+
+
 	}
 }

+ 176 - 0
src/MoonSharp.Interpreter/Interop/PropertyTableAssigner.cs

@@ -0,0 +1,176 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Interop
+{
+	/// <summary>
+	/// Utility class which may be used to set properties on an object of type T, from values contained in a Lua table.
+	/// Properties must be decorated with the <see cref="MoonSharpPropertyAttribute"/>.
+	/// This is a generic version of <see cref="PropertyTableAssigner"/>.
+	/// </summary>
+	/// <typeparam name="T">The type of the object.</typeparam>
+	public class PropertyTableAssigner<T>
+	{
+		PropertyTableAssigner m_InternalAssigner;
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="PropertyTableAssigner{T}"/> class.
+		/// </summary>
+		/// <param name="expectedMissingProperties">The expected missing properties, that is expected fields in the table with no corresponding property in the object.</param>
+		public PropertyTableAssigner(params string[] expectedMissingProperties)
+		{
+			m_InternalAssigner = new PropertyTableAssigner(typeof(T), expectedMissingProperties);
+		}
+
+		/// <summary>
+		/// Adds an expected missing property, that is an expected field in the table with no corresponding property in the object.
+		/// </summary>
+		/// <param name="name">The name.</param>
+		public void AddExpectedMissingProperty(string name)
+		{
+			m_InternalAssigner.AddExpectedMissingProperty(name);
+		}
+
+		/// <summary>
+		/// Assigns properties from tables to an object.
+		/// </summary>
+		/// <param name="obj">The object.</param>
+		/// <param name="data">The table.</param>
+		/// <exception cref="System.ArgumentNullException">Object is null</exception>
+		/// <exception cref="ScriptRuntimeException">A field does not correspond to any property and that property is not one of the expected missing ones.</exception>
+		public void AssignObject(T obj, Table data)
+		{
+			m_InternalAssigner.AssignObject(obj, data);
+		}
+
+		/// <summary>
+		/// Gets the type-unsafe assigner corresponding to this object.
+		/// </summary>
+		/// <returns></returns>
+		public PropertyTableAssigner GetTypeUnsafeAssigner()
+		{
+			return m_InternalAssigner;
+		}
+	}
+
+
+	/// <summary>
+	/// Utility class which may be used to set properties on an object from values contained in a Lua table.
+	/// Properties must be decorated with the <see cref="MoonSharpPropertyAttribute"/>.
+	/// See <see cref="PropertyTableAssigner{T}"/> for a generic compile time type-safe version.
+	/// </summary>
+	public class PropertyTableAssigner 
+	{
+		Type m_Type;
+		Dictionary<string, PropertyInfo> m_PropertyMap = new Dictionary<string, PropertyInfo>();
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="PropertyTableAssigner"/> class.
+		/// </summary>
+		/// <param name="type">The type of the object.</param>
+		/// <param name="expectedMissingProperties">The expected missing properties, that is expected fields in the table with no corresponding property in the object.</param>
+		/// <exception cref="System.ArgumentException">
+		/// Type cannot be a value type.
+		/// </exception>
+		public PropertyTableAssigner(Type type, params string[] expectedMissingProperties)
+		{
+			m_Type = type;
+
+			if (m_Type.IsValueType)
+				throw new ArgumentException("Type cannot be a value type.");
+
+			foreach(string property in expectedMissingProperties)
+			{
+				m_PropertyMap.Add(property, null);
+			}
+
+			foreach (PropertyInfo pi in m_Type.GetProperties(BindingFlags.Instance|BindingFlags.Static|BindingFlags.NonPublic|BindingFlags.Public))
+			{
+				foreach (MoonSharpPropertyAttribute attr in pi.GetCustomAttributes(true).OfType<MoonSharpPropertyAttribute>())
+				{
+					string name = attr.Name ?? pi.Name;
+
+					if (m_PropertyMap.ContainsKey(name))
+					{
+						throw new ArgumentException(string.Format("Type {0} has two definitions for MoonSharp property {1}", m_Type.FullName, name));
+					}
+					else
+					{
+						m_PropertyMap.Add(name, pi);
+					}
+				}
+			}
+
+		}
+
+		/// <summary>
+		/// Adds an expected missing property, that is an expected field in the table with no corresponding property in the object.
+		/// </summary>
+		/// <param name="name">The name.</param>
+		public void AddExpectedMissingProperty(string name)
+		{
+			m_PropertyMap.Add(name, null);
+		}
+
+
+		private bool TryAssignProperty(object obj, string name, DynValue value)
+		{
+			if (m_PropertyMap.ContainsKey(name))
+			{
+				PropertyInfo pi = m_PropertyMap[name];
+
+				if (pi != null)
+				{
+					object o = Interop.Converters.ScriptToClrConversions.DynValueToObjectOfType(value,
+						pi.PropertyType, null, false);
+
+					pi.GetSetMethod(true).Invoke(obj, new object[] { o });
+				}
+
+				return true;
+			}
+
+			return false;
+		}
+
+		private void AssignProperty(object obj, string name, DynValue value)
+		{
+			if (TryAssignProperty(obj, name, value)) return;
+			if (TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(name), value)) return;
+			if (TryAssignProperty(obj, DescriptorHelpers.Camelify(name), value)) return;
+			if (TryAssignProperty(obj, DescriptorHelpers.UpperFirstLetter(DescriptorHelpers.Camelify(name)), value)) return;
+
+			throw new ScriptRuntimeException("Invalid property {0}", name);
+		}
+
+		/// <summary>
+		/// Assigns properties from tables to an object.
+		/// </summary>
+		/// <param name="obj">The object.</param>
+		/// <param name="data">The table.</param>
+		/// <exception cref="System.ArgumentNullException">Object is null</exception>
+		/// <exception cref="System.ArgumentException">The object is of an incompatible type.</exception>
+		/// <exception cref="ScriptRuntimeException">A field does not correspond to any property and that property is not one of the expected missing ones.</exception>
+		public void AssignObject(object obj, Table data)
+		{
+			if (obj == null)
+				throw new ArgumentNullException("Object is null");
+
+			if (!m_Type.IsInstanceOfType(obj))
+				throw new ArgumentException(string.Format("Invalid type of object : got '{0}', expected {1}", obj.GetType().FullName, m_Type.FullName));
+
+			foreach (var pair in data.Pairs)
+			{
+				if (pair.Key.Type != DataType.String)
+				{
+					throw new ScriptRuntimeException("Invalid property of type {0}", pair.Key.Type.ToErrorTypeString());
+				}
+
+				AssignProperty(obj, pair.Key.String, pair.Value);
+			}
+		}
+	}
+}

+ 2 - 0
src/MoonSharp.Interpreter/MoonSharp.Interpreter.net35-client.csproj

@@ -137,6 +137,7 @@
     <Compile Include="CoreLib\StringLib\KopiLua_StrLib.cs" />
     <Compile Include="DataStructs\MultiDictionary.cs" />
     <Compile Include="DataStructs\ReferenceEqualityComparer.cs" />
+    <Compile Include="Interop\Attributes\MoonSharpPropertyAttribute.cs" />
     <Compile Include="Interop\Attributes\MoonSharpUserDataMetamethodAttribute.cs" />
     <Compile Include="Interop\BasicDescriptors\IMemberDescriptor.cs" />
     <Compile Include="Interop\BasicDescriptors\IOptimizableDescriptor.cs" />
@@ -152,6 +153,7 @@
     <Compile Include="Interop\DescriptorHelpers.cs" />
     <Compile Include="Interop\BasicDescriptors\DispatchingUserDataDescriptor.cs" />
     <Compile Include="Interop\IGeneratorUserDataDescriptor.cs" />
+    <Compile Include="Interop\PropertyTableAssigner.cs" />
     <Compile Include="Interop\StandardDescriptors\EnumDescriptor.cs" />
     <Compile Include="Interop\StandardDescriptors\MemberDescriptors\ObjectCallbackMemberDescriptor.cs" />
     <Compile Include="Interop\StandardDescriptors\MemberDescriptors\FunctionMemberDescriptorBase.cs" />

+ 1 - 1
src/MoonSharp.Interpreter/Script.cs

@@ -28,7 +28,7 @@ namespace MoonSharp.Interpreter
 		/// <summary>
 		/// The version of the MoonSharp engine
 		/// </summary>
-		public const string VERSION = "0.9.8.0"; 
+		public const string VERSION = "0.9.9.0"; 
 
 		/// <summary>
 		/// The Lua version being supported

+ 6 - 0
src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.net40-client/MoonSharp.Interpreter.net40-client.csproj

@@ -125,6 +125,9 @@
     <Compile Include="..\..\DataStructs\ReferenceEqualityComparer.cs">
       <Link>ReferenceEqualityComparer.cs</Link>
     </Compile>
+    <Compile Include="..\..\Interop\Attributes\MoonSharpPropertyAttribute.cs">
+      <Link>MoonSharpPropertyAttribute.cs</Link>
+    </Compile>
     <Compile Include="..\..\Interop\Attributes\MoonSharpUserDataMetamethodAttribute.cs">
       <Link>MoonSharpUserDataMetamethodAttribute.cs</Link>
     </Compile>
@@ -170,6 +173,9 @@
     <Compile Include="..\..\Interop\IGeneratorUserDataDescriptor.cs">
       <Link>IGeneratorUserDataDescriptor.cs</Link>
     </Compile>
+    <Compile Include="..\..\Interop\PropertyTableAssigner.cs">
+      <Link>PropertyTableAssigner.cs</Link>
+    </Compile>
     <Compile Include="..\..\Interop\StandardDescriptors\EnumDescriptor.cs">
       <Link>EnumDescriptor.cs</Link>
     </Compile>

+ 6 - 0
src/MoonSharp.Interpreter/_Projects/MoonSharp.Interpreter.portable40/MoonSharp.Interpreter.portable40.csproj

@@ -122,6 +122,9 @@
     <Compile Include="..\..\DataStructs\ReferenceEqualityComparer.cs">
       <Link>ReferenceEqualityComparer.cs</Link>
     </Compile>
+    <Compile Include="..\..\Interop\Attributes\MoonSharpPropertyAttribute.cs">
+      <Link>MoonSharpPropertyAttribute.cs</Link>
+    </Compile>
     <Compile Include="..\..\Interop\Attributes\MoonSharpUserDataMetamethodAttribute.cs">
       <Link>MoonSharpUserDataMetamethodAttribute.cs</Link>
     </Compile>
@@ -167,6 +170,9 @@
     <Compile Include="..\..\Interop\IGeneratorUserDataDescriptor.cs">
       <Link>IGeneratorUserDataDescriptor.cs</Link>
     </Compile>
+    <Compile Include="..\..\Interop\PropertyTableAssigner.cs">
+      <Link>PropertyTableAssigner.cs</Link>
+    </Compile>
     <Compile Include="..\..\Interop\StandardDescriptors\EnumDescriptor.cs">
       <Link>EnumDescriptor.cs</Link>
     </Compile>