Reputation: 1710
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
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
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
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