Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capturing variables in Ruby methods

In CoffeeScript:

f = ->
  v = 5
  g = ->
    v
  g()

f() # returns 5 as expected

In Ruby:

def f
  v = 5
  def g
    v # undefined local variable or method `v' for main:Object (NameError)
  end
  g
end
f

Okay, so apparently JavaScript functions are set up to capture variables in the scope they are created in, but Ruby's methods are not. Is there a way to make Ruby methods behave like JavaScript functions in this regard?

like image 890
Michael Dorst Avatar asked Aug 02 '13 23:08

Michael Dorst


People also ask

What is the name of the parameter passing method used in Ruby?

In ruby, arguments inside a method are passed by referencex. upcase!

Do Ruby variables have types?

There are different types of variables in Ruby: Local variables. Instance variables. Class variables.

What is class method and variable in Ruby?

Ruby | Class Method and Variables. Class Methods are the methods that are defined inside the class, public class methods can be accessed with the help of objects. The method is marked as private by default, when a method is defined outside of the class definition. By default, methods are marked as public which is defined in the class definition.

What are variables in Ruby?

Variables are the memory locations, which hold any data to be used by any program. There are five types of variables supported by Ruby. You already have gone through a small description of these variables in the previous chapter as well. These five types of variables are explained in this chapter. Global variables begin with $.

How many parameters can a method take in Ruby?

However, Ruby allows you to declare methods that work with a variable number of parameters. In this code, you have declared a method sample that accepts one parameter test. However, this parameter is a variable parameter. This means that this parameter can take in any number of variables.

What is a method in Ruby?

Ruby - Methods. Ruby methods are very similar to functions in any other programming language. Ruby methods are used to bundle one or more repeatable statements into a single unit. Method names should begin with a lowercase letter.


1 Answers

Ruby has script scope, module/class/method definition scope and block scope. Only blocks create nested scopes. So, you need to use a block to define your method. Thankfully, there is a method for defining methods that takes a block:

def f
  v = 5
  define_method :g do
    v
  end
  g
end
f
# => 5

However, note that this does not do what you think it does (and neither does your original code). It does not define a method g nested in method f. Ruby doesn't have nested methods. Methods always belong to modules (classes are modules), they cannot belong to methods.

What this does is define a method f, which when you run it defines a method g and then calls that method.

Observe:

methods.include?(:g)
# => true

You have now defined a new top-level method (actually a private instance method of Object) called g, and you will define it over and over and over again, everytime f gets called.

What you probably want is a lambda:

def f
  v = 5
  g = -> { v }
  g.()
end
f
# => 5

In a comment to another answer you wrote:

Okay, so I'm messing around with lambdas, and I noticed that anything I do to v inside of g is not reflected in v once g returns. Is there a way I can make my changes to v stick?

def f
  v = 5
  g = -> { v = 'Hello' }
  g.()
  v
end
f
# => 'Hello'

As you can see, the change to v does "stick" after g returns.

like image 92
Jörg W Mittag Avatar answered Oct 05 '22 14:10

Jörg W Mittag