Что означает class_eval << - "end_eval", __FILE__, __LINE__ означает в Ruby?
Я изучаю, как использовать class_eval в модулях (я немного знаком с class_eval) и наткнулся на этот полезный класс в resource_controller. Там они имеют такие вещи:
class_eval <<-"end_eval", __FILE__, __LINE__
def #{block_accessor}(*args, &block)
unless args.empty? && block.nil?
args.push block if block_given?
@#{block_accessor} = [args].flatten
end
@#{block_accessor}
end
end_eval
Что делает __FILE__
и __LINE__
в этом контексте? Я знаю, что __FILE__
ссылается на текущий файл, но что делает все это в точности? Не знаю, как это искать:).
Ответы
Ответ 1
__FILE__
и __LINE__
представляют собой разновидность динамических констант, которые содержат файл и строку, которые в настоящее время выполняются. Передача их здесь позволяет ошибкам правильно сообщать о своем местоположении.
instance_eval <<-end_eval, __FILE__, __LINE__
def foo
a = 123
b = :abc
a.send b
end
end_eval
foo
Когда вы запустите этот
$ ruby foo.rb
foo.rb:5:in `send': undefined method `abc' for 123:Fixnum (NoMethodError)
from foo.rb:5:in `foo'
from foo.rb:11
Обратите внимание, что он говорит файл и строку # 5, хотя это был только текст в eval. Без этого файла/линии трюк вывод будет выглядеть следующим образом:
$ ruby foo.rb
(eval):5:in `send': undefined method `abc' for 123:Fixnum (NoMethodError)
from (eval):5:in `foo'
from foo.rb:11
Трассировка стека просто показывает (eval)
, что не так полезно.
Ответ 2
<<
- начало heredoc. Эта строка является началом многострочной строки. Строка обведена для создания функции. Функция class_eval использует __FILE__ и __LINE__ для добавления отладочной информации.
Ответ 3
Следует также отметить, что при необходимости следует избегать eval
-личных строк. В вашем конкретном случае замена #class_eval
на #class_exec
возможна и должна быть предпочтительной:
class_exec do
define_method block_accessor do |*args, &block|
unless args.empty? && block.nil?
args.push block if block_given?
instance_variable_set "@#{block_accessor}", [args].flatten
end
instance_variable_get "@#{block_accessor}"
end
end