Пожалуйста, рассмотрите приведенный ниже код
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"
В настоящее время я пытаюсь получить доступ к методам test_1, test_2 и test_3, создавая экземпляр объекта из родительского класса. Изучив программу, можно понять действия, которые я выполняю. Тем не менее проблема возникает, поскольку вызов метода instance_methods возвращает пустой массив, в отличие от его ожидаемого поведения при предоставлении имен методов экземпляра, т. е. test_1, test_2 и test_3. Я не понимаю, почему это несоответствие происходит, и был бы очень признателен за любую помощь в решении этой проблемы.
Class#inherited вызывается в момент наследования.
На данный момент никакие instance_methods
(методы экземпляра, не унаследованные с тех пор, как вы использовали false
) не определены.
class Raja < Execute #inherited is called here
# methods are defined here
end
Это будет похоже на следующее
class Raja;end
Raja.instance_methods(false) #=> []
class Raja
def test_1 = 'test1'
end
Вместо этого вы могли бы заглянуть в Module#method_added, однако мне неясно, в чем причина этого кода, поэтому все, что я могу сделать, это ответить на вопрос, почему вы испытываете то, что испытываете.
Обновлять
Основываясь на комментариях OP, ищущих механизм автозапуска, похожий на test-unit
:
В качестве очень упрощенного примера:
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}
Затем (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
Выход
> ruby foo.rb
test_1
test_2
test_3
@Rajagopalan Я объяснил, почему, потому что это то, о чем вы просили. Библиотека, на которую вы ссылаетесь, намного сложнее, чем ваш пример, и не имеет абсолютно ничего общего с унаследованным хуком, кроме отслеживания потомков класса Test::Unit::TestCase
, и, как я уже упоминал, сильно использует method_added, но даже это не то, что на самом деле «работает». " код...
Эй, я видел вашу отредактированную программу, вы на самом деле более или менее достигли того, о чем я просил, за исключением одного. В Test::Unit::TestCase наследования этого Test::Unit::TestCase
достаточно, нам не нужно вызывать что-то вроде Runner.run
. Кроме этого, вы добились всего, отлично. Спасибо.
@Rajagopalan использует простой хук at_exit
для «автоматического запуска». См. Здесь вы можете легко реализовать это (обновленный пост), хотя я тоже делал пост о выходе из хуков некоторое время назад: stackoverflow.com/a/48565962/1978251
Большое спасибо. Это то, чего я хочу достичь.
Вы объясняете, почему так. Но моя цель — вызвать метод, который начинается с «test_», когда я запускаю вышеуказанную программу. Такая конфигурация доступна, когда мы наследуем Test::Unit::TestCase в нашем классе. Поэтому я хочу знать, как они этого добились. Его жемчужина под названием test-unit предоставляет эту возможность.