Ruby: возможно ли определить метод класса в модуле? - PullRequest
56 голосов
/ 15 января 2011

Скажем, есть три класса: A, B & C. Я хочу, чтобы у каждого класса был метод класса, скажем self.foo, который имеет точно такой же код для A, B & C.

Можно ли определить self.foo в модуле и включить этот модуль в A, B & C? Я попытался сделать это и получил сообщение об ошибке, в котором говорится, что foo не распознано.

Ответы [ 5 ]

98 голосов
/ 15 января 2011

Да

module Foo
  def self.included(base)
    base.extend(ClassMethods)
  end
  module ClassMethods
    def some_method
      # stuff
    end
  end
end

Можно добавить одно возможное замечание - если модуль будет ВСЕМ методами класса - лучше просто использовать extend ModuleName в модели и определить методы непосредственно в модуле.- вместо того, чтобы иметь модуль ClassMethods внутри модуля, а

 module ModuleName
   def foo
     # stuff
   end
 end
45 голосов
/ 15 января 2011
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

Или вы можете впоследствии расширить классы:

class A
end

class B
end

class C
end

[A, B, C].each do |klass|
  klass.extend Common
end
22 голосов
/ 26 июня 2015

В Rails 3 представлен модуль с именем ActiveSupport::Concern, целью которого является упрощение синтаксиса модулей.

module Foo
  extend ActiveSupport::Concern

  module ClassMethods
    def some_method
      # stuff
    end
  end
end

Это позволило нам сохранить несколько строк кода «шаблона» в модуле.

18 голосов
/ 09 декабря 2016

Это базовая функциональность 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'
0 голосов
/ 28 июня 2019

Просто хотел расширить ответ Оливера. Определить методы класса и методы экземпляра вместе в модуле.

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...