public static MetaObject TryBind(RubyContext /*!*/ context, GetMemberBinder /*!*/ binder, MetaObject /*!*/ target) { Assert.NotNull(context, target); var metaBuilder = new MetaObjectBuilder(); var contextExpression = Ast.Constant(context); metaBuilder.AddTargetTypeTest(target.Value, target.Expression, context, contextExpression); RubyMemberInfo method = context.ResolveMethod(target.Value, binder.Name, true).InvalidateSitesOnOverride(); if (method != null && RubyModule.IsMethodVisible(method, false)) { // we need to create a bound member: metaBuilder.Result = Ast.Constant(new RubyMethod(target.Value, method, binder.Name)); } else { // TODO: // We need to throw an exception if we don't find method_missing so that our version update optimization works: // This limits interop with other languages. // // class B CLR type with method 'foo' // class C < B Ruby class // x = C.new // // 1. x.GET("foo") from Ruby // No method found or CLR method found -> fallback to Python // Python might see its method foo or might just fallback to .NET, // in any case it will add rule [1] with restriction on type of C w/o Ruby version check. // 2. B.define_method("foo") // This doesn't update C due to the optimization (there is no overridden method foo in C). // 3. x.GET("foo") from Ruby // This will not invoke the binder since the rule [1] is still valid. // object symbol = SymbolTable.StringToId(binder.Name); RubyCallAction.BindToMethodMissing(metaBuilder, binder.Name, new CallArguments( new MetaObject(contextExpression, Restrictions.Empty, context), new[] { target, new MetaObject(Ast.Constant(symbol), Restrictions.Empty, symbol) }, RubyCallSignature.Simple(1) ), method != null ); } // TODO: we should return null if we fail, we need to throw exception for now: return(metaBuilder.CreateMetaObject(binder, MetaObject.EmptyMetaObjects)); }
protected override Node CreateNode(object data) { RubyMemberInfo method = _context.ResolveMethod(data, "to_yaml", false).InvalidateSitesOnOverride(); if (method == _objectToYamlMethod) { return(_ToYamlNode.Target(_ToYamlNode, _context, data, this)); } else { // TODO: this doesn't seem right // (we're passing the extra argument, but the callee might not take it?) return(_ToYaml.Target(_ToYaml, _context, data, this)); } }
public static MetaObject TryBind(RubyContext/*!*/ context, GetMemberBinder/*!*/ binder, MetaObject/*!*/ target) { Assert.NotNull(context, target); var metaBuilder = new MetaObjectBuilder(); var contextExpression = Ast.Constant(context); metaBuilder.AddTargetTypeTest(target.Value, target.Expression, context, contextExpression); RubyMemberInfo method = context.ResolveMethod(target.Value, binder.Name, true).InvalidateSitesOnOverride(); if (method != null && RubyModule.IsMethodVisible(method, false)) { // we need to create a bound member: metaBuilder.Result = Ast.Constant(new RubyMethod(target.Value, method, binder.Name)); } else { // TODO: // We need to throw an exception if we don't find method_missing so that our version update optimization works: // This limits interop with other languages. // // class B CLR type with method 'foo' // class C < B Ruby class // x = C.new // // 1. x.GET("foo") from Ruby // No method found or CLR method found -> fallback to Python // Python might see its method foo or might just fallback to .NET, // in any case it will add rule [1] with restriction on type of C w/o Ruby version check. // 2. B.define_method("foo") // This doesn't update C due to the optimization (there is no overridden method foo in C). // 3. x.GET("foo") from Ruby // This will not invoke the binder since the rule [1] is still valid. // object symbol = SymbolTable.StringToId(binder.Name); RubyCallAction.BindToMethodMissing(metaBuilder, binder.Name, new CallArguments( new MetaObject(contextExpression, Restrictions.Empty, context), new[] { target, new MetaObject(Ast.Constant(symbol), Restrictions.Empty, symbol) }, RubyCallSignature.Simple(1) ), method != null ); } // TODO: we should return null if we fail, we need to throw exception for now: return metaBuilder.CreateMetaObject(binder, MetaObject.EmptyMetaObjects); }
private void WriteAnObject(object obj) { if (_recursionLimit == 0) { throw RubyExceptions.CreateArgumentError("exceed depth limit"); } if (_recursionLimit > 0) { _recursionLimit--; } if (obj is int) { int value = (int)obj; if (value < -(1 << 30) || value >= (1 << 30)) { obj = (BigInteger)value; } } // TODO: use RubyUtils.IsRubyValueType? RubySymbol sym; if (obj == null) { _writer.Write((byte)'0'); } else if (obj is bool) { _writer.Write((byte)((bool)obj ? 'T' : 'F')); } else if (obj is int) { WriteFixnum((int)obj); } else if ((sym = obj as RubySymbol) != null) { // TODO (encoding): WriteSymbol(sym.ToString(), sym.Encoding); } else { int objectRef; if (_objects.TryGetValue(obj, out objectRef)) { _writer.Write((byte)'@'); WriteInt32(objectRef); } else { objectRef = _objects.Count; _objects[obj] = objectRef; // TODO: replace with a table-driven implementation // TODO: visibility? bool implementsDump = _context.ResolveMethod(obj, "_dump", VisibilityContext.AllVisible).Found; bool implementsMarshalDump = _context.ResolveMethod(obj, "marshal_dump", VisibilityContext.AllVisible).Found; bool writeInstanceData = false; string[] instanceNames = null; if (!implementsDump && !implementsMarshalDump) { // Neither "_dump" nor "marshal_dump" writes instance vars separately instanceNames = _context.GetInstanceVariableNames(obj); if (instanceNames.Length > 0) { _writer.Write((byte)'I'); writeInstanceData = true; } } if (!implementsDump || implementsMarshalDump) { // "_dump" doesn't write "extend" info but "marshal_dump" does RubyClass theClass = _context.GetImmediateClassOf(obj); if (theClass.IsSingletonClass) { foreach (var mixin in theClass.GetMixins()) { _writer.Write((byte)'e'); WriteModuleName(mixin); } } } if (obj is double) { WriteFloat((double)obj); } else if (obj is float) { WriteFloat((double)(float)obj); } else if (obj is BigInteger) { WriteBignum((BigInteger)obj); } else if (implementsMarshalDump) { WriteUsingMarshalDump(obj); } else if (implementsDump) { WriteUsingDump(obj); } else if (obj is MutableString) { WriteString((MutableString)obj); } else if (obj is RubyArray) { WriteArray((RubyArray)obj); } else if (obj is Hash) { WriteHash((Hash)obj); } else if (obj is RubyRegex) { WriteRegex((RubyRegex)obj); } else if (obj is RubyClass) { WriteClass((RubyClass)obj); } else if (obj is RubyModule) { WriteModule((RubyModule)obj); } else if (obj is RubyStruct) { WriteStruct((RubyStruct)obj); } else if (obj is Range) { WriteRange((Range)obj); } else { if (writeInstanceData) { // Overwrite the "I"; we always have instance data _writer.BaseStream.Seek(-1, SeekOrigin.Current); } else { writeInstanceData = true; } WriteObject(obj); } if (writeInstanceData) { WriteInt32(instanceNames.Length); var encoding = _context.GetIdentifierEncoding(); foreach (string name in instanceNames) { object value; if (!_context.TryGetInstanceVariable(obj, name, out value)) { value = null; } // TODO (encoding): WriteSymbol(name, encoding); WriteAnObject(value); } } } } if (_recursionLimit >= 0) { _recursionLimit++; } }
public static RubyMethod/*!*/ GetMethod(RubyContext/*!*/ context, object self, [DefaultProtocol, NotNull]string/*!*/ name) { RubyMemberInfo info = context.ResolveMethod(self, name, VisibilityContext.AllVisible).Info; if (info == null) { throw RubyExceptions.CreateUndefinedMethodError(context.GetClassOf(self), name); } return new RubyMethod(self, info, name); }
public static bool RespondTo(RubyContext/*!*/ context, object self, [DefaultProtocol, NotNull]string/*!*/ methodName, [Optional]bool includePrivate) { return context.ResolveMethod(self, methodName, includePrivate).Found; }
public static bool RespondTo(RubyContext/*!*/ context, object self, [DefaultProtocol, NotNull]string/*!*/ methodName, [DefaultParameterValue(null)]object includePrivate) { return context.ResolveMethod(self, methodName, Protocols.IsTrue(includePrivate)).Found; }