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

Но в этом случае вам придется изменить всех вызывающих абонентов.