Ruby元编程:无法将方法发送到模块 [英] Ruby metaprogramming: cannot send a method to a module

查看:74
本文介绍了Ruby元编程:无法将方法发送到模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,我有以下自定义类和模块:

For example I have following custom class and module:

module SimpleModule
  def hello_world
    puts 'i am a SimpleModule method'
  end

  def self.class_hello_world
    puts 'i am a SimpleModule class method'
  end
end

class SimpleClass
  def hello_world
    puts 'i am SimpleClass method'
  end

  def self.class_hello_world
    puts 'i am a SimpleClass class method'
  end
end

我尝试使用方法send

SimpleClass.send(class_hello_world)  # work
SimpleClass.new.send(hello_world)    # work
SimpleModule.send(class_hello_world) # work
SimpleModule.new.send(hello_world)   # not work
SimpleModule.send(hello_world)       # not work

换句话说,我不知道如何从SimpleModule调用hello_world.如果该方法是使用self before定义的,则是可能的.

In other word, I don't know how to invoke hello_world from SimpleModule. It is possible if that method is defined with self before.

我需要这样做是因为我想实现一个"custom-include":包括从模块到另一个类的所有方法.

I need to do this because I want to implement a "custom-include": that include all methods from module to another class.

请告诉我该怎么做.

推荐答案

这五个语句

让我们一次考虑这五个语句(但顺序与所呈现的顺序不同).请注意,send的参数必须是表示为字符串或符号的方法的名称.

Let's consider those five statements one at a time (but in a different order than as presented). Note that send's argument must be the name of the method expressed as a string or symbol.

SimpleModule.send("class_hello_world")
  # i am a SimpleModule class method

这很正常,尽管此类方法通常称为模块方法.一些常见的内置模块(例如 Math )包含模块方法

This is normal, though such methods are normally called module methods. Some common built-in modules, such as Math, contain module methods only.

SimpleClass.send(:class_hello_world)
  # i am a SimpleClass class method

由于类是模块,所以行为与上述相同. class_hello_world通常被称为类方法.

Since a class is a module, the behaviour is the same as above. class_hello_world is usually referred to as a class method.

SimpleClass.new.send(:hello_world)
  # i am SimpleClass method

这是实例方法的常规调用.

This is the normal invocation of an instance method.

SimpleModule.send("hello_world")
  #=> NoMethodError: undefined method `hello_world' for SimpleModule:Module

没有模块方法hello_world.

SimpleModule.new.send(hello_world)
  #=> NoMethodError: undefined method `new' for SimpleModule:Module

一个人无法创建模块的实例.

One cannot create an instance of a module.

includeprepend

include vs prepend

假设一个人写过

SimpleClass.include SimpleModule
  #=> SimpleClass
SimpleClass.new.hello_world
  # i am SimpleClass method

因此,SimpleClass的原始方法hello_world不会被相同名称的模块方法所覆盖.考虑SimpleClass的祖先.

so SimpleClass' original method hello_world is not overwritten by the module's method by the same name. Consider SimpleClass' ancestors.

SimpleClass.ancestors
  #=> [SimpleClass, SimpleModule, Object, Kernel, BasicObject]

在考虑SimpleModule之前,Ruby将在SimpleClass中寻找hello_world并找到它.

Ruby will look for hello_world in SimpleClass--and find it--before considering SimpleModule.

但是,可以使用 Module#prepend SimpleModule#hello_world放在SimpleClass#hello_world之前.

One can, however, use Module#prepend to put SimpleModule#hello_world before SimpleClass#hello_world.

SimpleClass.prepend SimpleModule
  #=> SimpleClass
SimpleClass.new.hello_world
  # i am a SimpleModule method
SimpleClass.ancestors
  #=> [SimpleModule, SimpleClass, Object, Kernel, BasicObject]

绑定未绑定方法

您还有另一件事. SimpleModule的实例方法(这里只有一个)是未绑定的.您可以使用 UnboundMethod#bind 进行绑定每个都SimpleClass的实例,然后使用callsend执行它.

There is one other thing you do. SimpleModule's instance methods (here just one) are unbound. You could use UnboundMethod#bind to bind each to an instance of SimpleClass and then execute it using call or send.

sc = SimpleClass.new
  #=> #<SimpleClass:0x007fcbc2046010> 
um = SimpleModule.instance_method(:hello_world)
  #=> #<UnboundMethod: SimpleModule#hello_world> 
bm = um.bind(sc)
  #=> #<Method: SimpleModule#hello_world> 
bm.call
  #=> i am a SimpleModule method
sc.send(:hello_world)
  #=> i am a SimpleModule method

这篇关于Ruby元编程:无法将方法发送到模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆