在Ruby 1.9中使用instance_eval进行常量查找 [英] Constant Lookup with instance_eval in Ruby 1.9

查看:101
本文介绍了在Ruby 1.9中使用instance_eval进行常量查找的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简短而甜美

在Ruby 1.9中运行此代码:

Running this code in 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

我得到成功!"和错误常数".如何获得两个打印成功!"的电话?这不是一个有趣的练习,我不会为此而浪费人们的时间.我遇到了一个现实问题,并将其简化为最简单的示例来说明问题.继续阅读为什么".

I get "success!" and "wrong constant". How can I get both calls to print "success!"? This is not a contrived exercise for fun - I wouldn't waste people's time for that. I have a real-world problem, and I've whittled it down to the simplest possible example that demonstrates the issue. Read on for the "why".

更详尽的说明

调用Something.handle {FOO}正常工作. Ruby使用Something类中给出的FOO的定义.但是,如果我尝试从另一个类中以相同的方式调用它,则会为那个类提供FOO的定义.

Calling Something.handle{FOO} works correctly. Ruby uses the definition of FOO given in the Something class. However, If I try to call it the same way from another class, it gives me the definition of FOO for that class.

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

I thought the idea of tighter constant looksups in Ruby 1.9 was to avoid problems like this. instance_eval is supposed to use the scope of its receiver (self.new, in this case), not the scope of the calling block. It works for things like instance variables, but not for constants. This is not a problem of precedence - remove the "global" and "wrong" constants, and ruby still won't be able to find the remaining correct constant.

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

The real-world problem I'm having is that I have a module with several classes. I have a method that accepts a block, and runs the block in the context of the module. Inside that block, I want to be able to refer to those classes by their short names (like I can anywhere in the module itself), rather than having to prepend the module name.

这很痛苦:

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类,使其打印出成功!".最后两次?那是测试用例,适合这个的任何解决方案都是我接受的答案,它的作者是我本周的个人英雄.拜托!

So that's the long-winded explanation. Please don't offer workarounds that don't address my question. I appreciate the desire to explore other avenues, but my question is simple: can ONLY the Something class by modified, in a way that prints "success!" twice at the end? That's the test case, and any solution that fits this is my accepted answer, and its author is my personal hero for the week. Please!

推荐答案

我使用硫化宝石(gem install sourcify)使它起作用:

I got it to work using the 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!

糟糕,您也可以看到我在使用绑定的地方,也删除了该代码.

edit: Oops, you could see where I was working on using bindings too, removed that code.

这篇关于在Ruby 1.9中使用instance_eval进行常量查找的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆