How can I write the conditional: each in ruby ​​is more concise?

I'm not sure how to write this code more cleanly in ruby? The only thing that is different is the iterator.

  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


source to share


3 answers


You can use Object#send

to call the method dynamically:



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

      

+5


source


I suppose you could do:



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

      

+2


source


I would try to make the intent for this thread a little clearer:

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

      

Which iterator to choose is an implementation detail that can make my business logic difficult to understand. Let's extract the iteration logic into a separate method. The benefit of this extraction is debatable if the general business logic is one liner. This will add more clarity if the original method is longer.

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) }

      

Now that we are free from the original method, I would expand on the triple if

to improve readability.

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) }

      

0


source







All Articles