Во-первых, некоторые сходства, которые еще не были упомянуты. Ruby поддерживает открытые классы, но модули также открыты. В конце концов, Class наследует от Module в цепочке наследования Class, поэтому класс и Module имеют похожее поведение.
Но вы должны спросить себя, какова цель наличия класса и модуля на языке программирования? Предполагается, что класс является планом для создания экземпляров, а каждый экземпляр представляет собой реализованный вариант плана. Экземпляр - это просто реализованная вариация проекта (Класса). Естественно, что классы функционируют как создание объектов. Кроме того, поскольку иногда мы хотим, чтобы один проект был получен из другого проекта, классы предназначены для поддержки наследования.
Модули не могут быть созданы, не создают объекты и не поддерживают наследование. Помните, что один модуль НЕ наследуется от другого!
Так в чем же смысл наличия модулей на языке? Одно из очевидных применений модулей - создание пространства имен, и вы заметите это и на других языках. Опять же, что хорошо в Ruby, так это то, что Модули можно открывать снова (так же, как Классы). И это большое применение, когда вы хотите повторно использовать пространство имен в разных файлах Ruby:
module Apple
def a
puts 'a'
end
end
module Apple
def b
puts 'b'
end
end
class Fruit
include Apple
end
> f = Fruit.new
=> #<Fruit:0x007fe90c527c98>
> f.a
=> a
> f.b
=> b
Но нет наследования между модулями:
module Apple
module Green
def green
puts 'green'
end
end
end
class Fruit
include Apple
end
> f = Fruit.new
=> #<Fruit:0x007fe90c462420>
> f.green
NoMethodError: undefined method `green' for #<Fruit:0x007fe90c462420>
Модуль Apple не наследовал никаких методов от модуля Green, и когда мы включили Apple в класс Fruit, методы модуля Apple были добавлены в цепочку предков экземпляров Apple, но не методы метода Green, хотя модуль Green был определен в модуле Apple.
Так как же нам получить доступ к зеленому методу? Вы должны явно включить его в свой класс:
class Fruit
include Apple::Green
end
=> Fruit
> f.green
=> green
Но у Ruby есть еще одно важное применение для модулей. Это средство Mixin, которое я опишу в другом ответе на SO. Подводя итог, можно сказать, что миксины позволяют определять методы в цепочке наследования объектов. С помощью миксинов вы можете добавлять методы в цепочку наследования экземпляров объектов (include) или singleton_class класса self (extension).