Переопределение метода singleton_class, чтобы он вел себя точно так же, как он вел себя раньше, но также делал что-то еще

#ruby

#ruby

Вопрос:

Я хочу изменить метод singleton_class определенного класса, чтобы он выполнял то же самое, что и раньше, но также делал что-то еще, например, помимо того, что он делал, для выполнения:

  • помещает «привет»

Хорошо, итак, я знаю, как переопределить обычный метод класса, чтобы он фактически делал то же самое, что и раньше, но также делал что-то еще, это было бы так:

 class Class
   def addHelloToMethod(methodName)
       unboundMethod = instance_method(methodName)

       define_method(methodName) do |*args, amp;block|

          result =unboundMethod.bind(self).(*args, amp;block)
          puts "hello"
          result
      end
   end
end
  

Что мне нужно, так это добавить это «привет» к методу
singleton_class, поэтому я попробовал это:

 class Class
   def addHelloToSingletonClassMethod(methodName)
       unboundMethod = singleton_class.instance_method(methodName)

       singleton_class.define_method(methodName) do |*args, amp;block|

          result =unboundMethod.bind(self).(*args, amp;block)
          puts "hello"
          result
      end
   end
end
  

Что я здесь делаю не так?

Ответ №1:

Один из способов сделать это — добавить анонимный модуль, который переопределяет требуемый метод, печатает hello и вызывает super для вызова фактической реализации.

Я не уверен, почему вы добавляете этот метод Class . Ваша цель — вызвать addHelloToSingletonClassMethod экземпляр такого класса, как этот?

 irb> s = "foo"
irb> s.addHelloToSingletonClassMethod(:upcase)
irb> s.upcase
hello
=> "FOO"
  

Если это так, определите следующее на Object :

 class Object
   def addHelloToSingletonClassMethod(methodName)
     mod = Module.new
     mod.define_method(methodName) do |*args, amp;blk|
       puts "hello"
       super(*args, amp;blk)
     end

     singleton_class.prepend(mod)
   end
end
  

Или в более типичном соглашении об именах Ruby:

 class Object
  def add_hello_to_method(name)
    mod = Module.new
    mod.define_method(name) do |*args, amp;blk|
      puts "hello"
      super(*args, amp;blk)
    end

    singleton_class.prepend(mod)
  end
end
  

Если ваша цель, с другой стороны, состоит в том, чтобы иметь возможность вызывать его в классе следующим образом

 irb> String.addHelloToSingletonClassMethod(:upcase)
irb> "foo".upcase
hello
=> "FOO"
  

затем вы хотите определить его на Class :

 class Class
  def add_hello_to_method(name)
    mod = Module.new
    mod.define_method(name) do |*args, amp;blk|
      puts "hello"
      super(*args, amp;blk)
    end

    prepend(mod)
  end
end
  

Ответ №2:

Измените изменение addHelloToSingletonClassMethod на self.addHelloToSingletonClassMethod . Это должен быть метод класса.

Комментарии:

1. Чтобы определить метод в классе singleton_class, я хочу переопределить метод в экземпляре класса singleton_class.