我试图通过编写动态生成的类方法来干我的代码。
我想要的是有多个错误类,我有以下代码
红宝石
class ChatPolicy::Error < StandardError
ERROR_CLASSES = [
{ class_name: 'UserBlacklisted', message: 'Message 1' },
{ class_name: 'UserSuspended', message: 'Message 2' },
{ class_name: 'UserNotEligibleToRent', message: 'Message 3' },
{ class_name: 'MembershipTierNotAllowed', message: 'Message 4' }
]
ERROR_CLASSES.each do |cls|
Object.const_set(cls[:class_name], Class.new {
attr_reader :object
def initialize(object)
@object = object
@message = cls[:message]
end
})
end
end
但是,由于在Class.new {}
块中,变量无法传入。我无法初始化消息变量。我想知道如何实现这一目标?
答案 0 :(得分:2)
使用def
定义方法时,不能从方法定义中的外部作用域引用局部变量,即cls
方法中的initialize
变量。
你可以从块内部引用这样的局部变量,你可以使用块来创建一个define_method
的方法。
因此,在您的示例中,您可以通过更改行
来使其工作def initialize(object)
到
define_method(:initialize) do |object|
既然方法体是一个块,你可以参考体内的cls
。
答案 1 :(得分:1)
但是,由于在
Class.new {}
块中,无法传入变量。
这不是关于“变量无法传入”,这是关于“在一个块内,接收器不同而且cls
局部变量无法解析。”有两种可能的方法来实现目标:
- 直接从可见内容中查找消息:
@message = ChatPolicy::Error::ERROR_CLASSES.detect do |hash|
hash[:class_name] == self.class.name
end[:message]
- 或使用class_eval
:
ERROR_CLASSES.each do |cls|
Object.const_set(cls[:class_name], class_eval %Q|
Class.new {
attr_reader :object
def initialize(object)
@object = object
@message = '#{cls[:message]}' # ⇐ HERE !!!
end
}|)
end
UPD @matt的方法更好;我留下这个答案仅用于历史目的。