tags:

views:

79

answers:

1
class A
  do_something_from_b

  def method_in_a
  end
end

module B
  def self.included base
    base.extend ClassMethods
  end

  module ClassMethods
    def do_something_from_b
      A.class_eval do
        alias_method :aliased_method_in_a, :method_in_a
      end
    end
  end
end

A.send(:include, B)

That code will fail because when do_somethind_from_b gets called, method_in_a doesn't exist yet.

So is there a way to hook into class A after it has been fully loaded, without putting the do_something_from_b call at the end of class A?

Edit: As pointed out, there's other stuff wrong with the code, but that's beside the point. I just want to illustrate what I want to accomplish, which is run some code after a class is closed (it doesn't matter that it can be re-opened at will). And now I know that's probably not possible.

Thanks!

+1  A: 

In Ruby a class is never fully loaded. You can reopen it whenever you want to.

class A
  def method_in_a
    …
  end
end

You can do later, no matter where your code is (even in another source code file).

class A
  alias :aliased_method_in_a :method_in_a
end

or you could do it the way you wrote it (which is exactly the same as the previous code)

A.class_eval do
  alias :aliased_method_in_a :method_in_a
end

As you pointed out A#method_in_a must exist at the time you alias it. To ensure this is true you could do

require "file_of_class_a"

before you do the alias. If you do not know when the method A#method_in_a will be created you could do

class A
  def self.method_added(name)
    alias :aliased_method_in_a :method_in_a if name == :method_in_a
  end
end

A.method_added gets automaticly called whenever a method in A gets defined.

johannes
johannes, I can't thank you enough. That method is extremely useful. I suspect it can be a performance hit, but let's hope it's not too great.By the way, I don't know what happens with a "plain" alias, but I'm using Rails' alias_method_chain, which triggers method_added in an infinite loop, so I had to use a class variable to see whether the method had already been aliased.
Ivan
And here's a bit more information about method_added: http://blog.sidu.in/2007/12/rubys-methodadded.html
Ivan
I tested it with plain alias, and no recursion occured.
johannes