将方法从一个类复制到另一个类

发布于 2025-01-05 08:32:32 字数 714 浏览 5 评论 0原文

我想用一些方法编写小类,这些方法实际上属于其他类,那么如何在其他类中定义方法,这些方法是现有的副本。我相信这是我不明白的元编程魔术师。

class Foo
  def initialize
    # with blocks, I would just pass block, but this is methods
    # so this won't work
    Bar.class_eval(perform)
    Bar.class_eval(process)
    Bar.class_eval(save)
  end

  def perform
    1+1
  end

  def process
    # some code
  end

  def save
    # some code
  end
end

class Bar; end

foo = Foo.new
foo.perform
#=> 2
Bar.test
#=> 1

为什么我需要这个?我正在研究 gem,它只使用三种方法来进行类。在初始化时(将隐藏在父类中),它将将此方法传递给不同的类。我可以用块来做到这一点,但是用方法来实现就更干净了。

PS:这就像将方法从一个类复制到另一个

PSS:或者...如何将方法转换为 proc,以便我可以将其传递给 class_eval< /代码>

I want to write small class with some methods, which actualy belongs to other classes, so how can I define methods in other classes which are copies of existing. I believe it is metaprogramming magi I don't understand.

class Foo
  def initialize
    # with blocks, I would just pass block, but this is methods
    # so this won't work
    Bar.class_eval(perform)
    Bar.class_eval(process)
    Bar.class_eval(save)
  end

  def perform
    1+1
  end

  def process
    # some code
  end

  def save
    # some code
  end
end

class Bar; end

foo = Foo.new
foo.perform
#=> 2
Bar.test
#=> 1

Why I need this? I am working on gem which takes a class with just three methods. On initializing (which ill be hidden in parent class) it will pass this methods to different classes. I can make this with blocks, but with methods it is little cleaner.

PS: It is like copying methods from one class to another

PSS: Or... how to convert method to proc, so I can pass it to class_eval

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

童话里做英雄 2025-01-12 08:32:32

要将方法转换为可以像 Proc 一样调用的方法,请使用 obj.method(:method_name)。这将为您提供一个绑定方法对象,当调用时,将在obj上调用。如果您想在同一类的不同对象上调用它,可以调用method.unbind.bind( different_obj) 。

这仍然不允许您将方法从一个类“复制”到另一个类。如果您希望允许用户传递一个定义 3 个方法的类,而不是传递 3 个块,那么如果您在内部存储对该类(或其实例)的引用,并根据需要调用其上的方法,效果可能会更好。这就是评论“授权”的人的意思。

或者,您可以让用户传递一个模块,并创建您自己的类包含扩展模块(根据需要)。

To convert a method to something which can be called like a Proc, use obj.method(:method_name). That will give you a bound Method object, which when called, will be invoked on obj. If you want to invoke it on a different object of the same class, you can call method.unbind.bind(different_obj).

That still doesn't allow you to "copy" methods from one class to another. If you want to allow the user to pass a class which defines 3 methods, rather than passing 3 blocks, it might work better if you store a reference to that class (or an instance of it) internally, and call methods on it as required. That's what the person who commented about "delegation" meant.

OR, you can let the user pass a Module, and make your own class include or extend the module (as required).

著墨染雨君画夕 2025-01-12 08:32:32

可以将方法从一个类复制到另一个类,但有一个主要警告:目标类必须是 kind_of?源类,或者源必须是模块。此限制部分记录在 UnboundMethod# 的文档中bind,但要查看模块异常,您必须查看该方法的源代码。 此答案包含有关该主题的更多讨论。

下面是一个示例:

module A
  def say_hello
    puts "Hello"
  end
end

class B
  define_method(:say_hello, A.instance_method(:say_hello))
end

b = B.new
b.say_hello
=> Hello

如果 A 是一个类并且 B 是从 A 继承的类,那么这也将起作用。但在这种情况下,您已经通过继承获得了该方法,因此我个人认为它没有用处。

我发现此模式有用的一种情况是使用继承自 BasicObject 的对象设计 DSL。由于 BasicObject 不像 Object 那样包含内核,因此您无法轻松访问许多有用的方法,例如 # instance_variables 甚至#class。但是您可以将它们从内核单独复制到您的类中:

class Foo < BasicObject
  define_method(:class, ::Kernel.instance_method(:class))
end

f = Foo.new
puts f.class
=> Foo

It is possible to copy methods from one class to another, but there is a major caveat: the destination class must be a kind_of? the source class, or the source must be a module. This restriction is partially documented in the docs for UnboundMethod#bind, but to see the module exception you have to look at the source code for the method. This answer contains more discussion on the topic.

Here is an example:

module A
  def say_hello
    puts "Hello"
  end
end

class B
  define_method(:say_hello, A.instance_method(:say_hello))
end

b = B.new
b.say_hello
=> Hello

This would also work if A was a class and B was a class that inherited from A. But in that case, you would have already gotten the method through inheritance, so I don't personally see a use for it.

The one situation where I have found this pattern useful is when designing DSL's using objects that inherit from BasicObject. Since BasicObject doesn't include Kernel like Object does, you don't have easy access to a lot of useful methods like #instance_variables or even #class. But you can copy them individually from Kernel into your class:

class Foo < BasicObject
  define_method(:class, ::Kernel.instance_method(:class))
end

f = Foo.new
puts f.class
=> Foo
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文