Короткие и сладкие
Запуск этого кода в 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
Я получаю "успех!" и "неправильная константа". Как я могу получить оба звонка, чтобы напечатать «успех!»? Это не надуманное упражнение для развлечения - я бы не стал тратить на это время людей. У меня есть реальная проблема, и я сократил ее до простейшего возможного примера, который демонстрирует проблему. Продолжайте читать «почему».
Более подробное объяснение
Calling Something.handle {FOO} работает правильно. Ruby использует определение FOO, данное в классе Something. Однако, если я попытаюсь назвать его таким же образом из другого класса, это даст мне определение FOO для , что class.
Я думал, что идея более жестких постоянных поисков в 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 таким образом, чтобы это выглядело «успех!» дважды в конце? Это тестовый пример, и любое решение, которое подходит для этого, является моим принятым ответом, а его автор - мой личный герой на неделю. Пожалуйста!