1

Is there anyway to access foo from GetVar.print_foo?

foo = "test"

module GetVar
    def self.print_foo
        puts foo
    end
end

GetVar.print_foo

I was able to get it to work by changing foo to a constant FOO, but this is more of a hack and I am looking for a better solution. I also can't, or rather prefer not, to make foo an instance variable @foo.

5
  • 1
    You could add def self.foo; "test"; end inside the module. Commented Mar 24, 2017 at 3:46
  • @CarySwoveland no, its cause I am not defining foo - which is actually 'verify_recaptcha', it is coming from another gem. I am using the recaptcha gem and I am trying to create a helper method that calls verify_recaptcha, but the helper function creates a new scope that does not have the function I need from the recaptcha gem. Commented Mar 24, 2017 at 3:50
  • @ChristianJuth A local variable is local to the current call to a method, or local to the top level binding if you define that in the top level. It cannot and should not be accessed anywhere else. Commented Mar 24, 2017 at 4:17
  • @ChristianJuth Your problem sounds like a design problem, so can you ask another question about your real problem? Commented Mar 24, 2017 at 4:19
  • @ChristianJuth : Technically, you could make foo a global variable ($foo), but don't do that unless you have very good reason to do so. As Aetherus said, this looks more like a design problem to me. Commented Mar 24, 2017 at 6:57

2 Answers 2

2

The simple answer is: no, there is no way to access the local variable foo in the script scope from the method scope of the print_foo method. foo is a local variable, local variables are local to the scope they are defined in, that's why they are called "local" variables, after all.

foo is defined in the script scope. It is not defined in the method scope of print_foo, ergo, it cannot be accessed from print_foo.

There are four local variable scopes in Ruby: script, module / class definition, method definition, and lambda literal / block body. Of these four, script scope, module / class scope, and method scope create new scopes. Lambda literals and blocks, and only those two create nested scopes that can access local variables from their surrounding lexical scopes.

So, the only way to get access to foo in print_foo is to make sure that print_foo is defined in a nested scope, i.e. in a block, and that all the surrounding scopes are also blocks. Thankfully, there is a method for defining methods called Module#define_method (or in this case actually Object#define_singleton_method) that takes a block, and there is a method for defining a module called Module::new that also takes a block:

Is there anyway to access foo from GetVar.print_foo?

foo = "test"

GetVar = Module.new do 
  define_singleton_method(:print_foo) do puts foo end
end

GetVar.print_foo
# test

Actually, we don't even need the block form of Module::new:

foo = "test"

GetVar = Module.new.tap do |m| m.define_singleton_method(:print_foo) do puts foo end end

GetVar.print_foo
# test
Sign up to request clarification or add additional context in comments.

Comments

0

Use class_eval

class A
  @foo = "test"
end
module GetVar
  def self.print_foo
      A.class_eval do
        puts @foo
      end
  end
end
GetVar.print_foo
#=> "test"

or flattening the scope

foo = "test"
GetVar = Module.new do
  # define a class method
  define_singleton_method :print_foo do
    puts foo
  end
end
GetVar.print_foo
#=> "test"

See this question: How to understand the difference between class_eval() and instance_eval()?

Comments

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.