繁体   English   中英

在Ruby 1.9中使用instance_eval进行常量查找

[英]Constant Lookup with instance_eval in Ruby 1.9

短而甜

在Ruby 1.9中运行此代码:

FOO = "global constant"

class Something
  FOO = "success!"

  def self.handle &block
    self.new.instance_eval &block
  end
end

class Other
  FOO = "wrong constant"

  def self.handle
    Something.handle{FOO}
  end
end

puts Something.handle{FOO}
puts Other.handle

我得到“成功!” 和“错误的常数”。 如何打印两次“成功!”的电话? 这不是一种人为的乐趣 - 我不会浪费人们的时间。 我有一个现实世界的问题,我已经把它缩小到最简单的例子来证明这个问题。 继续阅读“为什么”。

一个更彻底的解释

调用Something.handle {FOO}正常工作。 Ruby使用Something类中给出的FOO的定义。 但是,如果我尝试调用它从另一个类的方法相同,它给我该类的FOO的定义。

我认为Ruby 1.9中更严格的常量查找的想法是为了避免这样的问题。 instance_eval应该使用其接收器的范围(在这种情况下为self.new),而不是调用块的范围。 它适用于实例变量之类的东西,但不适用于常量。 这不是优先级问题 - 删除“全局”和“错误”常量,并且ruby仍然无法找到剩余的正确常量。

我遇到的现实问题是我有一个包含多个类的模块。 我有一个接受块的方法,并在模块的上下文中运行块。 在该块中,我希望能够通过它们的短名称引用这些类(就像我可以在模块本身的任何地方),而不是必须在模块名称前面添加。

这很痛苦:

ThirdPartyApis::MyAnswerSite.connection question.id, answer.id do |question_id, answer_id|
  question = ThirdPartyApis::MyAnswerSite::Question.find question_id
  answer = ThirdPartyApis::MyAnswerSite::Answer.find answer_id

  ThirdPartyApis::MyAnswerSite::Solution.new question, answer
end

这很愉快:

ThirdPartyApis::MyAnswerSite.connection question.id, answer.id do |question_id, answer_id|
  question = Question.find question_id
  answer = Answer.find answer_id

  Solution.new question, answer
end

摘要

这就是冗长的解释。 请不要提供不解决我的问题的解决方法。 我很欣赏探索其他途径的愿望,但我的问题很简单:只能修改Something类,以打印“成功!”的方式。 最后两次? 这是测试案例,任何符合此要求的解决方案都是我接受的答案,其作者是本周的个人英雄。 请!

我使用sourcify gem( gem install sourcify )让它工作:

require 'sourcify'
FOO = "global constant"

class Something
  FOO = "success!"

  def self.handle &block
    (self.new.instance_eval(block.to_source)).call
  end

end

class Other
  FOO = "wrong constant"

  def self.handle
    Something.handle{FOO}
  end
end

puts Something.handle{FOO}
=> success!
puts Other.handle
=> success!

编辑:糟糕,您可以看到我正在使用绑定的位置,删除该代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM