По моему мнению, class << self
был одним из самых неприятных битов синтаксиса в Ruby.Люди, плохо знакомые с языком, понятия не имеют, что он означает, кроме конвенций о культе груза, и даже те, кто близко знаком с языком, имеют лишь смутное понимание того, что отличает его от instance_method
, поскольку оба они кажутся удивительно похожими.
Вот пример двух разных способов определения метода класса:
class Example
class << self
def class_def
:class_def
end
end
instance_eval do
def instance_def
:instance_def
end
end
end
Вы можете проверить, работают ли они, вызвав методы:
puts Example.class_def.inspect
# => :class_def
puts Example.instance_def.inspect
# => :instance_def
Разница заключается в том, что вы динамически создаете методы с использованием define_method
, поскольку в версии instance_eval
привязка оказывается неверной:
class Example
class << self
define_method(:class_def) do
:class_def
end
end
instance_eval do
define_method(:instance_def) do
:instance_def
end
end
end
Это приводит к определению метода instance_def
, но небудучи привязанным к самому классу:
puts Example.class_def.inspect
# => :class_def
puts Example.instance_def.inspect
# => NoMethodError: undefined method ‘instance_def’ for Example:Class
Единственный надежный способ создания динамических методов - это class << self
.Метод instance_def
создается и отбрасывается, поскольку он не отображается в методах Example. даже внутри этого блока.