Akshay Vishnoi
Akshay Vishnoi

Reputation: 593

Get all instance variables declared in class

Please help me get all instance variables declared in a class the same way instance_methods shows me all methods available in a class.

class A
  attr_accessor :ab, :ac
end

puts A.instance_methods  #gives ab and ac

puts A.something         #gives me @ab @ac...

Upvotes: 59

Views: 51840

Answers (6)

Cody Elhard
Cody Elhard

Reputation: 11

If you run byebug you can run simply run instance_variables to get the list generated at runtime.

Might be a new feature. Running ruby 3.2.2

Upvotes: 0

David Hempy
David Hempy

Reputation: 6237

Building on the answer from @Obromios , I added .to_h and .to_s to a class to allow for pleasant, flexible dumping of attributes suitable for display to an end user.

This particular class (not an ActiveRecord model) will have a variety of attributes set in different situations. Only those attribs that have values will appear when printing myvar.to_s, which was my desire.

class LocalError
  attr_accessor :product_code, :event_description, :error_code, :error_column, :error_row 

  def to_h
    instance_variables.map do |attribute|
      key = attribute.to_s.gsub('@', '')
      [key, self.instance_variable_get(attribute)]
    end.to_h
  end

  def to_s
    to_h.to_s
  end
end

This allows me to put this simple code in a mailer template:

Data error:   <%= @data_error %>

And it produces (for example):

Data error:   {"event_description"=>"invalid date", "error_row"=>13}

This is nice, as the mailer doesn't have to be updated as the LocalError attributes change in the future.

Upvotes: 0

Obromios
Obromios

Reputation: 16373

If you want to get a hash of all instance variables, in the manner of attributes, following on from Aschen's answer you can do

class A
  attr_accessor :foo, :bar

    def attributes
    self.instance_variables.map do |attribute|
      key = attribute.to_s.gsub('@','')
      [key, self.instance_variable_get(attribute)]
    end.to_h
  end
end
a = A.new
a.foo = "foo"
a.bar = 42
a.context #=> {'foo' => 'foo', 'bar' => 42}

Upvotes: 1

Adam Strickland
Adam Strickland

Reputation: 11

It's not foolproof - additional methods could be defined on the class that match the pattern - but one way I found that has suited my needs is

A.instance_methods.grep(/[a-z_]+=/).map{ |m| m.to_s.gsub(/^(.+)=$/, '@\1') }

Upvotes: 1

Aschen
Aschen

Reputation: 1771

If you want to get all instances variables values you can try something like this :

class A
  attr_accessor :foo, :bar

  def context
    self.instance_variables.map do |attribute|
      { attribute => self.instance_variable_get(attribute) }
    end
  end
end

a = A.new
a.foo = "foo"
a.bar = 42
a.context #=> [{ :@foo => "foo" }, { :@bar => 42 }]

Upvotes: 18

Andrew Marshall
Andrew Marshall

Reputation: 96934

You can use instance_variables:

A.instance_variables

but that’s probably not what you want, since that gets the instance variables in the class A, not an instance of that class. So you probably want:

a = A.new
a.instance_variables

But note that just calling attr_accessor doesn’t define any instance variables (it just defines methods), so there won’t be any in the instance until you set them explicitly.

a = A.new
a.instance_variables #=> []
a.ab = 'foo'
a.instance_variables #=> [:@ab]

Upvotes: 88

Related Questions