Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby turn values inside a hash into local variables

Tags:

Say I have this hash:

entry = {"director"=>"Chris Nolan", "producer"=>"Sum Duk", "writer"=>"Saad Bakk"} 

I want to extract each key into its own local variable with the associated value:

director = "Chris Nolan" producer = "Sum Duk" ... 

By using a loop and not:

director = entry["director"] 

Since there are a lot of values and I don't want to do them individually.

I found this which works almost perfectly except it creates an instance variable and I want a local variable, but local_variable_set doesn't exist for some reason.

entry.each_pair { |k, v| instance_variable_set("@#{k}", v) } 

Is there a solution? Or failing that, a way to turn an instance variable into a local one and delete the instance one without doing it one by one?

like image 793
kakubei Avatar asked Nov 14 '12 15:11

kakubei


People also ask

How do I get the hash value in Ruby?

In Ruby, a hash is a collection of key-value pairs. A hash is denoted by a set of curly braces ( {} ) which contains key-value pairs separated by commas. Each value is assigned to a key using a hash rocket ( => ). Calling the hash followed by a key name within brackets grabs the value associated with that key.

How do I iterate a hash in Ruby?

Iterating over a Hash You can use the each method to iterate over all the elements in a Hash. However unlike Array#each , when you iterate over a Hash using each , it passes two values to the block: the key and the value of each element.

How do you iterate through a hash?

When we iterate over a hash, the #each method (as well as any other iteration method you use) yields the key/value pair together into the block. Inside that block, you have access to the key and the value, and can manipulate either one or both. Inside the iteration we have access to both the key and the value.


2 Answers

Option 1

I can't recommend this except for fun, but it mostly has the effect you are after:

entry.each |k, v|   singleton_class.send(:attr_accessor, k)   send("#{k}=", v) end  director                        # => "Chris Nolan" self.director = "Wes Anderson"  # Unfortunately, must use self for assignment director                        # => "Wes Anderson" 

Instead of creating local variables it defines acccessor methods on the singleton class of the current object, which you can call as if they were local variables.

To make them more "local" you could use singleton_class.remove_method to remove these methods when you are done with them. You could even try to alias any existing singleton class methods with the same name and restore them afterwards.

Option 2

This is something I use in real code. It requires the ActiveSupport gem which comes with Ruby On Rails but can also be used on its own.

director, producer, writer = entry.values_at('director', 'producer', 'writer') 

Unfortunately it requires typing each variable name twice, instead of zero times as you asked for. If you were certain about the order of the values in the hash, you could write:

director, producer, writer = entry.values  # Not so good, IMO. 

I feel uneasy about this version because now the code that created the hash has a non-obvious responsibility to ensure the hash is in a certain order.

Note

If your goal is just to reduce typing, here is an approach that only requires two more characters per variable access than if they were true local variables:

e = OpenStruct.new(entry) e.director     # => "Chris Nolan" 
like image 190
antinome Avatar answered Oct 05 '22 06:10

antinome


You can't create local variables, because of variable scope.
If you create a local variable inside a block, the variable would be only accessible inside the block itself.
Please refer to this question for more info.
Dynamically set local variables in Ruby

like image 27
MurifoX Avatar answered Oct 05 '22 07:10

MurifoX