Что 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