Skip to content

Instantly share code, notes, and snippets.

@vancluever
Last active November 8, 2015 17:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vancluever/18e653eb7faba1f09003 to your computer and use it in GitHub Desktop.
Save vancluever/18e653eb7faba1f09003 to your computer and use it in GitHub Desktop.
Array#index - better (and rubocop detectable) single-line conditional block structuring
# Rubocop (https://github.com/bbatsov/rubocop) is pretty awesome, and
# should be a part of every rubyist's toolkit. Not only do you get basic
# syntax checking so that you know that your code actually runs, you get a
# ton of linting and style rules that will make your code more readable and
# help you avoid ambigutity issues that may lead you to do things that you
# didn't intend to do.
#
# One such useful lint rule is Lint::AssignmentInCondition, which allows one
# to avoid the classical "=" in a conditional when you meant "==", as this is
# valid ruby and will result in an assignment, which is probably not what you
# want.
#
# However, there are situations where this linter will not fire. Consider the
# following block:
a = [{ key: 'one' }, { key: 'two' }]
index = a.index { |x| x[:key] = 'two' }
puts index
puts a
# The output is:
# 0
# {:key=>"two"}
# {:key=>"two"}
#
# Here, the assignment is happening in the conditional block passed to
# Array#index, and is essentially assigning the value we want to be checking
# for to :key in the hash elements of a.
#
# Rubocop does not pick this up (for an explaniation as to why, see
# https://github.com/bbatsov/rubocop/issues/2400).
#
# Here, you might have to exercise a little bit of self-discipline in how you
# structure your conditional blocks. This pattern for array searching is
# powerful and there is nothing wrong with the readability of the code, and
# with a modificaiton, rubocop *can* pick it up.
b = [{ key: 'one' }, { key: 'two' }]
index = b.index { |x| true if x[:key] = 'two' }
puts index
puts b
# This gets detected by rubocop, because we have wrapped the conditional in
# an if statement. And it's even more semantic, because you are spelling out
# the truth statement in almost plain English.
#
# Of course, the correct way to structure the above is:
c = [{ key: 'one' }, { key: 'two' }]
index = c.index { |x| true if x[:key] == 'two' }
puts index
puts c
# This gives, as would be expected:
# 1
# {:key=>"one"}
# {:key=>"two"}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment