Ruby has some useful methods for enumerable (Array, Hash, etc), this post will talk about usage of any?, all?, and none?.
For examples used on this post, an Order model might have many Payment model (customer can pay order using split payments).
To check if an order has any paid payments, a loop-based implementation might look like this :
has_paid_payment = false
order.payments.each do |payment|
if payment.status == "paid"
# one of the payment is paid
has_paid_payment = true
break
end
end
if has_paid_payment
# ...
end
We can simplify the code above using any? like this :
if order.payments.any?{ |payment| payment.status == 'paid'}
# this will be executed if there is at least one paid payment
end
any? method can take in a block, and it will return true if the block ever returns a value that is not false or nil. (ie. true, or 123, or “abc”)
If no block is supplied, it will perform a self check for the elements:
order.payments.any?
# is equivalent to
order.payments.any? { |payment| payment }
To check if all payments has been paid for an order, a loop-based implementation might look like this:
fully_paid = true
order.payments.each do |payment|
if payment.status != "paid"
# one of the payment is not paid, hence not fully paid
fully_paid = false
break
end
end
if fully_paid
# ...
end
We can simplify the code above using all? like this :
if order.payments.all?{ |payment| payment.status == 'paid'}
# this will be executed if all payments are paid
end
all? method can take in a block, and it will return true if the block never returns a value that is false or nil for all of the elements.
If no block is supplied, it will perform a self check for the elements:
order.payments.all?
# is equivalent to
order.payments.all? { |payment| payment }
This is the opposite of all?.
none? method accepts a block, and only returns true if the block never returns true for all elements.
if order.payments.none? { |payment| payment.status == 'paid' }
# this will be executed if there is no paid payment for the order
end
If no block is supplied, it will perform a self check for the elements:
order.payments.none?
# is equivalent to
order.payments.none? { |payment| payment }
By utilizing any?, all? and none?, we can remove the usage of loop and make it more readable.