Collections
Prefer literal array and hash creation notation (unless you need to pass parameters to their constructors, that is). [link]
# bad arr = Array.new hash = Hash.new # good arr = [ ] hash = { }
Prefer
%w
to the literal array syntax when you need an array of words (non-empty strings without spaces and special characters in them). [link]# bad STATES = ["draft", "open", "closed"] # good STATES = %w[draft open closed]
Prefer
%i
to the literal array syntax when you need an array of symbols (and you don't need to maintain Ruby 1.9 compatibility). [link]# bad STATES = [:draft, :open, :closed] # good STATES = %i[draft open closed]
Avoid comma after the last item of an
Array
orHash
when the items are not on separate lines. [link]# good: easier to move/add/remove items VALUES = [ 1001, 2020, 3333, ] # bad VALUES = [1001, 2020, 3333, ] # good VALUES = [1001, 2020, 3333]
Avoid the creation of huge gaps in arrays. [link]
arr = [] arr[100] = 1 # now you have an array with lots of nils
When accessing the first or last element from an array, prefer
first
orlast
over[0]
or[-1]
. [link]Use
Set
instead ofArray
when dealing with unique elements.Set
implements a collection of unordered values with no duplicates. This is a hybrid ofArray
's intuitive inter-operation facilities andHash
's fast lookup. [link]Prefer symbols instead of strings as hash keys. [link]
# bad hash = {"one" => 1, "two" => 2, "three" => 3} # good hash = {one: 1, two: 2, three: 3}
Avoid the use of mutable objects as hash keys. [link]
Use the Ruby 1.9 hash literal syntax when your hash keys are symbols. [link]
# bad hash = {:one => 1, :two => 2, :three => 3} # good hash = {one: 1, two: 2, three: 3}
Don't mix the Ruby 1.9 hash syntax with hash rockets in the same hash literal. When you've got keys that are not symbols stick to the hash rockets syntax. [link]
# bad {a: 1, "b" => 2} # good {:a => 1, "b" => 2}
Use
Hash#key?
instead ofHash#has_key?
andHash#value?
instead ofHash#has_value?
. As noted here by Matz, the longer forms are considered deprecated. [link]# bad hash.has_key?(:test) hash.has_value?(value) # good hash.key?(:test) # or hash.include?(:test) hash.value?(value)
Use
Hash#fetch
when dealing with hash keys that should be present. [link]heroes = {batman: "Bruce Wayne", superman: "Clark Kent"} # bad: if we make a mistake we might not spot it right away heroes[:batman] # => "Bruce Wayne" heroes[:supermann] # => nil # good: fetch raises a KeyError making the problem obvious heroes.fetch(:supermann)
Introduce default values for hash keys via
Hash#fetch
as opposed to using custom logic. [link]batman = {name: "Bruce Wayne", is_evil: false} # bad: if we just use || operator with falsy value we won't get the expected result batman[:is_evil] || true # => true # good: fetch work correctly with falsy values batman.fetch(:is_evil) { true } # => false
Prefer the use of the block instead of the default value in
Hash#fetch
. [link]batman = {name: "Bruce Wayne"} # bad: if we use the default value, we eager evaluate it # so it can slow the program down if done multiple times batman.fetch(:powers, obtain_batman_powers) # obtain_batman_powers is an expensive call # good: blocks are lazy evaluated, so only triggered in case of KeyError exception batman.fetch(:powers) { obtain_batman_powers }
Use
Hash#values_at
when you need to retrieve several values consecutively from a hash. [link]# bad email = data["email"] username = data["nickname"] # good email, username = data.values_at("email", "nickname")
Rely on the fact that as of Ruby 1.9 hashes are ordered. [link]
Do not modify a collection while traversing it. [link]
When accessing elements of a collection, avoid direct access via
[n]
by using an alternate form of the reader method if it is supplied. This guards you from calling[]
onnil
. [link]# bad Regexp.last_match[1] # good Regexp.last_match(1)
When providing an accessor for a collection, provide an alternate form to save users from checking for
nil
before accessing an element in the collection. [link]# bad def awesome_things @awesome_things end # good def awesome_things(index = nil) if index && @awesome_things @awesome_things[index] else @awesome_things end end