Home > database >  Ruby comparison with an OR operator - strange behaviour
Ruby comparison with an OR operator - strange behaviour

Time:03-09

Below code should be a good example of strange Ruby behaviour when it comes to the OR operator:

  def search_by_name_active
    if request.path == (name_search_registrants_path \
      || new_registrant_path)
      'active'
    end
  end

And the specs:

  describe "#search_by_name_active" do
    it "should return active if current page is new_registrant" do
      allow(helper.request).to receive(:path).and_return(new_registrant_path)
      expect(helper.search_by_name_active).to eq('active')
    end
  end

Which gives me an error:

 Failure/Error: expect(helper.search_by_name_active).to eq('active')

   expected: "active"
        got: nil

If I remove the brackets:

  def search_by_name_active
    if request.path == name_search_registrants_path \
      || new_registrant_path
      'active'
    end
  end

The first spec will passed but not the below one:

it "should return nil if current page is not search_by_name" do
  allow(helper.request).to receive(:path).and_return(id_search_registrants_path)
  expect(helper.search_by_name_active).to be_nil
end

 Failure/Error: expect(helper.search_by_name_active).to be_nil

   expected: nil
        got: "active"

WTF?! Is there any other way to write this logical equation besides an additional if like below?

  def search_by_name_active
    if request.path == name_search_registrants_path
      'active'
    elsif request.path == new_registrant_path
      'active'
    end
  end

CodePudding user response:

This behaviour is expected in all programming languages, not just ruby. To simplify your example a little:

x == (a || b)

...is not equivalent to:

(x == a) || (x == b)

The first expression is evaluating (a || b) before comparing it to x. So you're only comparing x to one of the values, not both of them.

The generic way to write this in all programming languages would to instead use the second code sample above. Or in other words, using your specific example:

if request.path == name_search_registrants_path \
  || request.path == new_registrant_path

Or, there are a couple of ruby-specific ways we can shorten this code:

# Works in any ruby code
if [name_search_registrants_path, new_registrant_path].include?(request.path)

# Works in any rails code
if requst.path.in? [name_search_registrants_path, new_registrant_path]

The second example is rails-specific, because it's using this extension to the core ruby language.

  • Related