In Ruby How to Create a Local Variable Explicitly

In Ruby is it possible to create a local variable explicitly

As per the Perl documentation of my,I think you are looking for something like below in Ruby:-

x = 123 
p = Proc.new {|;x|
x = 'I do not want change the value of the outer x, I want to create a local x'
}
p.call
# => "I do not want change the value of the outer x, I want to create a local x"
x # => 123

Dynamically set local variables in Ruby

The problem here is that the block inside each_pair has a different scope. Any local variables assigned therein will only be accessible therein. For instance, this:

args = {}
args[:a] = 1
args[:b] = 2

args.each_pair do |k,v|
key = k.to_s
eval('key = v')
eval('puts key')
end

puts a

Produces this:

1
2
undefined local variable or method `a' for main:Object (NameError)

In order to get around this, you could create a local hash, assign keys to this hash, and access them there, like so:

args = {}
args[:a] = 1
args[:b] = 2

localHash = {}
args.each_pair do |k,v|
key = k.to_s
localHash[key] = v
end

puts localHash['a']
puts localHash['b']

Of course, in this example, it's merely copying the original hash with strings for keys. I'm assuming that the actual use-case, though, is more complex.

Local Variables and Methods with Ruby

The variable a is not defined within the scope of the insert method.

There are several types of variables in ruby, which can be summarised by the following table:

$            A global variable
@ An instance variable
[a-z] or _ A local variable
[A-Z] A constant
@@ A class variable

In order for your code to work, you could either define a as a global variable (although this is generally considered bad practice!):

$a = [1,2,3,4,5]

puts "Pick number to insert into array:"
answer = gets.chomp()

def insert(answer)
$a.insert(1, answer)
end

insert(answer)

Or, you could define a within the scope of the method:

puts "Pick number to insert into array:"
answer = gets.chomp()

def insert(answer)
a = [1,2,3,4,5]
a.insert(1, answer)
end

insert(answer)

Or, you could pass a into the method as a parameter:

puts "Pick number to insert into array:"
answer = gets.chomp()

def insert(a, answer)
a.insert(1, answer)
end

a = [1,2,3,4,5]
insert(a, answer)

Or, you could define a class and make a an instance variable of that class - for example, something like:

class HelloWorld
attr_reader :a
def initialize
@a = [1,2,3,4,5]
end

def insert(answer)
@a.insert(1, answer)
end
end

puts "Pick number to insert into array:"
answer = gets.chomp()

my_awesome_object = HelloWorld.new
my_awesome_object.insert(answer)
puts my_awesome_object.a

Local variables and methods with the same name in Ruby?

In ruby you can have local variables and methods with the same name. This has some complications for example with setter methods in classes:

class Test
def active
@active
end

def active=(value)
@active = value
end

def make_active
active = true
end
end

t1 = Test.new
t1.active = true
t1.active #=> true

t2 = Test.new
t2.make_active
t2.active #=> nil

Code for t1 object will return expected result, but code for t2 returns nil, because make_active method is actually creating local variable and not calling active= method. You need to write self.active = true to make this work.

When you write gen_class, ruby tries to access local variable, if it is not defined ruby tries to call method. You can call your method explicit by writing gen_class().

how to use truly local variables in ruby proc/lambda

Sometimes it is the desired behavior:

total = 0
(1..10).each{|x| total += x}
puts total

But sometimes it's accidental and you don't want to mess with an outside variable which happens to have the same name. In that case, follow the list of parameters with a semicolon and a list of the block-local variables:

x = lambda{|v; x| x = 2; v}
p x.call(3) #3
p x #<Proc:0x83f7570@test1.rb:2 (lambda)>

Ruby loop local variables and inmutability

each loops often mutate the object. Each has to do something.
Because each doesn't return anything useful - it returns the array itself, It won't mutate the object if it sends every element somewhere, like to be printed on screen.

foo.each do |bar|
# do something with element like
# print it, change it, save it
end

Functional alterantive is map

foo.map { |bar| bar.something }

It returns new array which is original array processed in immutable way. Obviously you have to be careful to use immutable methods. This would not be immutable:

foo.map { |bar| bar.something! } 

Here something! does something destructive to the element of array.
However I have never seen map used like that. Use each for something destructive.

listing the local variables in irb

Your code is really complicated and obfuscated. First, let's clean up your code a bit so that we can see more clearly what's going on. You don't need self, since it is the default receiver anyway. And you don't need send, because you already know the name of the method you want to call. Also, Kernel#local_variables uses the current Binding anyway. Also, typically, such methods which are supposed to by called without an explicit receiver and don't actually make use of self (e.g. like puts or require) are put into Kernel. So, your code is equivalent to the following:

module Kernel
def list_vars
local_variables.map {|var| "#{var} = " + binding.local_variable_get(var).inspect}
end
end

Now we can immediately see the problem: you are reflecting on the local variables and the Binding of list_vars and not the place where it was called from! You need to pass the Binding into the method and use that instead:

module Kernel
def list_vars(binding)
binding.local_variables.map {|var| "#{var} = " + binding.local_variable_get(var).inspect}
end
end

list_vars(binding)

Or, you could make it an instance method of Binding:

class Binding
def list_vars
local_variables.map {|var| "#{var} = " + local_variable_get(var).inspect}
end
end

binding.list_vars


Related Topics



Leave a reply



Submit