Last active
November 8, 2015 17:31
-
-
Save vancluever/18e653eb7faba1f09003 to your computer and use it in GitHub Desktop.
Array#index - better (and rubocop detectable) single-line conditional block structuring
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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