Что означает class_eval << - "end_eval", __FILE__, __LINE__ в Ruby? - PullRequest
42 голосов
/ 23 марта 2010

Я учусь использовать 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 ]

53 голосов
/ 23 марта 2010

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

4 голосов
/ 23 марта 2010

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

2 голосов
/ 10 июня 2013

Отметим также, что по возможности следует избегать 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...