3

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.

1 Answer 1

5
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
Sign up to request clarification or add additional context in comments.

1 Comment

Ok, my understanding was that blocks close over all variables at the point of their definition. I was putting self in that bucket of variables but clearly it has a more dynamic nature.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.