你可以在Ruby中覆盖别名方法吗?

far*_*adf 11 ruby alias ruby-on-rails

在Ruby中,当方法有别名时,别名指向原始方法的主体.因此,即使重新定义原始方法,别名也将继续使用原始定义.

class Foo
  def bar
    "bar"
  end  
  alias :saloon :bar
end

class Foo
  def bar
    "BAR"
  end
end

puts Foo.new.saloon
Run Code Online (Sandbox Code Playgroud)

将返回'bar'而不是'BAR'.有没有办法让轿车使用新的酒吧定义?

编辑:我应该更清楚.这个例子只是一个问题的例子 - 这不是我需要解决的实际问题.当你有链式别名时,问题就更复杂了,例如,在rails的核心中.例如,perform_action由基准测试模块别名,然后由flash模块.所以现在对perform_action的调用实际上是调用perform_action_with_flash执行它的事情,然后有效地调用perform_action_with_benchmarking然后调用原始的perform_action.如果我想覆盖perform_action_with_benchmarking(即使我同意这是一个坏主意 - 请让我们不要讨论它,因为除了这一点),我不能,因为它已被别名,并且据我所知别名指向的是原始perform_action_with_benchmarking的副本,所以即使重新定义它,也没有效果.

cor*_*ard 6

只需重新建立别名:

class Foo
  def bar
    "bar"
  end  
  alias :saloon :bar
end

class Foo
  def bar
    "BAR"
  end
  alias :saloon :bar
end

puts Foo.new.saloon # => "BAR"
Run Code Online (Sandbox Code Playgroud)


Son*_*tos 2

这是另一个答案,但您必须执行一些额外的步骤:在覆盖之前收集别名,并在覆盖之后收集真实别名:

class Class
  def get_aliases method_name
    original_proc = instance_method method_name
    aliases = []
    instance_methods.each do |meth|
      # if the methods have different names but they're the same, they're aliased
      if meth != method_name.to_s && original_proc == instance_method(meth)
        aliases << meth
      end
    end
    aliases
  end
end

class Foo
  def bar
    "bar"
  end  
  alias :saloon :bar
end

class Foo
  aliases = get_aliases :bar
  def bar
    "BAR"
  end
  aliases.each { |a| alias_method a, :bar }
end

puts Foo.new.saloon  #=> BAR
Run Code Online (Sandbox Code Playgroud)

顺便说一句,如果有人可以去掉其中一个步骤,我可以知道吗!:)