是否可以通过使用字符串作为模块来扩展类? - 红宝石 2.7.1

Posted

技术标签:

【中文标题】是否可以通过使用字符串作为模块来扩展类? - 红宝石 2.7.1【英文标题】:Is it possible to extend a class by using a string as a module ? - Ruby 2.7.1 【发布时间】:2020-10-23 07:22:28 【问题描述】:

我正在 FreeBSD 12.1 上使用 Ruby 2.7.1 进行一些测试。我知道如何用模块扩展一个类,例如:

class Myclass
  def mymethod
    extend Mymodule
  end
end

但是有没有可能用类似这样的东西获得相同的结果:

class Myclass
  def mymethod
    var = "Mymodule"
    extend var
  end
end

如果我这样做,我会得到一个错误,因为extend指向一个字符串而不是一个模块。

这里有一些解释 - 例如,它在以下应用程序中很有用:

假设您有一个包含大量 ruby​​ 脚本的文件夹,它们都是具有明显名称的模块。例如 abcd.rb 将包含模块 Abcd。所以我创建了一个文件列表并将其保存在一个数组中。然后我可以加载或要求此数组中列出的所有这些文件。由于模块的名称是可预测的,因此我只需对数组的索引执行一些 .sub、.chop 和 .capitalize 方法,以获得看起来像模块名称的可行结果。

我们的想法是创建一种使用所有这些模块自动扩展我的主类的方法。在这个想法中,添加到文件夹中的任何模块都将自动加载并准备好使用。

但是由于我的数组操作的结果不是“纯”模块名称而是字符串,所以我就卡在这里了。

那么,有什么方法可以实现这一点(也许我使用了错误的路径)或者是不可能的?

提前致谢!

【问题讨论】:

好问题。我可以想象这种技术很有用。 可能也想看看Module#autoload,以便更轻松地实现加载。您可以Dir.glob.map 然后设置自动加载并返回符号并在其末尾标记each(&method(:extend))。我现在没有足够的时间来写一个完整的答案,否则我会的。 【参考方案1】:

您不能extend "arbitrary string",但您可以先将其转换为module

class Myclass
  def mymethod
    var = "Mymodule"
    extend self.class.const_get(var)
  end
end

const_get 可以轻松解析简单的模块名称,例如 XX::Y

ActiveSupport 中还有 constantize 方法,它与 Rails 捆绑在一起,做类似的事情:

extend var.constantize

【讨论】:

@Stefan 这是个好消息。也许我对没有这样做的旧版本的 Ruby 感到困惑。 显式调用 Object.const_get 并不等同于 OP 所写的内容,因为您明确地在 Object 开始查找(这也是***,因此有效地结束了那里的查找同样,模 KernelBasicObject)。为了使您的代码与 OP 的代码等效,您只需执行 const_get,或者因为这是一个实例方法,而不是 self.class.const_get,所以在接收者的类而不是 Object 处开始查找。 @JörgWMittag 保留分辨率范围?好主意。 是的。例如,无法解析周围词法范围内的常量可能会令人惊讶。

以上是关于是否可以通过使用字符串作为模块来扩展类? - 红宝石 2.7.1的主要内容,如果未能解决你的问题,请参考以下文章

红宝石'is_a?需要类或模块(TypeError)

如何使用 omniauth / oauth 对每秒登录次数进行基准测试? (红宝石+rspec)

红宝石啥时候出现特征类

markdown 红宝石标准库及扩展库的使用

是否有任何语言在 lua 中使用类似红宝石的糖生成目标代码?

无法加载 EventMachine C 扩展;使用纯红宝石反应器