Ruby включает единственный метод модуля в модель - PullRequest
14 голосов
/ 29 июня 2011

У меня есть модуль следующего

module SimpleTask
    def task1
    end
    def task2
    end
    def task3
    end
end

И у меня есть модель, которая требует только task2 метод модуля SimpleTask.

Я знаю, что включение SimpleTask в мою модель с include SimpleTask сделает эту работу.

Но мне интересно, могу ли я включить в свою модель только конкретный метод task2.

Ответы [ 4 ]

7 голосов
/ 29 июня 2011

Похоже, вам нужно провести рефакторинг #task2 в отдельный модуль (например, BaseTask). Тогда вы можете легко включить только BaseTask, где вам нужно только #task2.

module BaseTask
  def task2
    ...
  end
end

module SimpleTask
  include BaseTask

  def task1
    ...
  end

  def task3
    ...
  end
end

Трудно помочь гораздо больше без более конкретного вопроса (такого как взаимозависимость между методами SimpleTask и т. Д.

Вы могли бы выполнить метапрограммирование, где вы include SimpleTask и затем отмените методы, которые вам не нужны, но это довольно уродливо для ИМО.

6 голосов
/ 08 января 2014

Я собираюсь украсть пример из 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 предотвратит поиск во всей иерархии этого метода.

6 голосов
/ 29 июня 2011

Вы можете добавить

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

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

0 голосов
/ 17 сентября 2018

Простым решением для этого является

define_method :task2, SimpleTask.instance_method(:task2)

...