mybuddymichael
mybuddymichael

Reputation: 1710

How do I pass a Ruby local variable from a method to a sub-method?

Given this simple Ruby code:

def testMethod
  testVar = 1
  def subTestMethod
    if testVar == 1
      puts 'Yes'
    else
      puts 'No'
    end
  end
  subTestMethod
end

testMethod

Is there any way to pass the local testVar variable to the sub-method without being forced to use a class variable?

Upvotes: 3

Views: 1505

Answers (3)

Jörg W Mittag
Jörg W Mittag

Reputation: 369624

In Ruby, only blocks (and lambda literals) can be closures. So, you'll have to use a block to define the method:

def testMethod
  testVar = 1
  Object.send(:define_method, :subTestMethod) do
    if testVar == 1
      puts 'Yes'
    else
      puts 'No'
    end
  end
  subTestMethod
end

testMethod

As others have already pointed out, whether or not this does what you think it does depends of course on exactly what you think it does, but most likely, it doesn't.

Just a couple of style tips: methods and (non-constant) variables follow a snake_case naming convention, you use empty lines to separate initialization from the actual work and the return value, and everything is an expression.

So, your testMethod, subTestMethod and testVar should rather be named test_method, sub_test_method and test_var. There should be an empty line before define_method and before sub_test_method. And you can pull the puts outside of the if expression, since, well it is an expression and thus returns its value:

def test_method
  test_var = 1

  Object.send(:define_method, :sub_test_method) do
    puts(if test_var == 1 then 'Yes' else 'No' end)
  end

  sub_test_method
end

test_method

What you probably rather want is a lambda:

def test_method
  test_var = 1

  sub_test_lambda = -> { puts(if test_var == 1 then 'Yes' else 'No' end) }

  sub_test_lambda.()
end

test_method

Upvotes: 5

sepp2k
sepp2k

Reputation: 370465

The code you have, very likely does not do what you want:

The inner def in your code does not define a local method. Instead it defines subTextMethod as a global method in the Object class as soon as testMethod is called for the first time. That means that after you call testMethod, you'll be able to call subTestMethod from anywhere.

The fact that subTestMethod is not local to testMethod of course also means that subTestMethod can't close over testMethod's local variables.

To get the behaviour you want, you might want to use a lambda like this (or rethink your design so that you don't need any nested functions):

def testMethod
  testVar = 1
  subTestLambda = lambda do
    if testVar == 1
      puts 'Yes'
    else
      puts 'No'
    end
  end
  subTestLambda.call
end

Upvotes: 8

Chandra Patni
Chandra Patni

Reputation: 17587

Pass testVar as a parameter to subTestMethod

def testMethod
  testVar = 1
  def subTestMethod(testVar)
    if testVar == 1
      puts 'Yes'
    else
      puts 'No'
    end
  end
  subTestMethod testVar
end

Upvotes: 1

Related Questions