是否可以通过使用字符串作为模块来扩展类? - 红宝石 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
可以轻松解析简单的模块名称,例如 X
和 X::Y
。
ActiveSupport 中还有 constantize
方法,它与 Rails 捆绑在一起,做类似的事情:
extend var.constantize
【讨论】:
@Stefan 这是个好消息。也许我对没有这样做的旧版本的 Ruby 感到困惑。 显式调用Object.const_get
并不等同于 OP 所写的内容,因为您明确地在 Object
开始查找(这也是***,因此有效地结束了那里的查找同样,模 Kernel
和 BasicObject
)。为了使您的代码与 OP 的代码等效,您只需执行 const_get
,或者因为这是一个实例方法,而不是 self.class.const_get
,所以在接收者的类而不是 Object
处开始查找。
@JörgWMittag 保留分辨率范围?好主意。
是的。例如,无法解析周围词法范围内的常量可能会令人惊讶。以上是关于是否可以通过使用字符串作为模块来扩展类? - 红宝石 2.7.1的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 omniauth / oauth 对每秒登录次数进行基准测试? (红宝石+rspec)