在 class_eval 中访问 Ruby class 变量的顶级错误
Toplevel error accessing Ruby class variable in class_eval
我正在处理旧代码 Rails 3,Ruby 1.9.3 代码库。我引用了 gem 由于各种原因我无法升级。 gem 已经使用 class_eval 进行了猴子修补(正确的术语?)。我需要更改另一个看起来像这样的方法:
SomeNamespace::Bar do
def some_method
@@part_of_header ||= JSON.dump({... Stuff ...})
# ... other code ...
headers = {
"Header Part" => @@part_of_header
#... other headers ...
}
end
end
@@part_of_header class 变量背后的想法是缓存 JSON 转储以便可以重复使用。 @@part_of_header 未在 Bar base class.
的其他地方定义
我的猴子修补方法如下:
SomeNamespace::Bar.class_eval do
def some_method
@@part_of_header ||= JSON.dump({... Stuff ...})
# ... other code that I changed ...
headers = {
"Header Part" => @@part_of_header
#... other headers that I changed ...
}
end
end
代码工作正常,但我在 @@part_of_header class 变量的行中收到以下警告:
Class variable access from toplevel
我尝试将 class 变量移动到它自己的方法中:
SomeNamespace::Bar.class_eval do
def header_part
@@part_of_header ||= JSON.dump({... Stuff ...})
end
def some_method
# ... other code that I changed ...
headers = {
"Header Part" => header_part
#... other headers that I changed ...
}
end
end
然而 "toplevel" 错误只是转移到 header_part 方法。
我还尝试使用 class_variable_set 和 class_variable_get 访问 class 变量,但出现未定义的方法错误。
关于如何修复此警告的任何建议?如果无法修复,关于在 class_eval 中缓存 JSON 转储的任何建议?谢谢。
更新:
感谢@Josh 使用完整的 class 名称和 class_variable_get/set。我的最终解决方案如下:
SomeNamespace::Bar.class_eval do
def header_part
# Create the class variable if it does not exist, remember
# the base class does not define @@part_of_header.
if !SomeNamesapce::Bar.class_variable_defined?(:@@part_of_header)
SomeNamespace::Bar.class_variable_set(:@@part_of_header, nil)
end
if (SomeNamespace::Bar.class_variable_get(:@@part_of_header).nil?
header_part = JSON.dump({... Stuff ...})
SomeNamespace::Bar.class_variable_set(:@@part_of_header, header_part)
end
SomeNamespace::Bar.class_variable_get(:@@part_of_header)
end
def some_method
# ... other code that I changed ...
headers = {
"Header Part" => header_part
#... other headers that I changed ...
}
end
end
以上方法有效,但如有任何对上述解决方案的反馈,我们将不胜感激。谢谢。
看起来问题在于,尽管 class_eval
do
块是在 SomeNamespace::Bar
的上下文中执行的,但该上下文不适用于对 [=26] 的引用=]变量。
如果您 explicitly access the class variable,那么事情应该会按预期进行:
# NOTE: Omitting conditional set (||=) for simplicity
SomeNamespace::Bar::class_variable_set(:@@part_of_header, JSON.dump({... Stuff ...}))
headers = {
"Header Part" => SomeNamespace::Bar::class_variable_get(:@@part_of_header)
#... other headers that I changed ...
}
如果 @@part_of_header
真的只在 some_method
中使用,并且如果你完全替换 some_method
,那么你使用自己的模块变量 / class 变量,而不是重用现有的 SomeNamespace::Bar::@@part_of_header
。我可能更喜欢这种方法;感觉它更好地封装了您的更改。
module MonkeyPatch
SomeNamespace::Bar.class_eval do
def some_method
# This is within the MonkeyPatch module, so it
# makes a new class variable for MonkeyPatch
@@part_of_header ||= "JSON.dump({'a': 12})"
# ... other code that I changed ...
headers = {
"Header Part" => @@part_of_header
#... other headers that I changed ...
}
puts headers
end
end
end
我正在处理旧代码 Rails 3,Ruby 1.9.3 代码库。我引用了 gem 由于各种原因我无法升级。 gem 已经使用 class_eval 进行了猴子修补(正确的术语?)。我需要更改另一个看起来像这样的方法:
SomeNamespace::Bar do
def some_method
@@part_of_header ||= JSON.dump({... Stuff ...})
# ... other code ...
headers = {
"Header Part" => @@part_of_header
#... other headers ...
}
end
end
@@part_of_header class 变量背后的想法是缓存 JSON 转储以便可以重复使用。 @@part_of_header 未在 Bar base class.
的其他地方定义我的猴子修补方法如下:
SomeNamespace::Bar.class_eval do
def some_method
@@part_of_header ||= JSON.dump({... Stuff ...})
# ... other code that I changed ...
headers = {
"Header Part" => @@part_of_header
#... other headers that I changed ...
}
end
end
代码工作正常,但我在 @@part_of_header class 变量的行中收到以下警告:
Class variable access from toplevel
我尝试将 class 变量移动到它自己的方法中:
SomeNamespace::Bar.class_eval do
def header_part
@@part_of_header ||= JSON.dump({... Stuff ...})
end
def some_method
# ... other code that I changed ...
headers = {
"Header Part" => header_part
#... other headers that I changed ...
}
end
end
然而 "toplevel" 错误只是转移到 header_part 方法。
我还尝试使用 class_variable_set 和 class_variable_get 访问 class 变量,但出现未定义的方法错误。
关于如何修复此警告的任何建议?如果无法修复,关于在 class_eval 中缓存 JSON 转储的任何建议?谢谢。
更新: 感谢@Josh 使用完整的 class 名称和 class_variable_get/set。我的最终解决方案如下:
SomeNamespace::Bar.class_eval do
def header_part
# Create the class variable if it does not exist, remember
# the base class does not define @@part_of_header.
if !SomeNamesapce::Bar.class_variable_defined?(:@@part_of_header)
SomeNamespace::Bar.class_variable_set(:@@part_of_header, nil)
end
if (SomeNamespace::Bar.class_variable_get(:@@part_of_header).nil?
header_part = JSON.dump({... Stuff ...})
SomeNamespace::Bar.class_variable_set(:@@part_of_header, header_part)
end
SomeNamespace::Bar.class_variable_get(:@@part_of_header)
end
def some_method
# ... other code that I changed ...
headers = {
"Header Part" => header_part
#... other headers that I changed ...
}
end
end
以上方法有效,但如有任何对上述解决方案的反馈,我们将不胜感激。谢谢。
看起来问题在于,尽管 class_eval
do
块是在 SomeNamespace::Bar
的上下文中执行的,但该上下文不适用于对 [=26] 的引用=]变量。
如果您 explicitly access the class variable,那么事情应该会按预期进行:
# NOTE: Omitting conditional set (||=) for simplicity
SomeNamespace::Bar::class_variable_set(:@@part_of_header, JSON.dump({... Stuff ...}))
headers = {
"Header Part" => SomeNamespace::Bar::class_variable_get(:@@part_of_header)
#... other headers that I changed ...
}
如果 @@part_of_header
真的只在 some_method
中使用,并且如果你完全替换 some_method
,那么你使用自己的模块变量 / class 变量,而不是重用现有的 SomeNamespace::Bar::@@part_of_header
。我可能更喜欢这种方法;感觉它更好地封装了您的更改。
module MonkeyPatch
SomeNamespace::Bar.class_eval do
def some_method
# This is within the MonkeyPatch module, so it
# makes a new class variable for MonkeyPatch
@@part_of_header ||= "JSON.dump({'a': 12})"
# ... other code that I changed ...
headers = {
"Header Part" => @@part_of_header
#... other headers that I changed ...
}
puts headers
end
end
end