In this article, I'll write about this and that related to Enumerable, which I often point out as actually doing pull request reviews in business. Not all methods are covered, so don't be afraid. Click here for English version
Mix-ins for repeating classes. All the methods in this module are defined using each, so each must be defined in the included class.
https://docs.ruby-lang.org/ja/latest/class/Enumerable.html ... apparently ... In other words, classes that normally use each (eg Array, Hash, String) include this Enumerable module.
If you find each process, you might do the same without using each. Let's stop and look for a way to call without using each. Also, depending on what you want to do, using a different Enumerable method can be cleaner.
Aside from the difficult things, let's take a look at the things that I often point out. For things that are more than business, I will try to give meaning to variables.
Case 1: select
Before
arr = [1, 2, 3, 4, 5]
new_arr = []
arr.each do |v|
new_arr << v if v.odd?
end
p new_arr # => [1, 3, 5]
After
new_arr = arr.select(&:odd?)
p new_arr # => [1, 3, 5]
Case 2: map
Before
arr = [1, 2, 3, 4, 5]
new_arr = []
arr.each do |v|
new_arr << v * 2
end
p new_arr # => [2, 4, 6, 8, 10]
After
new_arr = arr.map { |v| v * 2 }
p new_arr # => [2, 4, 6, 8, 10]
Case 3: inject
Before
arr = [1, 2, 3, 4, 5]
sum = 0
arr.each do |v|
sum += v
end
p sum # => 15
After
arr = [1, 2, 3, 4, 5]
sum = arr.inject(:+)
p sum # => 15
Case 4: any?
The reservation status is defined as follows. I want to validate whether the status change is correct
booking_statuses = {
pending: 0,
payment_requested: 1,
paid: 2,
cancelled: 3
}
Before
def validate_booking_transition(passed_status)
if passed_status == booking_statuses[:cancelled]
allowed = [
booking_statuses[:pending],
booking_statuses[:payment_requested],
booking_statuses[:paid]
].include?(passed_status)
elsif ...
.
.
.
end
After
def validate_booking_transition(passed_status)
if passed_status == booking_statuses[:cancelled]
allowed = %i(pending payment_requested paid).any? do |v|
passed_status == booking_statuses[v]
end
elsif ...
.
.
.
end
Case 5: group_by
Before
arr = [{code: 'a', val: 1}, {code: 'a', val: 2}, {code: 'b', val: 3}, {code: 'b', val: 4}]
new_hash = {}
arr.each do |hash|
k = hash[:code]
new_hash[k] = [] if new_hash[k].nil?
new_hash[k] << hash[:val]
end
p new_hash #=> {"a"=>[1, 2], "b"=>[3, 4]}
After
new_hash = arr.group_by { |h| h[:code] }.transform_values { |grouped_arr| grouped_arr.map { |h| h[:val] } }
p new_hash #=> {"a"=>[1, 2], "b"=>[3, 4]}
Let's consider each one a little. Regarding Cases 1 to 3, it is a pattern that the processing that is done in common each, the convenient method, is used. It's almost an introduction to Enumerable. Case 4 is about the usage of Enumerable, and there is a pattern that makes redundant things more concise by using different Enumerable methods depending on what you want to do. (A little business logic element is added to make the image easier) What about Case 5? In this regard, simply spend one line and feel refreshed! I feel like it, but I think it's hard to understand. If you take a closer look, in Cases 1 to 4, put it in the iterative process,
While doing one thing like that, in Case 5
If you take a closer look, you're running more maps inside the transform_values block. At first glance, it seems to be simple to write, and you have created a double loop. If you need to do multiple things in one iteration like this, using each may be easier to understand and may have advantages in terms of processing speed.
I think that the most important index for writing code in many development sites is readability and ease of maintenance. While the each method is useful, it doesn't make sense in itself (it's basically just a loop), so sometimes it's possible that the reader doesn't know what the code writer intended. Proper use of the Enumerable method will clarify the intent of the writer and facilitate future code changes. From a perspective other than readability, I think you will be able to be more clearly aware of the effects and side effects. However, it seems to be long, so I will omit it here. However, as shown in Case 5, there may be a pattern that it is better to use each (especially if you are using the Enumerable method in the Enumerable method), so be careful. Let's do it.
What do you think. This time I briefly explained the Enumerable method with an example. Let's get used to it and write code more comfortably;)
Recommended Posts