Ruby `included` 块中的 `define_singleton_method` 与 `ClassMethods`

Ruby `define_singleton_method` in `included` block vs `ClassMethods`

即使Bar包含在Default模块之后,它仍然无法覆盖Default.foo。有办法吗?

module Default
  extend ActiveSupport::Concern
  included do
    define_singleton_method :foo do
      41
    end
  end
end
module Bar
  extend ActiveSupport::Concern
  module ClassMethods
    def foo
      42
    end
  end
end
class Foo
  include Default
  include Bar
end

Foo.foo
=> 41  #From Default.foo

如果我们在您的代码中添加一些调试语句,我们将看到模块的定义和包含顺序如下所示:

Defined => Default
Defined => Bar
Defined => ClassMethods
Included => Default
Included => Bar
41

由于包含模块 Default 的事件发生在定义模块 Bar 之后,因此生效的 foo 的定义是在模块 Default.

included 块中定义的一个

添加了调试语句的代码

require "rails"

module Default
  extend ActiveSupport::Concern
  puts "Defined => Default"
  included do
    define_singleton_method :foo do
      41
    end
    puts "Included => Default"
  end
end
module Bar
  extend ActiveSupport::Concern
  puts "Defined => Bar"
  module ClassMethods
    puts "Defined => ClassMethods"
    def foo
      42
    end
  end
  included do
    puts "Included => Bar"
  end
end
class Foo
  include Default
  include Bar
end

p Foo.foo

如果你想让Barfoo定义生效,那么,你也可以在Barincluded块中定义它=]如下图:

require "rails"

module Default
  extend ActiveSupport::Concern
  puts "Defined => Default"
  included do
    define_singleton_method :foo do
      41
    end
    puts "Included => Default"
  end
end
module Bar
  extend ActiveSupport::Concern
  puts "Defined => Bar"
  module ClassMethods
    puts "Defined => ClassMethods"
    def foo
      42
    end
  end
  included do
    puts "Included => Bar"
    define_singleton_method :foo do
      42
    end
  end
end
class Foo
  include Default
  include Bar
end

p Foo.foo

以上程序的输出

Defined => Default
Defined => Bar
Defined => ClassMethods
Included => Default
Included => Bar
42