class_eval
и module_eval
(которые эквивалентны) используются для оценки и немедленного выполнения строк в виде кода Ruby. Как таковые они могут использоваться как средство метапрограммирования для динамического создания методов. Примером является
class Foo
%w[foo bar].each do |name|
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{name}
puts '#{name}'
end
RUBY
end
end
Будет создано два метода foo
и bar
, которые печатают свои соответствующие значения. Как видите, я создаю строку, содержащую фактический исходный код функции, и передаю ее в class_eval
.
Хотя это очень эффективный инструмент для выполнения динамически создаваемого кода, его следует использовать с большой осторожностью. Если вы допустите ошибки здесь, ПЛОХИЕ ВЕЩИ БУДУТ ПРОИЗОЙТИ. Например. если вы используете пользовательские значения при генерации кода, убедитесь, что действительно , что переменные содержат только те значения, которые вы ожидаете. В качестве последнего средства обычно следует использовать функцию на основе Eval.
Более чистым и обычно предпочтительным вариантом является использование define_method
примерно так:
class Foo
%w[foo bar].each do |name|
define_method name do
puts name
end
end
end
(Обратите внимание, что MRI немного быстрее в варианте eval. Но это не имеет значения в большинстве случаев по сравнению с дополнительной безопасностью и ясностью.)
Теперь в вашем данном коде вы эффективно пишете код в строку, которую можно запустить напрямую. Использование class_eval
здесь приводит к выполнению строки в контексте самого верхнего объекта (Kernel
в данном случае). Поскольку это специальный одноэлементный объект, который не может быть создан (аналогично nil, true и false), вы получаете эту ошибку.
Однако, когда вы создаете непосредственно исполняемый код, вам вообще не нужно использовать class_eval
(или любую форму eval). Просто запустите ваш код в цикле, как есть. И всегда помните: варианты метапрограммирования (из которых методы eval являются одними из самых плохих) следует использовать только в качестве последнего средства.