String#end_with?
instead of a regex match anchored to the end of the string RB-PR1009Instead of searching for a string pattern at the end of a string using regex, it is more efficient to simply use end_with?
instead.
Sizes of objects that we know to be static should not be computed. For example, we know the size of array in the snippet below to be 3
. We can directly use the value instead of calculating it first.
flat_map
to flatten maps RB-PR1011flat_map
is more efficient than flatten
. Refer here.
=~
in places where the MatchData
returned by #match
will not be used RB-PR1016The return value of =~
is an integral index/nil
and is more performant.
size
instead of count
RB-PR1020size
should be preferred over count
. Read more here.
tr
/delete
instead of gsub
RB-PR1022tr
/delete
are more efficient than gsub
.
It is more efficient to replace Hash#merge!
with Hash#[]=
.
case
..when
can be modified for performance RB-PR1002Reordering when
conditions with a splat to the end of the when
branches can improve performance. Ruby has to allocate memory for the splat expansion every time that the case
-when
statement is run. Since Ruby does not support fall through inside of case
-when
, like some other languages do, the order of the when
branches should not matter. By placing any splat expansions at the end of the list of when
branches we will reduce the number of times that memory has to be allocated for the expansion. The exception to this is if multiple when
conditions can be true for any given condition. A likely scenario for this is defining a higher level when
condition to override a condition that is inside of the splat expansion.
casecmp
RB-PR1003Case-insensitive string comparison can be done more efficiently using casecmp
.
Methods compact
, flatten
and map
generate a new intermediate array that is discarded. It is faster to mutate the array when we know it's safe.
sort
, max
and min
with respective _by
methods RB-PR1005sort { |a, b| a.foo <=> b.foo }
can be replaced by sort_by(&:foo)
. This is true for max
and min
methods, too. All the sort
, min
and max
methods with block in the following example can be replaced by the respective _by
methods.
count
instead of select
/reject
RB-PR1006Usages of count
on an Enumerable
that follow calls to select
or reject
can be made more efficient. Querying logic can instead be passed to the count
call.
detect
method RB-PR1007Usages of select.first
, select.last
, find_all.first
, and find_all.last
can be changed to use detect
instead. ActiveRecord compatibility: ActiveRecord does not implement a detect
method and find
has its own meaning.
start_with?
/end_with?
can be combined RB-PR1008Double #start_with?
or #end_with?
calls separated by ||
, in some cases, can be replaced with an single #start_with?
/#end_with?
call.
Hash#keys.include?
is less efficient than Hash#key?
because the former allocates a new array and then performs an O(n) search through that array, while Hash#key?
does not allocate any array and performs a faster O(1) search for the key. Hash#values.include?
is less efficient than Hash#value?
. While they both perform an O(n) search through all of the values, calling values
allocates a new array while using value?
does not.
Struct
over OpenStruct
to optimize the performance RB-PR1013Instantiation of an OpenStruct
invalidates Ruby global method cache as it causes dynamic method definition during program runtime. This could have an effect on performance, especially in case of single-threaded applications with multiple OpenStruct
instantiations.
Range#cover?
instead of Range#include?
RB-PR1014Range#include?
iterates over each item in a Range
to see if a specified item is there. In contrast, Range#cover?
simply compares the target item with the beginning and end points of the Range
. In a great majority of cases, this is what is wanted. For example:
yield
instead of block call RB-PR1015Use of a &block
parameter and block.call
can be replaced by yield
in some cases.
match?
over match
RB-PR1018String#match?
, Regexp#match?
, and Symbol#match?
are faster than match
, because the methods avoid creating a MatchData
object or saving backref. So, when MatchData
is not used, match?
can be used instead of match
.
reverse_each
instead of reverse.each
RB-PR1019reverse_each
is more efficient than reverse.each
. Read more here.