Как вызвать любой метод экземпляра в объекте ruby ​​без его создания?

Я создаю вспомогательный модуль для инициализации объекта перед вызовом его методов.

module Initialized
  extend ActiveSupport::Concern

  class_methods do
    def run(*args)
      new(*args).run
    end

    def call(*args)
      new(*args).call
    end

    def execute(*args)
      new(*args).create
    end
  end
end

Поэтому вместо определения run, call и execute в моем вспомогательном модуле мне нужно получить имя любого метода и проверить, существует ли он в основном классе после его инициализации, а затем вызвать запрошенный метод экземпляра, если он существует в основной класс или вызвать ошибку, если нет

Я бы сказал, что мой целевой код будет примерно таким

module Initialized
  extend ActiveSupport::Concern
  class_methods do
    def _(*args, methodname)
      new(*args).try(:send, "#{methodname}") || raise 'Method not exist'
    end
  end
end

Пример использования будет

class MyClass
  include Initialized

  def initialize(param1)
    @param1 = param1
  end

  def call
    puts "call '#{@param1}'"
  end
end

затем звоню

MyClass.call('method param')

Я нашел эти ссылки, но еще не нашел свой ответ:

meta-dynamic-generic-programming-in-ruby

ruby-module-that-delegates-methods-to-an-object< /а>

template-methods-in-ruby


person adabo    schedule 31.08.2020    source источник
comment
Это может вам помочь - stackoverflow.com/questions/61927012/   -  person user11350468    schedule 31.08.2020
comment
@user11350468 user11350468 спасибо за ваш комментарий, но моя проблема заключается в том, как мне получить object.any_method_name() и выполнить его   -  person adabo    schedule 31.08.2020
comment
method_missing это обычный способ сделать это...   -  person max pleaner    schedule 31.08.2020


Ответы (2)


Несмотря на то, что method_missing справился бы с задачей, в данном случае я бы, вероятно, избегал его в пользу более явного делегирования. Простой и грязный пример:

module InstanceDelegator
  def delegate_to_instance(*methods)
    methods.each do |method_name|
      define_singleton_method method_name do |*args|
        new(*args).public_send(method_name)
      end
    end
  end
end

class Foo
  extend InstanceDelegator

  delegate_to_instance :bar # <- define explicitly which instance methods
                            # should be mirrored by the class ones

  def bar
    puts "bar is called"
  end

  def baz
    puts "baz is called"
  end
end

# and then

Foo.bar #  => bar is called
Foo.baz # NoMethodError ...

# reopening works too
class Foo
  delegate_to_instance :baz
end

Foo.baz # baz is called

Плюсы:

  1. вам не нужно переопределять method_missing (меньше магии -> меньше боли при отладке кода)
  2. вы точно контролируете, какие методы экземпляра должны быть обернуты с помощью сокращения уровня класса (меньше шансов делегировать то, что вы не хотите - более надежный код)
  3. (второстепенное) нет необходимости явно вызывать NoMethodError - вы можете полностью полагаться на диспетчеризацию ядра, как она есть...
person Konstantin Strukov    schedule 31.08.2020
comment
Хорошее решение, мне нравится - person adabo; 01.09.2020

Я нашел лучшее решение вместо использования модуля, я могу использовать метод класса self.method_missing

def self.method_missing(method_name, *args, &block)
  obj = new(*args)
  raise NoMethodError, "undefined method `#{method_name}' for #{self}:Class" unless obj.respond_to?(method_name)
  obj.send(method_name, &block)
end

Но ограничение в том, что я должен копировать его в каждый класс всякий раз, когда мне нужно использовать эту функцию.

person adabo    schedule 31.08.2020
comment
Спасибо max за comment - person adabo; 01.09.2020