Что означает 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__ ссылается на текущий файл, но что именно делает все это? Не знаю, как искать это:).

3 ответа

Решение

__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) что не так полезно.

<< это начало heredoc. Эта строка является началом многострочной строки. Строка выявляется для создания функции. Функция class_eval использует __FILE__ и __LINE__ для добавления отладочной информации.

Отметим также, что 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
Другие вопросы по тегам