One of the reasons why Ruby is my favorite language is that it has many shortcuts and can do a lot with a few lines of code. &
(ampersand) operator is one great example.
A quick explanation of how &
works in Ruby:
# These two calls are equivalent:
numbers.select { |number| number.even? }
numbers.select(&:even?)
&
calls the to_proc
method on the following object which is a symbol :even?
in the example above. (the to_proc
method is implemented on symbols.) This means the object will be encapsulated as a block of code (as a Proc object), and then passed to the given method.
This might still look weird to you as it did to me in the beginning because .even?
is a built-in method in Ruby. Why can I use it as a symbol? This works because method names in Ruby are internally stored as symbols. For the same reason, you can use this &
shortcut for the methods you define as well.
Let's see the examples with Ruby Enumerable that you use everyday:
1. find
# Returns the first admin user
# BAD
def find_admin(users)
users.find { |user| user.admin? }
end
# GOOD
def find_admin(users)
users.find(&:admin?)
end
2. select
# Returns all the admin users
# BAD
def find_admins(users)
admins = []
users.each do |user|
admins << user if user.admin?
end
admins
end
# GOOD
def find_admins(users)
users.select(&:admin?)
end
3. count
# Returns the number of the admin users
# BAD
def count_admin(users)
count = 0
users.each do |user|
count += 1 if user.admin?
end
count
end
# GOOD
def count_admin(users)
users.count(&:admin?)
end
4. map
# Returns an array of each user's name
# BAD
def user_names(users)
names = []
users.each do |user|
names << user.name
end
names
end
# GOOD
def user_names(users)
users.map(&:name)
end
5. any?
# Returns true if at least one user exists.
# BAD
def contains_nil?(users)
users.each do |user|
return true if user.nil?
end
false
end
# GOOD
def contains_nil?(users)
users.any?(&:nil?)
end
6. max
/max_by
# Returns the oldest user.
# BAD
def oldest_user(users)
oldest = nil
users.each do |user|
oldest = user if oldest.nil? || user.age > oldest.age
end
oldet
end
# GOOD
def oldest_user(users)
users.max_by(&:age)
end
Knowing this, when you iterate over an array using a block where you simply return object.method
, you will notice code smells and consider using &
operator instead.
Top comments (2)
Nice list of methods to use !!! Thank you
Thank you for reading!