【问题标题】:How do I override a class method through an instance_eval?如何通过 instance_eval 覆盖类方法?
【发布时间】:2014-03-17 08:09:32
【问题描述】:

我有一个带有方法栏的类 Foo。如何用

覆盖foo的栏
Foo.instance_eval do
  def bar
    #do something a little different
  end
end

要覆盖的内容:

module Lorem
  class Foo
    def bar
      # do something
    end
  end
end

instance_eval 需要使用,class_eval 用于覆盖但不保留上下文

【问题讨论】:

  • 有什么问题..那么?你的问题是什么?
  • 你在上面所做的工作..它有什么问题? (我刚试过,它确实覆盖了 Foo 的栏)
  • @Abdo 我比你早 15 分钟感到困惑 :-)
  • @ArupRakshit haha​​ :-) 我希望一切都好,伙计 :-)
  • j,您是否希望更改module Lorem,以便无论何时是included,都将使用您的新bar()

标签: ruby class instance


【解决方案1】:

我认为你试图实现的问题是你试图覆盖已经创建的对象的方法。

为此,您需要遍历这些对象并使用ObjectSpace 覆盖它们的方法,如https://stackoverflow.com/a/14318741/226255 中所示

以下没有帮助:

class Foo
  def bar
    puts "hello"
  end
end

x = Foo.new

Foo.instance_eval do
  def bar
    puts "bar"
  end
end

x.bar

你得到以下输出:

hello
=> nil

为了覆盖在您执行 instance_eval 之前创建的对象的方法,请执行以下操作:

x = Foo.new

ObjectSpace.each_object(Foo) { |obj|
  def obj.bar
    puts "bar"
  end
}

你得到输出:

x.bar
bar
=> nil

【讨论】:

  • 不应该这么复杂他想要的只是x.instance_eval { def bar; puts "bar"; end }
  • 是的,但您假设他引用了x。此代码将对Foo 的所有实例执行此操作。
  • @bjhaid 但是,如果他想要的只是覆盖 x 的方法,你可能是对的 =)
【解决方案2】:

假设您想更改 module Lorem 以便无论何时包含它,都将使用您的新 bar(),您非常接近:

module Lorem
  class Foo
    def bar
      puts "old bar"
    end
  end
end

Lorem::Foo.class_eval do
  def bar
    puts "new bar"
  end
end

class A
  include Lorem
  Foo.new.bar #=> "new bar"
end

【讨论】:

  • class_eval 不起作用,因为 Lorem::Foo 具有在类中评估的实例和要求
  • 我希望对 Lorem::Foo.new.bar 的每次调用都评估我的覆盖版本 bar 尽管预先存在的代码/声明的变量。前段时间我试过class_eval,切换到instance_eval
  • 我不懂你们的cmets。我将等待问题的澄清。
  • @jquadrin 如何在代码的生命周期中确定Lorem::Foo 的哪个实例应该具有bar 的哪个版本
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-30
  • 1970-01-01
  • 1970-01-01
  • 2014-11-10
  • 1970-01-01
  • 2021-06-26
  • 2023-03-15
相关资源
最近更新 更多