4

How can I add a bunch of instance variables from one object to another?

For example, imagine robots where you have the base robot and you can customize it with add-ons.

class Robot

   def initialize
      @name = "simple robot"
      @power = nil #no power
      @speed = nil
      # more attributes
   end

   def add_attributes(addon)
      @power = addon.power
      @speed = addon.speed
      #the rest of the attributes that addon has
   end
end

I would like to re-write the add_attributes method to simply iterate over each of the addon's attributes instead of writing them all one by one, cause there could be dozens of attributes.

Some addons may have instance variables that Robot doesn't have, and I would also like to add them to Robot. Like creating instance variables on the fly?

3 Answers 3

8

It depends on what you mean by "attribute"; Ruby doesn't have that concept directly but you could copy instance variables from one object to another as such:

def add_attributes(addon)
  addon.instance_variables.each do |x|
    self.instance_variable_set(addon.instance_variable_get(x))
  end      
end

[Edit] Note that the answer by @HolgerJust is also a good solution.

Sign up to request clarification or add additional context in comments.

1 Comment

I really don't like the peering into addon's instance variables like this. An addon should really provide a uniform way of getting a list of its attributes, and then that method could be called on it. (Of course, with the given information, what you have is probably the best solution.)
6

You could get rid of the instance variables and use a single hash instead. This has the advantage of a free enumerator and a clean interface to access all the features a robot has from one convenient place.

It also avoids having to mess with an instances internal variables. They are typically intended to be internal and are used for a vast amount of stuff. If you want to expose functionality, you should do it with a public method. Messing with internal state is at least bad design and will most probably lead to much grief later on. Generally, it's best to avoid meta-programming wherever possible.

class Robot
  attr_reader :features

  def initialize
    @features = {}
    @features[:name] = "simple robot"
    @features[:power] = nil #no power
    @features[:speed] = nil
  end

  def add_attributes(addon)
    @features.merge! addon.features
  end
end

1 Comment

Using Hash#merge instead of iterating over the addon parameter would clean up the add_attributes method.
0

You could use the flexible gem[0] which lets you create instance variables on the fly without writing much code. Just do

class SomeClass
  include Flexible
end
sc = SomeClass.new
sc.my_variable_name = 1 # or any other value

[0] https://github.com/matthiasbeyer/flexible

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.