Ruby: класс String для исправления Monkey

Меня немного смущает, почему на самом деле работает следующий фрагмент кода:

String.instance_eval do # self is set to String
  [:readlink, :symlink?, :expand_path].each do |method| # self is still String
    define_method(method) do # self is still String
      File.send(method, self) # what exactly is this self?
    end
  end
end
"asdf".expand_path # => "C:/users/some_user/asdf"

Я не понимаю, почему последняя строчка работает именно так. Когда каждый метод определен, разве тело метода не эквивалентно File.send(method, String)? Ни один из вышеперечисленных блоков не меняет self. Единственная строка, которая изменяет self, - это String.instance_eval, и она меняет self на String.


person David K.    schedule 23.10.2012    source источник


Ответы (1)


File.send(method, self)

Этот self будет оцениваться при вызове этого динамически сгенерированного метода. В этот момент он будет установлен на экземпляр String. ("asdf" в вашем примере).

Фактически это эквивалентно открытию класса String и написанию всех этих методов вручную.

class String
  def readlink
    File.send :readlink, self
  end

  def expand_path
    File.send :expand_path, self
  end
end
person Sergio Tulentsev    schedule 23.10.2012
comment
Хорошо, я понял, что блоки закрываются по всем переменным в точке их определения. Я помещал self в это ведро переменных, но явно он имеет более динамичный характер. - person David K.; 23.10.2012