gpt4 book ai didi

ruby - 在 Module#included 中的 class_eval 中定义类变量

转载 作者:IT老高 更新时间:2023-10-28 12:29:10 27 4
gpt4 key购买 nike

如何在 class_eval block 中定义类变量?我有以下内容:

module Persist
def self.included(base)
# base is the class including this module
base.class_eval do
# class context begin
@@collection = Connection.new.db('nameofdb').collection(self.to_s.downcase)
def self.get id # Class method
#...
end
end
end
# Instance methods follow
def find
@@collection.find().first
#...
end
end

class User
include Persist
end

class Post
include Persist
end

当使用 User.methodsPost.methods 进行自省(introspection)时,User 和 Post 类都显示 :get。这是有道理的,因为它们是在 class_eval 的上下文中定义的,并且正是我所需要的。类似地,方法 :find 显示为各个类的 instance_method。

然而,我认为是一个类变量,即 @@collection,结果却是一个模块级别的 class_variable。当我反省 User.class_variablesPost.class_variables 时,它们变成了空的。但是 Persist.class_variables 显示 :@@collection

这怎么可能? class_eval block 内的上下文不是类的上下文吗?那么变量 @@collection 不应该在类而不是模块上定义吗?

另外,@@collection 的值始终是包含它的最后一个类的名称。所以在这种情况下,它始终是“帖子”,而不是“用户”。我认为这是因为它是一个模块级变量,它会在每次包含时发生变化。这是正确的吗?

最后我将如何在这个上下文中定义一个类变量,以便每个类都有自己的 @@collection 定义。

最佳答案

一种方法是为类变量创建访问器方法。

module Persist
def self.included(base)
# Adds class methods from 'ClassMethods' to including class.
base.extend(ClassMethods)
base.class_eval do
self.collection = Connection.new.db('nameofdb').collection(self.to_s.downcase)
# ...
end
end
module ClassMethods
def collection=(value)
@@collection = value
end
def collection
@@collection
end
end
# Instance methods follow
def find
self.class.collection.find().first
#...
end
end

class User
include Persist
end

class Post
include Persist
end

另一种方法是通过访问器class_variable_set等访问模块中包含类的类变量。

def self.included(base)
base.class_eval do
class_variable_set('@@collection', Connection.new.db('nameofdb').collection(self.to_s.downcase))
# …
end
end

我将尝试回答您的问题“这怎么可能?class_eval block 中的上下文不是类的上下文。”

class_eval 方法确实使 self 引用它在给定 block 内被调用的类。这允许您调用类方法等。但是,类变量将在 block 绑定(bind)到的上下文中进行评估 - 这里是模块。

例如,尝试这样做:

class Foo
@@bar = 1
end

Foo.class_eval { puts @@bar }

这将导致异常“NameError: uninitialized class variable @@bar in Object”。这里给定的 block 绑定(bind)到顶级命名空间“Object”的上下文。

关于ruby - 在 Module#included 中的 class_eval 中定义类变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14921569/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com