views:

127

answers:

3

Hello there,

I'm trying to make an API for dynamic reloading processes; right now I'm at the point where I want to provide in all contexts a method called reload!, however, I'm implementing this method on an object that has some state (so it can't be on Kernel).

Suppose we have something like

WorkerForker.run_in_worker do
  # some code over here...
  reload! if some_condition
end

Inside the run_in_worker method there is a code like the following:

begin
  worker = Worker.new(pid, stream)
  block.call
rescue NoMethodError => e
  if (e.message =~ /reload!/) 
    puts "reload! was called"
    worker.reload! 
  else
    raise e
  end
end

So I'm doing it this way because I want to make the reload! method available in any nested context, and I don't wanna mess the block I'm receiving with an instance_eval on the worker instance.

So my question is, is there any complications regarding this approach? I don't know if anybody has done this already (haven't read that much code yet), and if it has been done already? Is there a better way to achieve the objective of this code?

A: 

what's wrong with doing this?

def run_in_worker(&block)
    ...
    worker = Worker.new(pid, stream)
    block.call(worker)
end

WorkerForker.run_in_worker do |worker|
    worker.reload! if some_condition
end
banister
Suppose I'm invoking methods from some other classes (like a framework), do you think is actually a good idea to pass around the worker through all the stack?... that was my first implementation until I realized that problem, thanks for your answer though
Roman Gonzalez
I don't see how that's a problem, in fact i don't even know what you mean :).
banister
Okay, let me explain myself a bit better, Suppose you want to invoke the `reload!` method in any place (like you would do when a method is part of the Kernel module). At the same time, imagine that the block that `run_in_worker` receives, we invoke a method on a class, that at the same time invokes several methods in other classes and so on. Don't you think is a bit overkilling to pass the worker instance through all this different methods as a parameter just to invoke `worker.reload!`?
Roman Gonzalez
A: 

It sounds like you just want every method to know about an object without the method or the method's owner having been told about it. The way to accomplish this is a global variable. It's not generally considered a good idea (because it leads to concurrency issues, ownership issues, makes unit testing harder, etc.), but if that's what you want, there it is.

Chuck
mightn't another approach, to avoid using globals, be to create the method using `define_method` and close over the object that needs to be shared between instances
banister
+1  A: 

Assuming i understand you now, how about this:

my_object = Blah.new
Object.send(:define_method, :reload!) { 
    my_object.reload!
    ...
}

Using this method every object that invokes the reload! method is modifying the same shared state since my_object is captured by the block passed to define_method

banister
Great... the use of closures on the `reload!` method is a really elegant way to solve this problem, thanks banister.
Roman Gonzalez