Ruby — Как имитировать super для метода класса?

#ruby #metaprogramming

#ruby #метапрограммирование

Вопрос:

В (автоматических) образовательных целях я пытаюсь имитировать super поведение, чтобы узнать, как это работает.

Я мог бы имитировать super , например, методы, но я не мог этого сделать для методов класса.

Вот мой код:

 class A
  def aa
    @msg ||= 'Original...: '
    puts "#{@msg}#{self}.aa: #{self.class} < #{self.class.superclass}"
  end
  def self.ab
    @msg ||= 'Original...: '
    puts "#{@msg}#{self}.ab: #{self} < #{self.superclass}"
  end
end

class B < A
  def aa
    @msg = "Real super.: "
    super
  end
  def self.ab
    @msg = "Real super.: "
    super
  end
  def mimic_aa
    @msg = "Mimic super: "
    self.class.superclass.instance_method(:aa).bind(self).call
  end
  def self.mimic_ab
    @msg = "Mimic super: "
    #superclass.method(:ab).unbind.bind(self).call
      #=> Error: singleton method only works in original object

    #superclass.ab
      #=> self is A; I want self to be B

    proc = superclass.method(:ab).to_proc

    #self.instance_eval(amp;proc)
      #=> ArgumentError: instance_eval seems to call aa(some_unwanted_param)
      # Note: Ruby 1.8.7

    #eval('proc.call', binding)
      #=> self is A; I want self to be B

  end
end

a = A.new
b = B.new

a.aa         #=> Original...: #<A:0xb77c66ec>.aa: A < Object
b.aa         #=> Real super.: #<B:0xb77c6624>.aa: B < A
b.mimic_aa   #=> Mimic super: #<B:0xb77c6624>.aa: B < A

puts ''

A.ab         #=> Original...: A.ab: A < Object
B.ab         #=> Real super.: B.ab: B < A
B.mimic_ab   #=> (expected the same as above)
  

Есть идеи?

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

1. Ваш вопрос слишком сложный и непонятный. Я думаю, именно поэтому на ваш вопрос пока нет ответа. Что вы пытаетесь сделать с B#mimic_aa и B.mimic_ab ? Почему будет B#aa и B.ab недостаточно? Кроме того, названия методов сбивают с толку. Возможно, вы захотите улучшить вопрос.

2. @sawa, я хочу узнать, как выполнить метод класса в A в контексте того, что B является self . Это может быть полезно, когда имена методов в A и B разные, и поэтому я не смог использовать super . В любом случае, спасибо, я подумаю над улучшением вопроса. 🙂

Ответ №1:

Что ж, проблема, вероятно, в используемой вами версии Ruby. Я использую 1.9.2, и программа выполняется, как ожидалось. Я думаю (из комментария в вашем коде), что проблема в том, что вы используете Ruby версии v1.8.7. Также не помешало бы попробовать запустить ваш код еще раз.

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

1. Круто! Используете ли вы self.instance_eval(amp;proc) ?

2. Это было определение, которое работает: def self.mimic_ab; @msg = "Mimic super: "; superclass.method(:ab).unbind.bind(self).call; end