我怎么能写一个条件:每个在红宝石中更简洁?

时间:2017-05-15 16:21:59

标签: ruby

我不确定如何在ruby中更干净地编写这段代码?唯一不同的是迭代器。

  if items.respond_to?(:find_each)
    items.find_each do |item|
      output_item(csv, item)
    end
  else
    items.each do |item|
      output_item(csv, item)
    end
  end

3 个答案:

答案 0 :(得分:5)

您可以使用Object#send动态调用方法:

method = items.respond_to?(:find_each) ? :find_each : :each
items.send(method) do |item|
  output_item(csv, item)
end

答案 1 :(得分:2)

我想你可以这样做:

method = items.respond_to?(:find_each) ? :find_each : :each
items.send(method) { |item| output_item(csv, item) }

答案 2 :(得分:0)

我试图让这个分支的意图更清晰一点:

iterator = items.is_a?(ActiveRecord::Relation) ? :find_each : :each
items.send(iterator) { |item| output_item(csv, item) } 

选择哪个迭代器是一个实现细节,可能会使我的业务逻辑更难理解。让我们将迭代逻辑提取到一个单独的方法中。如果总业务逻辑是单线程,那么这种提取的好处是值得商榷的。如果原始方法更长,它将增加更多清晰度。

def iterate(relation_or_array, *args, &block)
  iterator = relation_or_array.is_a?(ActiveRecord::Relation) ? :find_each : :each
  relation_or_array.send(iterator, *args, &block)
end

# main logic
iterate(items) { |item| output_item(csv, item) }

既然我们没有使用原始方法,我会扩展三元if以提高可读性。

def iterate(relation_or_array, *args, &block)
  if relation_or_array.is_a? ActiveRecord::Relation
    relation_or_array.find_each(*args, &block)
  else 
    relation_or_array.each(*args, &block)
  end
end

# main logic
iterate(items) { |item| output_item(csv, item) }