Skip to content

Instantly share code, notes, and snippets.

@feliperaul
Created January 7, 2022 11:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save feliperaul/372bf2732509f3eea1cff9c7a06d7718 to your computer and use it in GitHub Desktop.
Save feliperaul/372bf2732509f3eea1cff9c7a06d7718 to your computer and use it in GitHub Desktop.
Example
class Greeter
def greet(name)
"Hello #{name}"
end
end
class User
def first_name
"Foo"
end
def greet_with(&block)
Greeter.new.instance_exec(&block)
end
def greet_first_name
greet_with { greet(first_name) }
end
end
User.new.greet_first_name
@shnikola
Copy link

The problem here is that greet(first_name) is actually calling greet(self.first_name), and inside the instance_exec block, the self is no longer User. The block scope still sees local variables - it just can't run the method. So one solution is just putting the result of the method in a local var:

def greet_first_name
  name = first_name()
  greet_with { greet(name) }
end

instance_exec actually has a built-in pattern for this. It takes arguments which it will pass to the block. This is useful if you want to use methods or instance variables, without needing to put them into local variables. We just need to adjust the greet_with method a little:

  def greet_with(*args, &block)
    Greeter.new.instance_exec(*args, &block)
  end

  def greet_first_name
    greet_with(first_name) { |name| greet(name) }
  end

This way you can be more explicit about the original lexical scope you're using.
Neither is particularly pretty, but it's not a particularly common scenario either.

@feliperaul
Copy link
Author

@shnikola Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment