Ruby在模型中包含模块的单一方法
Posted
技术标签:
【中文标题】Ruby在模型中包含模块的单一方法【英文标题】:Ruby include module's single method in model 【发布时间】:2011-09-24 20:05:38 【问题描述】:我有一个关注模块
module SimpleTask
def task1
end
def task2
end
def task3
end
end
我有一个模型,它只需要模块SimpleTask
的task2
方法。
我知道在我的模型中包含SimpleTask
和include SimpleTask
可以完成这项工作。
但我想知道我是否只能在我的模型中包含特定的 task2
方法。
【问题讨论】:
Can I invoke an instance method on a Ruby module without including it? 的可能重复项 【参考方案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
处进行一些元编程,然后取消定义您不想要的方法,但这在 IMO 中是相当丑陋的。
【讨论】:
这个问题没有错,很好,很清楚。我到了这个页面,因为我有完全相同的问题。我不想创建新模块,也不想在类命名空间中不必要地包含其他方法。我只想包含模块中的一个方法。【参考方案2】:你可以添加
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
但在这种情况下,您必须更改所有调用者。
【讨论】:
module_function
很好,只要所有模块实例方法都是私有的就可以了。如果您希望它们公开,您可以使用extend self
。必须小心,任何方法都不依赖于包含它们的实例的状态;在这种情况下,类方法将不起作用。【参考方案3】:
我要从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 将阻止在整个层次结构中搜索该方法。
【讨论】:
【参考方案4】:一个简单的解决方案是
define_method :task2, SimpleTask.instance_method(:task2)
【讨论】:
以上是关于Ruby在模型中包含模块的单一方法的主要内容,如果未能解决你的问题,请参考以下文章