【问题标题】:Can you override an aliased method in Ruby?您可以在 Ruby 中覆盖别名方法吗?
【发布时间】:2011-05-06 00:29:10
【问题描述】:

在 Ruby 中,当一个方法有别名时,别名指向原始方法的主体。所以即使你重新定义了原来的方法,别名也会继续使用原来的定义。

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

class Foo
  def bar
    "BAR"
  end
end

puts Foo.new.saloon

将返回 'bar' 而不是 'BAR'。有什么办法让saloon 使用bar 的新定义?

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

【问题讨论】:

    标签: ruby-on-rails ruby alias


    【解决方案1】:

    只需重新建立别名:

    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"
    

    【讨论】:

      【解决方案2】:
      class Foo
        def bar
          "bar"
        end
        def saloon
          bar
        end
      end
      

      这根本不是别名,但它可以随心所欲。

      【讨论】:

        【解决方案3】:

        是和不是。 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"
        

        旧栏仍然存在,只是现在更难访问了。

        【讨论】:

          【解决方案4】:

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

          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
          

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

          【讨论】:

          • 这是一种确定哪些方法有别名的聪明方法。我认为它可以解决问题......
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-07
          • 1970-01-01
          • 2013-03-18
          • 1970-01-01
          • 2010-12-17
          • 1970-01-01
          相关资源
          最近更新 更多