Ruby:是否可以在模块中定义类方法?

Mis*_*hko 59 ruby

说有三大类:A,BC.我想每个班有一个类的方法,说self.foo,刚好有对相同的代码A,BC.

是否可以self.foo在模块中定义并包含此模块A,B&C?我试图这样做并收到一条错误消息,说明foo无法识别.

Oma*_*shi 104

是的

module Foo
  def self.included(base)
    base.extend(ClassMethods)
  end
  module ClassMethods
    def some_method
      # stuff
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我应该添加一个可能的注意事项 - 如果模块将成为所有类方法 - 最好只extend ModuleName在模型中使用并直接在模块中定义方法 - 而不是在模块内部使用ClassMethods模块,

 module ModuleName
   def foo
     # stuff
   end
 end
Run Code Online (Sandbox Code Playgroud)


Mla*_*vić 47

module Common
  def foo
    puts 'foo'
  end
end

class A
  extend Common
end

class B
  extend Common
end

class C
  extend Common
end

A.foo
Run Code Online (Sandbox Code Playgroud)

或者,您可以在以后扩展类:

class A
end

class B
end

class C
end

[A, B, C].each do |klass|
  klass.extend Common
end
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,不是`foo`是A,B和C的实例方法吗? (6认同)
  • 正如安德鲁已经指出的那样,Ruby的方法总是实例方法.但在这种情况下,实例是类.所以,`foo`是类实例方法.你用类作为接收器来调用它:`A.foo`.在A的实例方法中,您也可以使用`self.class.foo`. (3认同)
  • @MladenJablanović好吧,_instance_通常用于引用类生成的对象,而不是类对象本身.我建议调用它们_class methods_而不是_class实例方法_以避免混淆. (3认同)

小智 24

Rails 3引入了一个名为的模块ActiveSupport::Concern,其目标是简化模块的语法.

module Foo
  extend ActiveSupport::Concern

  module ClassMethods
    def some_method
      # stuff
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

它允许我们在模块中保存几行"样板"代码.


小智 20

这是ruby mixin的基本功能,使ruby如此特别.而extend开启模块方法分成类方法,include轮流模块方法分成在包括/延伸类或模块实例方法.

module SomeClassMethods
  def a_class_method
    'I´m a class method'
  end
end

module SomeInstanceMethods
  def an_instance_method
   'I´m an instance method!'
  end
end

class SomeClass
  include SomeInstanceMethods
  extend SomeClassMethods
end

instance = SomeClass.new
instance.an_instance_method => 'I´m an instance method!'

SomeClass.a_class_method => 'I´m a class method'
Run Code Online (Sandbox Code Playgroud)

  • 感谢您展示`include`和`extend`之间的区别。 (2认同)

小智 11

只是想在模块中扩展奥利弗的答案定义类方法和实例方法。

module Foo
 def self.included(base)
   base.extend(ClassMethods)
 end
 module ClassMethods
   def a_class_method
     puts "ClassMethod Inside Module"
   end
 end

 def not_a_class_method
   puts "Instance method of foo module"
 end
end

class FooBar
 include Foo
end

FooBar.a_class_method

FooBar.methods.include?(:a_class_method)

FooBar.methods.include?(:not_a_class_method)

fb = FooBar.new

fb.not_a_class_method

fb.methods.include?(:not_a_class_method)

fb.methods.include?(:a_class_method)
Run Code Online (Sandbox Code Playgroud)