Насколько я понимаю, вы хотите смешать некоторые методы экземпляра модуля в классе.
Давайте начнем с рассмотрения того, как работает Module # include . Предположим, у нас есть модуль UsefulThings
, который содержит два метода экземпляра:
module UsefulThings
def add1
self + 1
end
def add3
self + 3
end
end
UsefulThings.instance_methods
#=> [:add1, :add3]
и Fixnum
include
с этим модулем:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
include UsefulThings
end
Мы видим, что:
Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
#=> [:add2, :add3, :add1]
1.add1
2
1.add2
cat
1.add3
dog
Вы ожидали, что UsefulThings#add3
переопределит Fixnum#add3
, чтобы 1.add3
вернул 4
? Учтите это:
Fixnum.ancestors
#=> [Fixnum, UsefulThings, Integer, Numeric, Comparable,
# Object, Kernel, BasicObject]
Когда класс include
s является модулем, модуль становится суперклассом класса. Таким образом, из-за того, как работает наследование, отправка add3
экземпляру Fixnum
приведет к вызову Fixnum#add3
, возвращающему dog
.
Теперь давайте добавим метод :add2
к UsefulThings
:
module UsefulThings
def add1
self + 1
end
def add2
self + 2
end
def add3
self + 3
end
end
Теперь мы желаем от Fixnum
до include
только методов add1
и add3
. При этом мы ожидаем получить те же результаты, что и выше.
Предположим, как указано выше, мы выполняем:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
include UsefulThings
end
Каков результат? Нежелательный метод :add2
добавляется к Fixnum
, :add1
добавляется и, по причинам, которые я объяснил выше, :add3
не добавляется. Так что все, что нам нужно сделать, это undef
:add2
. Мы можем сделать это с помощью простого вспомогательного метода:
module Helpers
def self.include_some(mod, klass, *args)
klass.send(:include, mod)
(mod.instance_methods - args - klass.instance_methods).each do |m|
klass.send(:undef_method, m)
end
end
end
который мы вызываем так:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
Helpers.include_some(UsefulThings, self, :add1, :add3)
end
Тогда:
Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
#=> [:add2, :add3, :add1]
1.add1
2
1.add2
cat
1.add3
dog
что является желаемым результатом.