0
Posted on Tuesday, September 04, 2018 by 醉·醉·鱼 and labeled under

You have a class with a class method. Write a module that, when included, will override that class method.


在这篇文章里面已经介绍了一种方法 http://tech.tulentsev.com/2012/02/ruby-how-to-override-class-method-with-a-module/,但我还可以分享另外的方法。


方法一:用instance_eval。原文中的方法。

module BooModule
  def self.included base
    base.instance_eval do
      def bar
        puts "module"
      end
    end
  end
end

class KlassC

  def self.bar
    puts 'class'
  end
end

KlassC.send(:include, BooModule)

KlassC.bar #=> module
p KlassC.ancestors

方法二:用 class << base ; end


module TooModule
  def self.included base
    class << base
      def bar
        puts "module"
      end
    end
  end
end

class KlassD

  def self.bar
    puts 'class'
  end
end

KlassD.send(:include, TooModule)

KlassD.bar #=> module
p KlassD.ancestors

方法三:用prepend。如果你知道extend实际上就是class << base; include ClassMethods end的话,你就很好理解为啥prepend在这里可以起作用了。前两者都是直接修改类方法,而这直接通过修改继承链的方法去覆盖类方法。


module GooModule
  def self.included base
    class << base
      prepend ClassMethods
    end
  end

  module ClassMethods
    def bar
      puts "module"
    end
  end
end

class KlassE
  def self.bar
    puts 'class'
  end
end

KlassE.send(:include, GooModule)

KlassE.bar #=> module
p KlassE.ancestors


能够直接用prepend么?不行。你可以试试下面的例子。虽然说,被prepend的module会放到class的继承链的下方,但实际上,类方法却不受影响。


module FooModule
  def self.included base
    base.extend ClassMethods
  end

  def self.prepended base
    base.extend ClassMethods
  end

  module ClassMethods
    def bar
      puts "module"
    end
  end
end

class KlassA
  include FooModule

  def self.bar
    puts 'class'
  end
end


KlassA.bar #=> class
p KlassA.ancestors

class KlassB
  prepend FooModule

  def self.bar
    puts 'class'
  end
end


KlassB.bar #=> class
p KlassB.ancestors
0
Responses to ... Ruby: How to Override Class Method With a Module

Post a Comment