Ori*_*rds 171 ruby methods module
我有一个声明了许多实例方法的模块
module UsefulThings
def get_file; ...
def delete_file; ...
def format_text(x); ...
end
Run Code Online (Sandbox Code Playgroud)
我想从一个类中调用其中的一些方法.你通常如何在ruby中这样做是这样的:
class UsefulWorker
include UsefulThings
def do_work
format_text("abc")
...
end
end
Run Code Online (Sandbox Code Playgroud)
include UsefulThings从中引入所有方法UsefulThings.在这种情况下,我只想要format_text并明确地不想get_file和delete_file.
我可以看到几个可能的解决方案:
Usefulthings并且只引入一些方法
UsefulThings在其中,然后委托format_text给该代理实例
为什么单个模块中有很多不相关的功能?它ApplicationHelper来自一个rails应用程序,我们的团队事实上决定将其作为任何其他地方不具备的特定任何东西的倾倒场.大多数独立的实用程序方法随处可见.我可以将它分解成单独的助手,但是它们中有30个,每个都有1个方法......这似乎没有效果
dol*_*nko 139
我认为最简单的方法就是抛弃单个调用(不改变现有模块或创建新模块)如下:
Class.new.extend(UsefulThings).get_file
Run Code Online (Sandbox Code Playgroud)
dgt*_*zed 130
如果将模块上的方法转换为模块函数,则可以简单地将其从Mods中调用,就好像它已被声明为
module Mods
def self.foo
puts "Mods.foo(self)"
end
end
Run Code Online (Sandbox Code Playgroud)
下面的module_function方法将避免破坏任何包含所有Mod的类.
module Mods
def foo
puts "Mods.foo"
end
end
class Includer
include Mods
end
Includer.new.foo
Mods.module_eval do
module_function(:foo)
public :foo
end
Includer.new.foo # this would break without public :foo above
class Thing
def bar
Mods.foo
end
end
Thing.new.bar
Run Code Online (Sandbox Code Playgroud)
但是,我很好奇为什么一组不相关的函数首先包含在同一个模块中?
编辑显示,如果public :foo被调用后仍然有效module_function :foo
Dus*_*tin 79
如果您"拥有"该模块,另一种方法是使用它module_function.
module UsefulThings
def a
puts "aaay"
end
module_function :a
def b
puts "beee"
end
end
def test
UsefulThings.a
UsefulThings.b # Fails! Not a module method
end
test
Run Code Online (Sandbox Code Playgroud)
Rai*_*kis 18
如果要在不将模块包含在另一个类中的情况下调用这些方法,则需要将它们定义为模块方法:
module UsefulThings
def self.get_file; ...
def self.delete_file; ...
def self.format_text(x); ...
end
Run Code Online (Sandbox Code Playgroud)
然后你可以打电话给他们
UsefulThings.format_text("xxx")
Run Code Online (Sandbox Code Playgroud)
要么
UsefulThings::format_text("xxx")
Run Code Online (Sandbox Code Playgroud)
但无论如何我建议你把相关的方法放在一个模块或一个类中.如果你有问题想要从模块中只包含一个方法,那么它听起来就像是一个糟糕的代码味道,将不相关的方法放在一起并不是很好的Ruby风格.
ren*_*ier 17
要在不包含模块的情况下调用模块实例方法(并且不创建中间对象):
class UsefulWorker
def do_work
UsefulThings.instance_method(:format_text).bind(self).call("abc")
...
end
end
Run Code Online (Sandbox Code Playgroud)
首先,我建议将模块分解为您需要的有用的东西.但是你总是可以为你的调用创建一个扩展它的类:
module UsefulThings
def a
puts "aaay"
end
def b
puts "beee"
end
end
def test
ob = Class.new.send(:include, UsefulThings).new
ob.a
end
test
Run Code Online (Sandbox Code Playgroud)
A. 如果您总是想以“合格的”独立方式(UsefulThings.get_file)调用它们,那么就像其他人指出的那样将它们设为静态,
module UsefulThings
def self.get_file; ...
def self.delete_file; ...
def self.format_text(x); ...
# Or.. make all of the "static"
class << self
def write_file; ...
def commit_file; ...
end
end
Run Code Online (Sandbox Code Playgroud)
B. 如果你仍然想在相同的情况下保留 mixin 方法,以及一次性的独立调用,你可以有一个单行模块,用 mixin扩展自己:
module UsefulThingsMixin
def get_file; ...
def delete_file; ...
def format_text(x); ...
end
module UsefulThings
extend UsefulThingsMixin
end
Run Code Online (Sandbox Code Playgroud)
所以两者都有效:
UsefulThings.get_file() # one off
class MyUser
include UsefulThingsMixin
def f
format_text # all useful things available directly
end
end
Run Code Online (Sandbox Code Playgroud)
恕我直言,它比module_function每种方法都更干净-以防万一。
据我了解,您想将模块的一些实例方法混合到一个类中。
让我们首先考虑Module#include是如何工作的。假设我们有一个UsefulThings包含两个实例方法的模块:
module UsefulThings
def add1
self + 1
end
def add3
self + 3
end
end
UsefulThings.instance_methods
#=> [:add1, :add3]
Run Code Online (Sandbox Code Playgroud)
和Fixnum include那个模块:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
include UsefulThings
end
Run Code Online (Sandbox Code Playgroud)
我们看到:
Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
#=> [:add2, :add3, :add1]
1.add1
2
1.add2
cat
1.add3
dog
Run Code Online (Sandbox Code Playgroud)
您是否希望UsefulThings#add3覆盖Fixnum#add3,以便1.add3返回4?考虑一下:
Fixnum.ancestors
#=> [Fixnum, UsefulThings, Integer, Numeric, Comparable,
# Object, Kernel, BasicObject]
Run Code Online (Sandbox Code Playgroud)
当类include成为模块时,模块成为类的超类。因此,由于继承的工作方式,发送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
Run Code Online (Sandbox Code Playgroud)
现在,我们希望Fixnum到include只有方法add1和add3。这样做,我们期望得到和上面一样的结果。
假设,如上所述,我们执行:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
include UsefulThings
end
Run Code Online (Sandbox Code Playgroud)
结果是什么?不需要的方法: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
Run Code Online (Sandbox Code Playgroud)
我们这样调用:
class Fixnum
def add2
puts "cat"
end
def add3
puts "dog"
end
Helpers.include_some(UsefulThings, self, :add1, :add3)
end
Run Code Online (Sandbox Code Playgroud)
然后:
Fixnum.instance_methods.select { |m| m.to_s.start_with? "add" }
#=> [:add2, :add3, :add1]
1.add1
2
1.add2
cat
1.add3
dog
Run Code Online (Sandbox Code Playgroud)
这就是我们想要的结果。
小智 5
不确定 10 年后是否有人仍然需要它,但我使用 eigenclass 解决了它。
module UsefulThings
def useful_thing_1
"thing_1"
end
class << self
include UsefulThings
end
end
class A
include UsefulThings
end
class B
extend UsefulThings
end
UsefulThings.useful_thing_1 # => "thing_1"
A.new.useful_thing_1 # => "thing_1"
B.useful_thing_1 # => "thing_1"
Run Code Online (Sandbox Code Playgroud)