Ruby включает единый метод модуля в модели
У меня есть модуль следующего
module SimpleTask
def task1
end
def task2
end
def task3
end
end
И у меня есть модель, для которой требуется только task2
метод модуля SimpleTask
.
Я знаю, что SimpleTask
в моей модели с include SimpleTask
выполнил бы эту работу.
Но мне интересно, могу ли я включить только определенный метод task2
в мою модель.
Ответы
Ответ 1
Похоже, вам нужно реорганизовать #task2
в отдельный модуль (например, BaseTask
). Тогда вы можете легко включить только BaseTask
, где вам нужно только #task2
.
module BaseTask
def task2
...
end
end
module SimpleTask
include BaseTask
def task1
...
end
def task3
...
end
end
Трудно помочь гораздо больше без более конкретного вопроса (например, взаимозависимости между методами SimpleTask
и т.д.
Вы можете выполнить метапрограммирование там, где вы include SimpleTask
, а затем не можете определить методы, которые вам не нужны, но это довольно уродливое ИМО.
Ответ 2
Я собираюсь украсть пример из delegate.rb, он ограничивает то, что включает
...
class Delegator < BasicObject
kernel = ::Kernel.dup
kernel.class_eval do
[:to_s,:inspect,:=~,:!~,:===,:<=>,:eql?,:hash].each do |m|
undef_method m
end
end
include kernel
...
становится
module PreciseInclude
def include_except(mod, *except)
the_module = mod.dup
the_module.class_eval do
except.each do |m|
remove_method m # was undef_method, that prevents parent calls
end
end
include the_module
end
end
class Foo
extend PreciseInclude
include_except(SimpleTask, :task1, :task2)
end
Foo.instance_methods.grep(/task/) => [:task3]
вы всегда можете перевернуть его, чтобы вместо включения он становился include_only
Ловушка заключается в том, что remove_method не будет работать для вложенных модулей, а использование undef предотвратит поиск всей иерархии для этого метода.
Ответ 3
Вы можете добавить
module SimpleTask
def task1
end
def task2
end
def task3
end
module_function :task2
end
Чтобы вы могли вызывать метод как метод класса в модуле, а также иметь его как экземпляр
метод в тех местах, где вы хотите все три метода, например:
class Foo
include SimpleTask
end #=> Foo.new.task2
class LessFoo
def only_needs_the_one_method
SimpleTask.task2
end
end #=> LessFoo.new.only_needs_the_one_method
Или, если в модуле действительно нет общего состояния, и вы не возражаете всегда использовать само имя модуля, вы можете просто объявить все методы класса-уровня следующим образом:
module SimpleTask
def self.task1
end
def self.task2
end
def self.task3
end
end
class Foo
include SimpleTask # Does, more or less nothing now
def do_something
SimpleTask.task1
end
end
#=> Foo.new.task2 #=> "task2 not a method or variable in Foo"
#=> Foo.new.do_something does, however, work
class LessFoo
def only_needs_the_one_method
SimpleTask.task2
end
end #=> LessFoo.new.only_needs_the_one_method works as well in this case
Но в этом случае вам придется изменить всех вызывающих абонентов.