Home > Software design >  Is it possible to set instance variables on class methods that are only visible to the current metho
Is it possible to set instance variables on class methods that are only visible to the current metho

Time:05-03

Lets say I have the following:

class MyClass
    class << self
        def call(req_id)
            @request_id = req_id
            method_1
            method_2
        end
        
        def method_1
            puts "method 1 - req id: #{@request_id}"
            sleep(@request_id)
        end
        
        def method_2
            puts "method 2 - req id: #{@request_id}"
        end
    end
end

def func3
    MyClass.call(6)
end

def func4
    MyClass.call(2)
end

t1 = Thread.new{func3()}
sleep(1)
t2 = Thread.new{func4()}
t1.join
t2.join

And this produces the following output:

method 1 - req id: 6
method 1 - req id: 2
method 2 - req id: 2
method 2 - req id: 2

This makes sense since the class instance variable request_id gets changed by func4. But is there a way that we can make request_id specific only to it's own thread such that we get the following result:

method 1 - req id: 6
method 1 - req id: 2
method 2 - req id: 2
method 2 - req id: 6

I can accomplish this by straight up passing req_id to func3 and func4 but would like to avoid that if possible.

Is this possible to do by using instance vars?

CodePudding user response:

You can use instance methods

Just create instances in class method

Like this as idea

class MyClass
  class << self
    def call(req_id)
      new(req_id).call
    end
  end

  def call
    method1
    method2
  end

  private

  def initialize(req_id)
    @request_id = req_id
  end

  def method1
    puts "method 1 - req id: #{@request_id}"
    sleep(@request_id)
  end

  def method2
    puts "method 2 - req id: #{@request_id}"
  end
end

def func3
  MyClass.call(6)
end

def func4
  MyClass.call(2)
end

t1 = Thread.new { func3 }

sleep(1)

t2 = Thread.new { func4 }

t1.join
t2.join
# will print
method 1 - req id: 6
method 1 - req id: 2
method 2 - req id: 2
method 2 - req id: 6

CodePudding user response:

Only with dirty tricks: You could create the variable, and it will then be visible to the methods you are calling, but before you return from your "root" method, you have to destroy the variable again (using remove_instance_variable), lest it would continue to exist for the lifetime of this object.

For the same reason, you have to be careful with exceptions. Therefore I would place the remove_instance_variable into an ensure clause, to make sure that it is executed even if the method is left prematurely by an exception.

However it may be better tor rethink your design. Instead of creating and destroying instance variables on the fly, consider creating them in the constructor and set them to nil initially. Instead of removing the variable, set it to nil again.

  • Related