In Ruby, How to Get Instance Variables in a Hash Instead of an Array

In Ruby, how can I get instance variables in a hash instead of an array?

To create a hash of all instance variables you can use the following code:

class Object
def instance_variables_hash
Hash[instance_variables.map { |name| [name, instance_variable_get(name)] } ]
end
end

But as cam mentioned in his comment, you should use instance_variable_get method instead:

object.instance_variable_get :@my_instance_var

Make instance variable accessible through hash in Ruby

It's not "through Hash", it's "array access" operator.

To implement it, you need to define methods:

def [](*keys)
# Define here
end

def []=(*keys, value)
# Define here
end

Of course, if you won't be using multiple keys to access an element, you're fine with using just key instead of *keys, so that you have not an array of keys (even if only one is given), but just a single key.

Plenty of other classes implement it, namely Structs, so you're free to pick an existing implementation or roll out your own.

Getting instance variables to be affected by these methods means implementing them using instance_variable_get/instance_variable_set. Nothing fancy.

Accessing an object's instance variable from an array

accounts is an array. So you have to access one of its elements' account_number instance variable. For example the first element's:

# accounts[0] would return an instance of `AccountMaker `
accounts[0].instance_variable_get(:account_number)

Also, you don't need to use instance_variable_get, since you already declared it as accessor. So, you can just call account_number method on it.

accounts[0].account_number

Convert hash params into instance variables on Ruby initializer

I want to do this in a clean way.

You won't get attr_accessors and instance variables without defining them. The below is using some simple metaprogramming (does it qualify for "clean"?)

class PriceChange
def initialize(data = {})
data.each_pair do |key, value|
instance_variable_set("@#{key}", value)
self.class.instance_eval { attr_accessor key.to_sym }
end
end
end

Usage:

price_change = PriceChange.new(foo: :foo, bar: :bar)
#=> #<PriceChange:0x007fb3a1755178 @bar=:bar, @foo=:foo>
price_change.foo
#=> :foo
price_change.foo = :baz
#=> :baz
price_change.foo
#=> :baz

Calculating a map of instance variables

This works of course, but I wonder whether there isn't a simpler way to achieve the same result.

There are some slight simplifications that you could do:

  • Use Array#to_h instead of Hash::[].
  • Use Array#zip.
  • Use point-free style using Object#method or something like the method reference operator if that is ever added to Ruby.
module M
def self.ivar_map
instance_variables.zip(instance_variables.map(&method(:instance_variable_get))).to_h
end
end

or with the experimental (and removed again in 2.7.0-preview3) method reference operator:

module M
def self.ivar_map
instance_variables.zip(instance_variables.map(&self.:instance_variable_get)).to_h
end
end

After all, Ruby somehow has to maintain such a symbol table already, mapping the variables to their content.

Actually, that is not true. Several Ruby Implementations (including YARV, the most widely-used one) optimize instance variables to some extent. E.g. I believe YARV stores up to three instance variables in the object header directly, without using an instance variable table.

And YARV is on the more simple side when it comes to optimizations. Other implementations like Rubinius, JRuby, TruffleRuby, and RubyOMR perform much more sophisticated optimizations.

Quickly setting instance variables with options hash in Ruby?

def initialize(opts={})
opts.each { |k,v| instance_variable_set("@#{k}", v) }
end

How to get all instances variables in ruby class?

You can use instance_variables to collect them in an Array. You will get all initialized instance variables.

class MyClass
attr_accessor :name1
attr_accessor :name2
...
attr_accessor :namen

def inner_func():
all_vars = instance_variables
res = out_func(all_vars)
do_more_stuff(res)
end
end

What is an elegant way in Ruby to tell if a variable is a Hash or an Array?

You can just do:

@some_var.class == Hash

or also something like:

@some_var.is_a?(Hash)

It's worth noting that the "is_a?" method is true if the class is anywhere in the objects ancestry tree. for instance:

@some_var.is_a?(Object)  # => true

the above is true if @some_var is an instance of a hash or other class that stems from Object. So, if you want a strict match on the class type, using the == or instance_of? method is probably what you're looking for.

can I pass a hash to an instance method to create instance variables?

Sure you can do something like this in your initialize method:

     hash.each do |k, v|
instance_variable_set("@#{k}", v)
self.class.send(:attr_reader, k)
end

Here's an example using your input hash:

class Reminder
def initialize(hash)
hash.each do |k, v|
instance_variable_set("@#{k}", v)
self.class.send(:attr_reader, k)
end
end
end

reminder_hash = {"bot_client_id"=>"test-client-id", "recurring"=>true, "recurring_natural_language"=>"everyday", "time_string"=>"10AM", "time_zone"=>"America/Los_Angeles", "via"=>"slack", "keyword"=>"test-keyword", "status"=>"active", "created_time"=>1444366166000}

reminder = Reminder.new(reminder_hash)
puts reminder

puts reminder.bot_client_id

Output:

#<Reminder:0x007f8a48831498>
test-client-id


Related Topics



Leave a reply



Submit