Rubocop for catching conditional assignment

183 Views Asked by At

We have some code that bit us in production and I am wondering if there is a way to prevent it in the future. We are using ruby and rubocop but I could find a cop to fit my needs.

The code looks like:

a = 1
b = 1
return ((a == 1) || (b = 2)) # should return a boolean, false in  this case

Line 3 is where we had the issue, we missed an equal sign (so it was a single equal instead of a double equal) when calculating a boolean value.

Is there anything off the shelf we could use to catch this error in ruby or rubocop?

Thanks,

2

There are 2 best solutions below

0
jansha On BEST ANSWER

These were treated as assignment, it can't ensure and confirm that the user is providing an assignment or he is validating equality.

i have came accross similar thing (different usecase) and i achieved by creating custom cop extension.

It is not an appreciatable way to override the exisisting functionality, But however you can achieve this by defining custom cops by creating your own extensions.

for example You can create a new ruby -rubocop file like assignment_mistake_correction_cop.rb and you can make necessary changes in this file.

in your yaml file, you can include this file like

#.rubocop.yml

require: './assignment_mistake_correction_cop.rb'

as example changes for the assignment_mistake_correction_cop file, check the code below which i have implemented for some other usecase, this code is updated as per your requirement.

# assignment_mistake_correction_cop.rb
require 'rubocop'

module RuboCop
  module Cop
    module CustomWrittenCops
      class AssignmentMistakeCorrectionCop < Cop

        MSG = 'Assignment mistake . Use `==` for comparison instead of `=`.'.freeze

        def on_send(node)
          receiver, method_name, *args = *node
          return if  !(method_name == :return && args.size == 1)

          arg = args.first

          receiver, method_name, *args = *arg

          arg1, arg2 = args

          if assignment_has_a_mistake?(arg1)
            add_offense(arg1, location: :expression)
          elsif assignment_has_a_mistake?(arg2)
            add_offense(arg2, location: :expression)
          end

        end

        private

        def assignment_has_a_mistake?(val)
          val.assignment?
        end
      end
    end
  end
end

Note: This is a sample code which i modified based on your use case.

for more references, may be you can look into rubocop/cop/corrector.rb file.

here the corrector class is responsible for applying the fix (i.e autocorrect fix).

2
Andy Waite On

There is a cop Lint/AssignmentInCondition. If you had written:

return if a == 1 || b = 2

then it would have reported:

Use == if you meant to do a comparison or wrap the expression in parentheses to indicate you meant to assign in a condition.

But since the expression had already been wrapped in (unnecessary) parenthesis, RuboCop ignored this.