很抱歉,如果这太简单了。我正在寻找一种方法让我的ruby
代码变干:我想在同一个实例变量@var = Model.new(param)
上调用多个方法:
@var.method1
@var.method2
@var.method3
...
是否可以使用send
方法编写一行代码?顺便说一下,是否可以在Model.new
上调用一个块来生成更简洁的代码?
答案 0 :(得分:6)
我认为应该使用DRY来使代码更易于维护,更具可读性。我不认为应该用它来缩短你输入的字符数,或者展示你的代码杂技。
@ Arup和@ p11y的解决方案在上下文中都很棒,但作为一般规则(在了解您的课程或方法之前),我相信写作
@var.method1
@var.method2
@var.method3
比写
更具可读性和可维护性%i[method1 method2 method3].each(&@var.method(:send))
(你需要精通高级红宝石才能理解这一点)
或
@var.method1
.method2
.method3
(对于未来的读者来说,消失的行为再次让人感到困惑而不是有帮助)
始终考虑谁将在6个月内阅读您的代码,以及最清楚的方式让他了解正在发生的事情。
答案 1 :(得分:5)
如果您构建method1
,method2
等,以便使用self
返回实例本身,则可以构建可链接的接口。例如:
class Foo
def method1
# do something
self
end
def method2
# do something
self
end
def method3
# do something
self
end
# more methods...
end
@var = Foo.new
@var.method1.method2.method3
# or if this gets too long
@var.method1
.method2
.method3
答案 2 :(得分:3)
执行以下操作:
%i[method1 method2 method3].each { |m| @var.send(m) }
如果您想缩短它,请使用:
%i[method1 method2 method3].each(&@var.method(:send))
答案 3 :(得分:0)
当我写完原始答案时,我错过了你问题中的最后一句话:
顺便说一下,是否可以在
Model.new
上调用一个块来生成更简洁的代码?
这个问题的答案是肯定的。这个模式是一个构建器模式,它在ruby中的几个gem中实现(例如tire
)。
该模式指出initialize
方法使用instance_eval
接收一个块,该块在创建的对象的上下文中运行。如果块接收参数,则将实例对象传递给它而不是更改块的范围:
class Model
def initialize(name, &block)
@name = name
block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
end
def method1
# something
end
def method2
# something
end
def method3
# something
end
end
它的用法将是这样的:
@var = Model.new('model') do
method1
method2
method3
end
或者,或者:
@var = Model.new('model') do |m|
m.method1
m.method2
m.method3
end