/Languages/Ruby/Ruby/Runtime/CustomTypeDescHelpers.cs

https://github.com/developingchris/ironruby · C# · 333 lines · 253 code · 59 blank · 21 comment · 30 complexity · ebb4901a585244ef11318503a1d8d1fa MD5 · raw file

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if !SILVERLIGHT // ICustomTypeDescriptor
  16. using System;
  17. using System.Collections.Generic;
  18. using System.ComponentModel;
  19. using System.Runtime.CompilerServices;
  20. using Microsoft.Scripting;
  21. using Microsoft.Scripting.Actions.Calls;
  22. using Microsoft.Scripting.Utils;
  23. using IronRuby.Builtins;
  24. using IronRuby.Compiler.Generation;
  25. using IronRuby.Runtime.Calls;
  26. namespace IronRuby.Runtime {
  27. /// <summary>
  28. /// Helper class that all custom type descriptor implementations call for
  29. /// the bulk of their implementation.
  30. /// </summary>
  31. public static class CustomTypeDescHelpers {
  32. #region ICustomTypeDescriptor helper functions
  33. private static RubyClass/*!*/ GetImmediateClass(object self) {
  34. IRubyObject rubyObj = self as IRubyObject;
  35. ContractUtils.RequiresNotNull(rubyObj, "self");
  36. return rubyObj.ImmediateClass;
  37. }
  38. [Emitted]
  39. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
  40. public static AttributeCollection GetAttributes(object self) {
  41. return AttributeCollection.Empty;
  42. }
  43. [Emitted]
  44. public static string GetClassName(object self) {
  45. return GetImmediateClass(self).NominalClass.Name;
  46. }
  47. [Emitted]
  48. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
  49. public static string GetComponentName(object self) {
  50. return null;
  51. }
  52. [Emitted]
  53. public static TypeConverter GetConverter(object self) {
  54. return new TypeConverter();
  55. }
  56. [Emitted]
  57. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
  58. public static EventDescriptor GetDefaultEvent(object self) {
  59. return null;
  60. }
  61. [Emitted]
  62. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
  63. public static PropertyDescriptor GetDefaultProperty(object self) {
  64. return null;
  65. }
  66. [Emitted]
  67. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "editorBaseType")]
  68. public static object GetEditor(object self, Type editorBaseType) {
  69. return null;
  70. }
  71. [Emitted]
  72. public static EventDescriptorCollection GetEvents(object self, Attribute[] attributes) {
  73. // TODO: update when we support attributes on Ruby types
  74. if (attributes == null || attributes.Length == 0) {
  75. return GetEvents(self);
  76. }
  77. // you want things w/ attributes? we don't have attributes!
  78. return EventDescriptorCollection.Empty;
  79. }
  80. [Emitted]
  81. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
  82. public static EventDescriptorCollection GetEvents(object self) {
  83. return EventDescriptorCollection.Empty;
  84. }
  85. [Emitted]
  86. public static PropertyDescriptorCollection GetProperties(object self) {
  87. return new PropertyDescriptorCollection(GetPropertiesImpl(self, new Attribute[0]));
  88. }
  89. [Emitted]
  90. public static PropertyDescriptorCollection GetProperties(object self, Attribute[] attributes) {
  91. return new PropertyDescriptorCollection(GetPropertiesImpl(self, attributes));
  92. }
  93. static PropertyDescriptor[] GetPropertiesImpl(object self, Attribute[] attributes) {
  94. bool ok = true;
  95. foreach (var attr in attributes) {
  96. if (attr.GetType() != typeof(BrowsableAttribute)) {
  97. ok = false;
  98. break;
  99. }
  100. }
  101. if (!ok) {
  102. return new PropertyDescriptor[0];
  103. }
  104. RubyClass immediateClass = GetImmediateClass(self);
  105. RubyContext context = immediateClass.Context;
  106. const int readable = 0x01;
  107. const int writable = 0x02;
  108. var properties = new Dictionary<string, int>();
  109. using (context.ClassHierarchyLocker()) {
  110. immediateClass.ForEachMember(true, RubyMethodAttributes.DefaultVisibility, delegate(string/*!*/ name, RubyModule/*!*/ module, RubyMemberInfo/*!*/ member) {
  111. int flag = 0;
  112. if (member is RubyAttributeReaderInfo) {
  113. flag = readable;
  114. } else if (member is RubyAttributeWriterInfo) {
  115. flag = writable;
  116. } else if (name == "initialize") {
  117. // Special case; never a property
  118. } else {
  119. int arity = member.GetArity();
  120. if (arity == 0) {
  121. flag = readable;
  122. } else if (arity == 1 && name.LastCharacter() == '=') {
  123. flag = writable;
  124. }
  125. }
  126. if (flag != 0) {
  127. if (flag == writable) {
  128. name = name.Substring(0, name.Length - 1);
  129. }
  130. int oldFlag;
  131. properties.TryGetValue(name, out oldFlag);
  132. properties[name] = oldFlag | flag;
  133. }
  134. });
  135. }
  136. var result = new List<PropertyDescriptor>(properties.Count);
  137. foreach (var pair in properties) {
  138. if (pair.Value == (readable | writable)) {
  139. result.Add(new RubyPropertyDescriptor(context, pair.Key, self, immediateClass.GetUnderlyingSystemType()));
  140. }
  141. }
  142. return result.ToArray();
  143. }
  144. [Emitted]
  145. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "pd")]
  146. public static object GetPropertyOwner(object self, PropertyDescriptor pd) {
  147. return self;
  148. }
  149. #endregion
  150. #if EXPOSE_INSTANCE_VARS
  151. class RubyInstanceVariableDescriptor : PropertyDescriptor {
  152. private readonly string _name;
  153. private readonly Type _propertyType;
  154. private readonly Type _componentType;
  155. internal RubyInstanceVariableDescriptor(string name, Type propertyType, Type componentType)
  156. : base(name, null) {
  157. _name = name;
  158. _propertyType = propertyType;
  159. _componentType = componentType;
  160. }
  161. public override object GetValue(object component) {
  162. object value;
  163. GetClass(component).Context.TryGetInstanceVariable(component, _name, out value);
  164. return value;
  165. }
  166. public override void SetValue(object component, object value) {
  167. GetClass(component).Context.SetInstanceVariable(component, _name, value);
  168. }
  169. public override bool CanResetValue(object component) {
  170. return false;
  171. }
  172. public override Type ComponentType {
  173. get { return _componentType; }
  174. }
  175. public override bool IsReadOnly {
  176. get { return false; }
  177. }
  178. public override Type PropertyType {
  179. get { return _propertyType; }
  180. }
  181. public override void ResetValue(object component) {
  182. }
  183. public override bool ShouldSerializeValue(object component) {
  184. return false;
  185. }
  186. }
  187. #endif // EXPOSE_INSTANCE_VARS
  188. class RubyPropertyDescriptor : PropertyDescriptor {
  189. private readonly string/*!*/ _name;
  190. private readonly Type/*!*/ _propertyType;
  191. private readonly Type/*!*/ _componentType;
  192. private readonly CallSite<Func<CallSite, object, object>>/*!*/ _getterSite;
  193. private readonly CallSite<Func<CallSite, object, object, object>>/*!*/ _setterSite;
  194. internal RubyPropertyDescriptor(RubyContext/*!*/ context, string/*!*/ name, object testObject, Type/*!*/ componentType)
  195. : base(name, null) {
  196. _name = name;
  197. _componentType = componentType;
  198. _getterSite = CallSite<Func<CallSite, object, object>>.Create(
  199. RubyCallAction.Make(context, _name, RubyCallSignature.WithImplicitSelf(0))
  200. );
  201. _setterSite = CallSite<Func<CallSite, object, object, object>>.Create(
  202. RubyCallAction.Make(context, _name + "=", RubyCallSignature.WithImplicitSelf(0))
  203. );
  204. try {
  205. _propertyType = GetValue(testObject).GetType();
  206. } catch (Exception) {
  207. _propertyType = typeof(object);
  208. }
  209. }
  210. public override object GetValue(object obj) {
  211. return _getterSite.Target.Invoke(_getterSite, obj);
  212. }
  213. public override void SetValue(object obj, object value) {
  214. if (_setterSite != null) {
  215. _setterSite.Target.Invoke(_setterSite, obj, value);
  216. }
  217. }
  218. public override bool CanResetValue(object component) {
  219. return false;
  220. }
  221. public override Type ComponentType {
  222. get { return _componentType; }
  223. }
  224. public override bool IsReadOnly {
  225. get { return (_setterSite == null); }
  226. }
  227. public override Type PropertyType {
  228. get { return _propertyType; }
  229. }
  230. public override void ResetValue(object component) {
  231. }
  232. public override bool ShouldSerializeValue(object component) {
  233. return false;
  234. }
  235. }
  236. #if TODO
  237. private class TypeConv : TypeConverter {
  238. object convObj;
  239. public TypeConv(object self) {
  240. convObj = self;
  241. }
  242. #region TypeConverter overrides
  243. public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
  244. object result;
  245. return Converter.TryConvert(convObj, destinationType, out result);
  246. }
  247. public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
  248. return Converter.CanConvertFrom(sourceType, convObj.GetType(), NarrowingLevel.All, true);
  249. }
  250. public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
  251. return Converter.Convert(value, convObj.GetType());
  252. }
  253. public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
  254. return Converter.Convert(convObj, destinationType);
  255. }
  256. public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) {
  257. return false;
  258. }
  259. public override bool GetPropertiesSupported(ITypeDescriptorContext context) {
  260. return false;
  261. }
  262. public override bool GetStandardValuesSupported(ITypeDescriptorContext context) {
  263. return false;
  264. }
  265. public override bool IsValid(ITypeDescriptorContext context, object value) {
  266. object result;
  267. return Converter.TryConvert(value, convObj.GetType(), out result);
  268. }
  269. #endregion
  270. }
  271. #endif
  272. }
  273. }
  274. #endif