PageRenderTime 258ms CodeModel.GetById 44ms app.highlight 106ms RepoModel.GetById 56ms app.codeStats 0ms

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

https://github.com/MarkNijhof/ironruby
C# | 333 lines | 253 code | 59 blank | 21 comment | 30 complexity | ebb4901a585244ef11318503a1d8d1fa MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, MIT, GPL-2.0
  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
 16#if !SILVERLIGHT // ICustomTypeDescriptor
 17
 18using System;
 19using System.Collections.Generic;
 20using System.ComponentModel;
 21using System.Runtime.CompilerServices;
 22using Microsoft.Scripting;
 23using Microsoft.Scripting.Actions.Calls;
 24using Microsoft.Scripting.Utils;
 25using IronRuby.Builtins;
 26using IronRuby.Compiler.Generation;
 27using IronRuby.Runtime.Calls;
 28
 29namespace IronRuby.Runtime {
 30    /// <summary>
 31    /// Helper class that all custom type descriptor implementations call for
 32    /// the bulk of their implementation.
 33    /// </summary>
 34    public static class CustomTypeDescHelpers {
 35
 36        #region ICustomTypeDescriptor helper functions
 37
 38        private static RubyClass/*!*/ GetImmediateClass(object self) {
 39            IRubyObject rubyObj = self as IRubyObject;
 40            ContractUtils.RequiresNotNull(rubyObj, "self");
 41            return rubyObj.ImmediateClass;
 42        }
 43
 44        [Emitted]
 45        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
 46        public static AttributeCollection GetAttributes(object self) {
 47            return AttributeCollection.Empty;
 48        }
 49
 50        [Emitted]
 51        public static string GetClassName(object self) {
 52            return GetImmediateClass(self).NominalClass.Name;
 53        }
 54
 55        [Emitted]
 56        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
 57        public static string GetComponentName(object self) {
 58            return null;
 59        }
 60
 61        [Emitted]
 62        public static TypeConverter GetConverter(object self) {
 63            return new TypeConverter();
 64        }
 65
 66        [Emitted]
 67        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
 68        public static EventDescriptor GetDefaultEvent(object self) {
 69            return null;
 70        }
 71
 72        [Emitted]
 73        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
 74        public static PropertyDescriptor GetDefaultProperty(object self) {
 75            return null;
 76        }
 77
 78        [Emitted]
 79        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "editorBaseType")]
 80        public static object GetEditor(object self, Type editorBaseType) {
 81            return null;
 82        }
 83
 84        [Emitted]
 85        public static EventDescriptorCollection GetEvents(object self, Attribute[] attributes) {
 86            // TODO: update when we support attributes on Ruby types
 87            if (attributes == null || attributes.Length == 0) {
 88                return GetEvents(self);
 89            }
 90
 91            // you want things w/ attributes?  we don't have attributes!
 92            return EventDescriptorCollection.Empty;
 93        }
 94
 95        [Emitted]
 96        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self")]
 97        public static EventDescriptorCollection GetEvents(object self) {
 98            return EventDescriptorCollection.Empty;
 99        }
100
101        [Emitted]
102        public static PropertyDescriptorCollection GetProperties(object self) {
103            return new PropertyDescriptorCollection(GetPropertiesImpl(self, new Attribute[0]));
104        }
105
106        [Emitted]
107        public static PropertyDescriptorCollection GetProperties(object self, Attribute[] attributes) {
108            return new PropertyDescriptorCollection(GetPropertiesImpl(self, attributes));
109        }
110
111        static PropertyDescriptor[] GetPropertiesImpl(object self, Attribute[] attributes) {
112            bool ok = true;
113            foreach (var attr in attributes) {
114                if (attr.GetType() != typeof(BrowsableAttribute)) {
115                    ok = false;
116                    break;
117                }
118            }
119            if (!ok) {
120                return new PropertyDescriptor[0];
121            }
122            
123            RubyClass immediateClass = GetImmediateClass(self);
124            RubyContext context = immediateClass.Context;
125
126            const int readable = 0x01;
127            const int writable = 0x02;
128
129            var properties = new Dictionary<string, int>();
130            using (context.ClassHierarchyLocker()) {
131                immediateClass.ForEachMember(true, RubyMethodAttributes.DefaultVisibility, delegate(string/*!*/ name, RubyModule/*!*/ module, RubyMemberInfo/*!*/ member) {
132                    int flag = 0;
133                    if (member is RubyAttributeReaderInfo) {
134                        flag = readable;
135                    } else if (member is RubyAttributeWriterInfo) {
136                        flag = writable;
137                    } else if (name == "initialize") {
138                        // Special case; never a property
139                    } else {
140                        int arity = member.GetArity();
141                        if (arity == 0) {
142                            flag = readable;
143                        } else if (arity == 1 && name.LastCharacter() == '=') {
144                            flag = writable;
145                        }
146                    }
147                    if (flag != 0) {
148                        if (flag == writable) {
149                            name = name.Substring(0, name.Length - 1);
150                        }
151                        int oldFlag;
152                        properties.TryGetValue(name, out oldFlag);
153                        properties[name] = oldFlag | flag;
154                    }
155                });
156            }
157
158            var result = new List<PropertyDescriptor>(properties.Count);
159            foreach (var pair in properties) {
160                if (pair.Value == (readable | writable)) {
161                    result.Add(new RubyPropertyDescriptor(context, pair.Key, self, immediateClass.GetUnderlyingSystemType()));
162                }
163            }
164            return result.ToArray();
165        }
166
167        [Emitted]
168        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "pd")]
169        public static object GetPropertyOwner(object self, PropertyDescriptor pd) {
170            return self;
171        }
172
173        #endregion
174
175#if EXPOSE_INSTANCE_VARS
176        class RubyInstanceVariableDescriptor : PropertyDescriptor {
177            private readonly string _name;
178            private readonly Type _propertyType;
179            private readonly Type _componentType;
180
181            internal RubyInstanceVariableDescriptor(string name, Type propertyType, Type componentType)
182                : base(name, null) {
183                _name = name;
184                _propertyType = propertyType;
185                _componentType = componentType;
186            }
187
188            public override object GetValue(object component) {
189                object value;
190                GetClass(component).Context.TryGetInstanceVariable(component, _name, out value);
191                return value;
192            }
193            public override void SetValue(object component, object value) {
194                GetClass(component).Context.SetInstanceVariable(component, _name, value);
195            }
196
197            public override bool CanResetValue(object component) {
198                return false;
199            }
200
201            public override Type ComponentType {
202                get { return _componentType; }
203            }
204
205            public override bool IsReadOnly {
206                get { return false; }
207            }
208
209            public override Type PropertyType {
210                get { return _propertyType; }
211            }
212
213            public override void ResetValue(object component) {
214            }
215
216            public override bool ShouldSerializeValue(object component) {
217                return false;
218            }
219        }
220#endif // EXPOSE_INSTANCE_VARS
221
222        class RubyPropertyDescriptor : PropertyDescriptor {
223            private readonly string/*!*/ _name;
224            private readonly Type/*!*/ _propertyType;
225            private readonly Type/*!*/ _componentType;
226            private readonly CallSite<Func<CallSite, object, object>>/*!*/ _getterSite;
227            private readonly CallSite<Func<CallSite, object, object, object>>/*!*/ _setterSite;
228
229            internal RubyPropertyDescriptor(RubyContext/*!*/ context, string/*!*/ name, object testObject, Type/*!*/ componentType)
230                : base(name, null) {
231                _name = name;
232                _componentType = componentType;
233
234                _getterSite = CallSite<Func<CallSite, object, object>>.Create(
235                    RubyCallAction.Make(context, _name, RubyCallSignature.WithImplicitSelf(0))
236                );
237
238                _setterSite = CallSite<Func<CallSite, object, object, object>>.Create(
239                    RubyCallAction.Make(context, _name + "=", RubyCallSignature.WithImplicitSelf(0))
240                );
241
242                try {
243                    _propertyType = GetValue(testObject).GetType();
244                } catch (Exception) {
245                    _propertyType = typeof(object);
246                }
247            }
248
249            public override object GetValue(object obj) {
250                return _getterSite.Target.Invoke(_getterSite, obj);
251            }
252
253            public override void SetValue(object obj, object value) {
254                if (_setterSite != null) {
255                    _setterSite.Target.Invoke(_setterSite, obj, value);
256                }
257            }
258
259            public override bool CanResetValue(object component) {
260                return false;
261            }
262
263            public override Type ComponentType {
264                get { return _componentType; }
265            }
266
267            public override bool IsReadOnly {
268                get { return (_setterSite == null); }
269            }
270
271            public override Type PropertyType {
272                get { return _propertyType; }
273            }
274
275            public override void ResetValue(object component) {
276            }
277
278            public override bool ShouldSerializeValue(object component) {
279                return false;
280            }
281        }
282
283#if TODO
284        private class TypeConv : TypeConverter {
285            object convObj;
286
287            public TypeConv(object self) {
288                convObj = self;
289            }
290
291            #region TypeConverter overrides
292
293            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
294                object result;
295                return Converter.TryConvert(convObj, destinationType, out result);
296            }
297
298            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
299                return Converter.CanConvertFrom(sourceType, convObj.GetType(), NarrowingLevel.All, true);
300            }
301
302            public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) {
303                return Converter.Convert(value, convObj.GetType());
304            }
305
306            public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
307                return Converter.Convert(convObj, destinationType);
308            }
309
310            public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) {
311                return false;
312            }
313
314            public override bool GetPropertiesSupported(ITypeDescriptorContext context) {
315                return false;
316            }
317
318            public override bool GetStandardValuesSupported(ITypeDescriptorContext context) {
319                return false;
320            }
321
322            public override bool IsValid(ITypeDescriptorContext context, object value) {
323                object result;
324                return Converter.TryConvert(value, convObj.GetType(), out result);
325            }
326
327            #endregion
328        }
329#endif
330    }
331}
332
333#endif