Question

I am a little confused why the following piece of code actually works:

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"

I don't understand why the last line works as it does. When each method is defined isn't the body of the method equivalent to File.send(method, String)? None of the above blocks actually change self. The only line that changes self is String.instance_eval and it changes self to String.

Was it helpful?

Solution

File.send(method, self)

This self will be evaluated when that dynamically generated method will be called. At that point it will be set to an instance of String. ("asdf" in your example).

It's actually equivalent to opening String class and writing all those methods manually.

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

  def expand_path
    File.send :expand_path, self
  end
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top