Что class_methods делает в проблемах?

Я читаю некоторые коды, которые используют проблемы в Rails 4.

Я прочитал несколько статей, чтобы сказать, если мы хотим включить методы класса используя модуль ClassMethods, но код, который я читал, используя что-то вроде:

class_methods do
  def **** 
  end
end

Ответ 1

Это просто для удобства. module ClassMethods является чистым Ruby, но class_methods для удобства используется в ActiveSupport::Concern. Если вы посмотрите на исходный код, вы обнаружите, что class_methods делает то же самое

  # activesupport/lib/concern.rb
  def class_methods(&class_methods_module_definition)
    mod = const_defined?(:ClassMethods, false) ?
      const_get(:ClassMethods) :
      const_set(:ClassMethods, Module.new)

    mod.module_eval(&class_methods_module_definition)
  end

Ответ 2

ActiveSupport::Concern предоставляет синтаксический сахар для общих шаблонов Ruby для модульных миксинов.

Когда вы используете модули как миксины, вы не можете просто использовать self для объявления методов класса, как если бы вы использовали класс:

module Foo
  def self.bar
    "Hello World"
  end

  def instance_method
    "Hello World"
  end
end

class Baz
  include Foo
end

irb(main):010:0> Baz.bar
NoMethodError: undefined method 'bar' for Baz:Class
    from (irb):10
irb(main):011:0> Foo.bar
=> "Hello World"
irb(main):012:0> 

Как вы можете видеть из примера, который фактически создает метод модуля - это потому, что self - это модуль. Вы можете использовать расширение вместо:

module Foo
  def a_class_method
    "Hello World"
  end
end

class Bar
  extend Foo
end

irb(main):049:0> Bar.a_class_method
=> "Hello World"

Но это не позволяет вам объявлять методы экземпляра в модуле. Что не очень полезно.

Поэтому решение состоит в том, чтобы создать внутренний модуль с именем ClassMethods и расширить класс, когда модуль включен:

module Foo
  # this is a method thats called when you include the module in a class.
  def self.included(base)
    base.extend ClassMethods
  end

  def an_instance_method
  end

  # the name ClassMethods is just convention.
  module ClassMethods
    def a_class_method
      "Hello World"
    end
  end
end

class Bar
  include Foo
end

irb(main):071:0> Bar.a_class_method
=> "Hello World"

Этот стандартный код встречается почти в каждом рубиновом геме/библиотеке.

Расширяя свой модуль с помощью ActiveSupport::Concern вы можете сократить это до:

module Foo
  extend ActiveSupport::Concern
  class_methods do
    def a_class_method
      "Hello World"
    end
  end
end

Под капотом ActiveSupport::Concern создает модуль ClassMethods и оценивает блок в контексте модуля (ClassMethods). Загляните в источник, если вам интересно, как он на самом деле это делает.

Ответ 3

class_methods используется для добавления методов класса к модели, используемой этой проблемой.

Типичный модуль выглядит следующим образом:

module M
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    ...
  end
end

Используя ActiveSupport::Concern, указанный выше модуль мог бы быть записан как:

require 'active_support/concern'

module M
  extend ActiveSupport::Concern

  class_methods do
    ...
  end
end

Как Олег Антонян отметил, из исходного кода мы знаем, что он будет использовать модуль ClassMethods под капотом.

Ссылка: http://api.rubyonrails.org/classes/ActiveSupport/Concern.html