Просто разбираюсь в метапрограммировании Ruby. Примеси / модули всегда меня сбивают с толку.
Так заключается ли основная разница только в этом или скрывается более крупный дракон? например
module ReusableModule
def module_method
puts "Module Method: Hi there!"
end
end
class ClassThatIncludes
include ReusableModule
end
class ClassThatExtends
extend ReusableModule
end
puts "Include"
ClassThatIncludes.new.module_method # "Module Method: Hi there!"
puts "Extend"
ClassThatExtends.module_method # "Module Method: Hi there!"

Правильно.
За кулисами include на самом деле является псевдонимом для append_features, который (из документации):
Ruby's default implementation is to add the constants, methods, and module variables of this module to aModule if this module has not already been added to aModule or one of its ancestors.
То, что вы сказали, правильно. Однако это еще не все.
Если у вас есть класс Klazz и модуль Mod, включение Mod в Klazz дает экземплярам Klazz доступ к методам Mod. Или вы можете расширить Klazz с помощью Mod, предоставив классKlazz доступ к методам Mod. Но также вы можете расширить произвольный объект с помощью o.extend Mod. В этом случае индивидуальный объект получает методы Mod, хотя все другие объекты того же класса, что и o, не получают.
кратко, как Конфуций.
продлевать - добавляет методы и константы указанного модуля в метакласс цели (то есть в одноэлементный класс) например
Klazz.extend(Mod), теперь у Klazz есть методы Mod (как методы класса)obj.extend(Mod), теперь obj имеет методы Mod (как методы экземпляра), но ни в один другой экземпляр obj.class не добавлены эти методы.extend - общедоступный методвключают - по умолчанию он смешивает методы указанного модуля как методы экземпляра в целевом модуле / классе. например
class Klazz; include Mod; end;, теперь все экземпляры Klazz имеют доступ к методам Mod (как методы экземпляра)include - это частный метод, поскольку он предназначен для вызова из класса / модуля контейнера.тем не мение, очень часто модули отвергать Поведение include путем «обезьяны» исправления метода included. Это очень заметно в устаревшем коде Rails. более подробная информация от Иегуды Каца.
Дополнительные сведения о include с его поведением по умолчанию, если вы запустили следующий код
class Klazz
include Mod
end
@@foo или @@barsuper в Klazz # foo будет проверять наличие Mod # foo перед проверка на метод foo реального суперкласса Klazz (подробности см. в RubySpec).Конечно, основная документация по Ruby - лучшее место для этих вещей. Проект RubySpec также был фантастическим ресурсом, потому что они точно документировали функциональность.
#includeRubySpecрубидок#includedRubySpecрубидок#extendRubySpecрубидок#extendedRubySpecрубидок#extend_objectRubySpecрубидок#append_featuresRubySpecрубидокЯ знаю, что это довольно старый пост, но ясность ответа не могла удержать меня от комментариев. Большое спасибо за хорошее объяснение.
@anwar Очевидно, но теперь я могу комментировать, и мне удалось снова найти статью. Он доступен здесь: aaronlasseigne.com/2012/01/17/explaining-include-and-extend, и я все еще думаю, что схема значительно упрощает понимание
Большой выигрыш в этом ответе заключается в том, как extend может применять методы как методы экземпляра класса или же в зависимости от использования. Klass.extend = методы класса, objekt.extend = методы экземпляра. Я всегда (ошибочно) предполагал, что методы класса исходят от extend, а экземпляр - от include.
Все остальные ответы хороши, включая совет по RubySpecs:
https://github.com/rubyspec/rubyspec/blob/master/core/module/include_spec.rb
https://github.com/rubyspec/rubyspec/blob/master/core/module/extend_object_spec.rb
Что касается вариантов использования:
Если вы используете модуль ReusableModule включают в классе ClassThatIncludes, на методы, константы, классы, подмодули и другие объявления будут ссылаться.
Если у вас класс ClassThatExtends продлевать с модулем ReusableModule, то методы и константы получают скопировано. Очевидно, что если вы не будете осторожны, вы можете потратить много памяти на динамическое дублирование определений.
Если вы используете ActiveSupport :: Concern, функция .included () позволяет напрямую переписать включающий класс. модуль ClassMethods внутри Концерна получает расширенный (скопированный) во включающий класс.
Я также хотел бы объяснить механизм, как он работает. Если я не прав, поправьте.
Когда мы используем include, мы добавляем связь из нашего класса с модулем, который содержит некоторые методы.
class A
include MyMOd
end
a = A.new
a.some_method
У объектов нет методов, есть только классы и модули.
Поэтому, когда a получает сообщение some_method, он начинает поиск метода some_method в собственном классе a, затем в классе A, а затем в связанных с модулями класса A, если они есть (в обратном порядке, последний включенный побеждает).
Когда мы используем extend, мы добавляем связь с модулем в собственном классе объекта.
Итак, если мы используем A.new.extend (MyMod), мы добавляем ссылку на наш модуль на собственный класс экземпляра A или класс a'.
И если мы используем A.extend (MyMod), мы добавляем связь с собственным классом A (объекты, классы также являются объектами) A'.
поэтому путь поиска метода для a выглядит следующим образом:
a => a '=> связанные модули с классом a' => A.
также есть метод prepend, который изменяет путь поиска:
a => a '=> добавленные модули к A => A => добавленные модули к A
Извините за мой плохой английский.
Когда вы include модуль в класс, методы модуля импортируются как методы экземпляра.
Однако, когда вы extend модуль в класс, методы модуля импортируются как методы класса.
Например, если у нас есть модуль Module_test, определенный следующим образом:
module Module_test
def func
puts "M - in module"
end
end
Теперь о модуле include. Если мы определим класс A следующим образом:
class A
include Module_test
end
a = A.new
a.func
Результат будет: M - in module.
Если мы заменим строку include Module_test на extend Module_test и снова запустим код, мы получим следующую ошибку: undefined method 'func' for #<A:instance_num> (NoMethodError).
При изменении вызова метода a.func на A.func вывод меняется на M - in module.
Из выполнения приведенного выше кода ясно, что когда мы include модуль, его методы становятся методы экземпляра, а когда мы extend модуль, его методы становятся методы класса.
Также проверьте эту ссылку: juixe.com/techknow/index.php/2006/06/15/mixins-in-ruby