-1

I would like to count method calls of new methods defined in a class. To do this, I redefine each newly defined method using method_added hook. Inside it, I use define_methodand increment the value of a class variable@@test_count`.

Base class:

class Unit
  @new_method = true
  @@test_count = 0

  def self.test_count
    puts @@test_count
  end

  def self.method_added(name)
    old_method = instance_method(name)
    if @new_method
      @new_method = false
      define_method(name) do |*args, &block|
        @@test_count += 1
        old_method.call(*args, &block)
      end
      @new_method = true
    end
  end
end

Subclass with newly defined methods:

class Test < Unit  
  def test_assertion
    puts true
  end
end

When I call a new method, @@test_count is still 0:

Test.new.test_assertion
Unit.test_count

true
0

Why @@test_count value isn't changed?

leemour
  • 11,414
  • 7
  • 36
  • 43
  • 2
    what is this @new_method? seems to be unset thus nil or false so everything else does not get executed. – engineersmnky Dec 23 '13 at 20:07
  • Also, with this code, your question is not reproducable, you've forgotten to include the method `instance_method`. – Henrik Andersson Dec 23 '13 at 20:10
  • I guess `@new_method` should have to be set `true` from the beginning, as that would allow to add new methods inside `method_added` without having an infinite recursion. `instance_method` is from the `Module` class, it returns an unbound instance method http://ruby-doc.org/core-1.9.3/Module.html#method-i-instance_method . – paradoja Dec 23 '13 at 21:04
  • Sorry, I forgot to add that line to question. It exists in my code. – leemour Dec 24 '13 at 08:52
  • Updated question with complete code. – leemour Dec 24 '13 at 09:04
  • Dup of http://stackoverflow.com/questions/20730304/use-define-method-with-method-added ? – Denis de Bernardy Dec 24 '13 at 09:42
  • @Denis, nope, it's a different question on the same code – leemour Dec 24 '13 at 11:37

1 Answers1

-1

The problem was caused by initializing class instance variable @new_method in the body of class Unit. As I was subclassing this class with Test this variable was not initialized in subclass Test. No ideas why it's like that but I solved the problem by changing if to unless thus using nil from uninitialized variable to pass the check and then assign appropriate values to it:

class Unit
  @@test_count = 0

  def self.method_added(name)
     unless @new_method
      @new_method = true
      old_method = instance_method(name)
      define_method(name) do |*args, &block|
        @@test_count += 1
        old_method.bind(self).call(*args, &block)
      end
      @new_method = false
    end
  end
end

Any ideas why class instance variable initialization isn't "inherited" in a subclass?

leemour
  • 11,414
  • 7
  • 36
  • 43