Можете ли вы переопределить псевдоним метода в Ruby? - PullRequest
11 голосов
/ 06 мая 2011

В Ruby, когда метод имеет псевдоним, псевдоним указывает на тело исходного метода.Таким образом, даже если вы переопределите оригинальный метод, псевдоним будет продолжать использовать исходное определение.

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

class Foo
  def bar
    "BAR"
  end
end

puts Foo.new.saloon

вернет 'bar', а не 'BAR'.Есть ли способ заставить салон использовать новое определение бара?

РЕДАКТИРОВАТЬ: Я должен был быть более ясным.Пример был просто иллюстрацией проблемы - это не та проблема, которую мне нужно решить.Проблема более сложна, если у вас есть псевдонимы, например, в ядре rails.Например, execute_action связывается с модулем бенчмаркинга, а затем также с модулем flash.Таким образом, теперь вызов execute_action фактически вызывает execute_action_with_flash, который делает свое дело, а затем фактически вызывает execute_action_with_benchmarking, который затем вызывает исходную execute_action.Если я хочу переопределить execute_action_with_benchmarking (даже если я согласен, что это плохая идея - пожалуйста, давайте не будем обсуждать это, поскольку это не имеет значения), я не могу, потому что это было псевдонимом, и насколько я могу сказать,псевдоним указывает на то, что по сути является копией оригинального execute_action_with_benchmarking, поэтому даже если я переопределю его, никакого эффекта не будет.

Ответы [ 4 ]

5 голосов
/ 06 мая 2011

Просто восстановите псевдоним:

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"
3 голосов
/ 06 мая 2011
class Foo
  def bar
    "bar"
  end
  def saloon
    bar
  end
end

Это вовсе не псевдоним, но он работает, как вы хотите.

2 голосов
/ 06 мая 2011

Вот еще один ответ, но вы должны сделать несколько дополнительных шагов: собрать псевдонимы до переопределения и реалии после:

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

Кстати, если кто-нибудь может отменить один из этих шагов, могу я это знать! :)

1 голос
/ 06 мая 2011

Да и нет.Либо Coreyward, либо решения Sony Santos работают нормально.Вам нужно знать, почему ваш код не сработал так, как вы.

alias делает новое имя для функции таким, какое оно появляется при вызове метода.Это не указатель, а новый способ обращения к чему-либо.Это позволяет нам делать что-то вроде этого:

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

class Foo
  def bar(secret_code = false)
    return speakeasy if secret_code == "A friend of Al"
    "Closed because of prohibition!"
  end
end

puts Foo.new.bar #=> "Closed because of prohibition!"
puts Foo.new.bar "A friend of Al" #=> "bar"

Старый бар все еще существует, теперь к нему немного сложнее.

...