Rajagopalan
Rajagopalan

Reputation: 6064

An unexpected result was encountered when invoking the instance_methods method, resulted in the return of an empty array

Please consider the below code

class Execute
  def self.inherited(klass)
    puts "Class Inherited: #{klass}"
    klass.run
  end

  def self.run
    puts "Running Instance Methods"
    instance_methods(false).each do |m|
      if m.to_s.start_with?("test_")
        puts "Executing Method: #{m}"
        new.send(m)
      end
    end
  end
end

puts "Before class definition"

class Raja < Execute
  def test_1
    puts 'test_1'
  end

  def test_2
    puts 'test_2'
  end

  def test_3
    puts 'test_3'
  end
end

puts "After class definition"

I am currently making an attempt to access the test_1, test_2, and test_3 methods by instantiating an object from the parent class. Upon examination of the program, one may comprehend the actions I am performing. Nonetheless, the issue arises as the invocation of the instance_methods method returns an empty array, contrary to its expected behavior of providing the names of the instance methods, i.e., test_1, test_2, and test_3. I am at a loss as to why this discrepancy is occurring and would greatly appreciate any assistance in resolving this issue

Upvotes: 1

Views: 101

Answers (1)

engineersmnky
engineersmnky

Reputation: 29598

Class#inherited is called at the moment of inheritance. At this point no instance_methods (non-inherited instance methods since you used false) have been defined.

class Raja < Execute #inherited is called here 
 # methods are defined here
end

It would be similar to the following

class Raja;end 
Raja.instance_methods(false) #=> []
class Raja
  def test_1 = 'test1'
end

You could possibly look into Module#method_added instead however I am unclear on what the reasoning behind this code is so all I can do is answer the question of Why you are experiencing what you you are experiencing.

Update Based on OP comments looking for an auto run mechanism similar to test-unit:

As a very simplified Example:

class Tracker
  @@runner = {} 
  def self.runner
    @@runner
  end 
  def self.inherited(klass) 
    runner[klass] = [] 
  end 
  def self.method_added(method_name)
    runner[self] << method_name if method_name.match?(/test_/)
  end 
end 

class Runner 
 def self.run
    Tracker.runner.each do |klass,tests|
      tests.each do |m| 
        klass.new.send(m)
      end 
    end 
  end
end 
# Run the Runner before the program exits
at_exit { Runner.run}

Then (foo.rb)

require 'runner_tracker'
class Foo < Tracker 
  def test_1
    puts 'test_1'
  end

  def test_2
    puts 'test_2'
  end

  def test_3
    puts 'test_3'
  end
end 

Output

> ruby foo.rb
test_1
test_2
test_3

Upvotes: 3

Related Questions