简体   繁体   English

在 Ruby 中为类的实例动态定义超级方法

[英]Dynamically define a super method for an instance of a class in Ruby

Say we have a class that we cannot change,假设我们有一个我们不能改变的类,

class C
  def foo
    super
    puts "Low!"
  end
end

We'll need to dynamically define the method foo in something that we'll be able to inject into C's ancestry chain.我们需要动态地定义foo方法,以便我们能够注入到 C 的祖先链中。 The behavior of super must be specific to a given object, not class-wide. super的行为必须特定于给定的对象,而不是类范围的。 We'll be able to enclose that logic into an anonymous module (let's name it for now):我们将能够将该逻辑包含在一个匿名模块中(让我们暂时命名):

module M
  def foo
    puts "High!"
  end
end

Extending an instance of C with the module:使用模块扩展C的实例:

c = C.new
c.extend(M)
c.foo
# High!

will not work since we've put the method from the module before the method we've defined in the class.将不起作用,因为我们将模块中的方法放在我们在类中定义的方法之前。 Looking at our object's ancestors查看我们对象的祖先

c.singleton_class.ancestors
# => [#<Class:#<C:0x00005652be630b20>>, M, C, ...]

I came up with an ugly workaround, which is redefining the methods from our class in our singleton_class, ie我想出了一个丑陋的解决方法,即在我们的单例类中重新定义我们类中的方法,即

c.define_singleton_method(:foo, c.class.instance_method(:foo))
c.foo
# High!
# Low!

While this works (does it work? I've tested it for a bit and it seems to, but I'm no longer certain), I wonder whether I'm missing something obvious and there's an easier way to dynamically define a "super" method for an instance of a class.虽然这有效(它有效吗?我已经测试了一段时间,似乎可以,但我不再确定),我想知道我是否遗漏了一些明显的东西,并且有一种更简单的方法来动态定义“超级" 类的实例的方法。

To be clear, we want to be able to extend another instance of C with another module, ie明确地说,我们希望能够用另一个模块扩展另一个C实例,即

C.new.extend(Module.new do
  def foo
    puts "Medium!"
  end
end).foo
# Medium!
# Low!

and have its output not tainted by other instances.并使其输出不受其他实例的污染。

Now that I understand you're trying to work around an issue in some third-party code, I can suggest a more reasonable solution.既然我知道您正在尝试解决某些第三方代码中的问题,我可以建议一个更合理的解决方案。 In the code below, I'm thinking that B and C are defined by the gem and you don't want to change their source code, but you want to inject some code into the place where C#foo calls B#foo .在下面的代码中,我认为BC是由 gem 定义的,您不想更改它们的源代码,但是您想在C#foo调用B#foo的地方注入一些代码。

class B
  def foo
    puts "Highest!"
  end
end

class C < B
  def foo
    super
    puts "Low!"
  end
end

module CE
  def foo
    super
    foo_injected
  end
end

C.include(CE)

module M
  def foo_injected
    puts "High!"
  end
end

c = C.new
c.extend(M)
p c.singleton_class.ancestors
c.foo

The output is:输出是:

[#<Class:#<C:0x000055ce443366a8>>, M, C, CE, B, Object, Kernel, BasicObject]
Highest!
High!
Low!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何动态定义ruby中的实例方法? - How to define instance method in ruby dynamically? 用Sorbet在Ruby中定义super class中定义的passthrough方法的方法签名 - Define method signature for passthrough method defined in super class in Ruby with Sorbet Ruby / Rails 元编程,如何动态定义实例和 class 方法? - Ruby / Rails meta programing, how to define instance and class methods dynamically? 在已经在ruby中定义了类之后,定义类的实例方法 - Define instance method of a class after class already defined in ruby 我应该如何在Ruby中定义其处理算法在超类中定义的实例变量? - How should I define an instance variable in Ruby whose processing algorithm is defined in a super class? (class_eval,define_method)vs(instance_eval,define_method)的Ruby单例方法 - Ruby singleton methods with (class_eval, define_method) vs (instance_eval, define_method) 如何根据一个实例变量,使用define_method在ruby中动态创建一个方法? - How to create a method dynamically in ruby with define_method, depending on one instance variable? 在实例方法中动态定义方法 - Dynamically define a method inside an instance method 在ruby中调用超类中的另一个方法 - calling another method in super class in ruby Ruby-如何为类方法模仿super? - Ruby - How to mimic super for class method?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM