在super()调用之后将范围限制为父级

时间:2018-12-07 19:03:12

标签: ruby

我有一些类似于以下内容的东西:

class A
  def foo
    bar
  end

  def bar
    puts "A"
  end
end

class B < A
  def foo
    super
  end

  def bar
    puts "B"
  end
end

所需的输出将能够调用B.new.foo #=> "A"。一旦调用super,是否有可能将范围限制到父级?这对我来说有点不对劲,所以也许这表明设计不好,但是我很好奇这是否可能。

3 个答案:

答案 0 :(得分:2)

这里的问题是B定义了一个新的bar方法,该方法取代了A中定义的方法。如果您需要保留原有行为,则必须 为此创建一个别名:

class A
  def foo
    original_bar
  end

  def bar
    puts "A"
  end
  alias_method :original_bar, :bar
end

class B < A
  def foo
    super
  end

  def bar
    puts "B"
  end
end

在此处使用alias_method保留了子类未覆盖的原始方法的“副本”。

不过,您是对的,这有点混乱。您可能需要将bar声明为private,以免轻易被推翻。

答案 1 :(得分:1)

这是另一种方法,我仅出于教育目的而提出。

class A
  def foo
    m = method(:bar)
    m = m.super_method until m.owner == A
    m.call
  end    
  def bar
    puts "A"
  end
end

class B < A
  def foo
    super
  end    
  def bar
    puts "B"
  end
end

class C < B
  def foo
    super
  end    
  def bar
    puts "C"
  end
end

B.new.foo
A
C.new.foo
A
A.new.foo
A

请参见Object#methodMethod#super_method

答案 2 :(得分:1)

这是另一种方式。

您通过以下方式获得A的(未绑定)实例方法bar

um = A.instance_method(:bar)
#=> #<UnboundMethod: A#bar>

此方法可以通过以下方式绑定到当前接收者:

bm = um.bind(self)
#=> #<Method: A#bar>

然后可以调用绑定方法:

bm.call
# "A"

在您的代码中:

class A
  def foo
    A.instance_method(:bar).bind(self).call
  end

  # ...
end