Search code examples
rubyyieldruby-block

Variable assignment takes place in a block in a block


I first had this code, but it wasn't working:

VIM = Vimrunner::RSpec.configure do |config|
  config.reuse_server = true

  config.start_vim do
    vim = Vimrunner.start
    vim
  end
end

The configure is just a method that does the settings for a Vimrunner server. The start_vim method just depicts, what is supposed to be executed to start vim. However that doesn't really matter.

What was actually correct was:

Vimrunner::RSpec.configure do |config|
  config.reuse_server = true

  config.start_vim do
    VIM = Vimrunner.start
    VIM
  end
end

I don't quite understand this. In the first case I actually assigned a Proc to the VIM constant, as I found out through irb, whereas in the second case, the VIM constant was correctly assigned.

So it seems, I assigned the VIM constant (which lies in the global namespace) through the use of these blocks, and that's where my understanding fails me:

How I can I assign a variable in a block in a block and let that assignment be hurled back to global namespace?

How does that work? For example I tried this code:

def foo
    yield
end

foo do
    a = 'Hello World!'
    a
end

puts a

Which will show me an error. How can I have variables inside ruby blocks be put into the caller's scope?


Solution

  • You could use an instance variable if you want to access it outside? i.e. @a = 'Hello World!' and then use puts @a. Local variables are tied to the block you're in itself and thus can not be called outside.

    I'm not sure exactly what your use case is, however you should be able to use this instead

    def foo
      yield
    end
    
    foo { 'Hello World!' }
    

    or in your first case (since it's a configuration setting I'm not sure if it even matters if you need a variable to store this)

    Vimrunner::RSpec.configure do |config|
      config.reuse_server = true
      config.start_vim { Vimrunner.start }
      config
    end