同一个实例的几种方法 - DRY

时间:2014-02-27 20:39:42

标签: ruby-on-rails ruby dry

很抱歉,如果这太简单了。我正在寻找一种方法让我的ruby代码变干:我想在同一个实例变量@var = Model.new(param)上调用多个方法:

@var.method1
@var.method2
@var.method3
...

是否可以使用send方法编写一行代码?顺便说一下,是否可以在Model.new上调用一个块来生成更简洁的代码?

4 个答案:

答案 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)

如果您构建method1method2等,以便使用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