Victor Victor - 1 month ago 19
Ruby Question

Ruby: Extended instance variables

How can I set some instance variables when

extend
ing a instance in the same way it can be done when creating it, with
initialize
.

In this example the variable set when extending is "lost":

module Mod
def self.extended(base)
@from_module = "Hello from Mod"
puts "Setting variable to: #{@from_module}"
end

def hello_from_module
return @from_module
end
end

class Klass
def initialize
@from_class = "Hello from Klass"
end

def hello_from_class
return @from_class
end
end

klass = Klass.new #=> #<Klass:0x00000000ed8618 @from_class="Hello from Klass">
klass.extend(Mod) #=> #<Klass:0x00000000ed8618 @from_class="Hello from Klass">
"Setting variable to: Hello from Mod"

klass.hello_from_class #=> "Hello from Klass"
klass.hello_from_module #=> nil (warning: instance variable @from_module not initialized)

Answer

There are a number of ways to do what you describe.

The most common one would be to use instance_variable_get and instance_variable_set:

module ModA
  def self.extended(base)
    base.instance_variable_set(:@from_module, "Hello from Mod A")
    puts "Setting variable to: #{base.instance_variable_get(:@from_module)}"
  end

  def hello_from_module
    return @from_module
  end
end

Another common technique is to use any of the eval or exec methods. In this case instance_exec:

module ModB
  def self.extended(base)
    base.instance_exec { @from_module = "Hello from Mod B" }
    puts "Setting variable to: #{base.instance_exec { @from_module }}"
  end

  def hello_from_module
    return @from_module
  end
end