Alec Alec -4 years ago 44
Ruby Question

What's the cleanest way of chaining stream functions in Ruby?

Let's say I have an array of stuff that I want to perform all sorts of wacky operations on. For example:

my_array = [
{ name: 'Lyra', age: 12 },
{ name: 'Harry', age: 11 },
{ name: 'Kestrel', age: 13},
]


I want to filter out anyone under the age of 12, change all names to symbols, and then sort them by age (say).

This can be achieved with:

new_array = my_array.
select { |person| person[:age] > 11 }.
map { |person| person.merge(name: person[:name].to_sym) }.
sort_by { |person| person[:age] }


So that's all dandy. But what if I have arbitrarily complex logic I need to do my selecting/mapping/sorting/etc.?

Standard practice says that multi-line blocks with braces are to be avoided (and some linters even outright forbid it). Yet, the alternative is to start chaining
do..end
blocks, which looks even ickier:

new_array = my_array.
select do |person|
# Do something complex
end.
map do |person|
# More complex stuff
end.
sort_by do |person|
# Yet more complex stuff
end


Does the Ruby community have any advice on best practice for chaining this sort of thing? For example, is it nicer to define a
Proc
(or similar), and pass that into the block?

Answer Source

You could create a copy and use destructive methods instead:

new_array = my_array.dup

new_array.select! do |person|
  # Do something complex
end

new_array.map! do |person|
  # More complex stuff
end

new_array.sort_by! do |person|
  # Yet more complex stuff
end
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download