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.

sawa
  • 165,429
  • 45
  • 277
  • 381
Jon Doe
  • 2,172
  • 1
  • 18
  • 35
  • 1
    You could add `def self.foo; "test"; end` inside the module. – Cary Swoveland Mar 24 '17 at 03: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. – Jon Doe Mar 24 '17 at 03: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. – Aetherus Mar 24 '17 at 04:17
  • @ChristianJuth Your problem sounds like a design problem, so can you ask another question about your real problem? – Aetherus Mar 24 '17 at 04: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. – user1934428 Mar 24 '17 at 06:57

2 Answers2

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
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
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()?

Fangxing
  • 5,716
  • 2
  • 49
  • 53