D1D2D3D4D5
D1D2D3D4D5

Reputation: 151

Understanding impact of false in method

My method handles the program loop for true/false. The code takes a number of integers, then checks:

  1. If the submitted value is a number
  2. If the number is between 1 and 100

The code is:

def self.number_validator(*numbers)
    numbers.each do |number|
        unless number.is_a?(Integer)
            puts "#{number} is not an integer" 
            return false
        end
        unless number > 0 && number < 100
            puts "#{number} is out of range"
            return false
        end
    end
    return true
end

My understanding is that returning false will exit the whole method. I'm concerned and want to make sure that it does not break only the loop and return to the return true section. I want to make sure that the true value doesn't get triggered by the false value closing the loop and moving back to the overall method (rather than actually just reporting false and stopping the method).

Upvotes: 0

Views: 57

Answers (2)

Tom Lord
Tom Lord

Reputation: 28305

I'm concerned (and want to make sure) that [it works].

It does work (almost). With the slight mistake that you've written < 100 instead of <= 100.

return exits the method immediately. The keyword break, on the other hand, would only exit the loop.

But don't just take my word for it. (And asking someone on StackOverflow whether or not your code works isn't an efficient way to go about testing it!) Let's write a few tests for your code:

require 'rspec'

RSpec.describe 'number_validator' do
  subject { number_validator(*input) }

  context 'integers only (valid input)' do
    let(:input) { [1, 5, 80, 100] }
    it { is_expected.to eq true }
  end

  context 'non positive integer' do
    let(:input) { [1, 5, 0] }
    it { is_expected.to eq false }
  end

  context 'integer greater than 100' do
    let(:input) { [1, 5, 101] }
    it { is_expected.to eq false }
  end

  context 'non integer' do
    let(:input) { [1, 5, 'BAD'] }
    it { is_expected.to eq false }
  end
end

You could write more edge cases too if you like, e.g. what if there is no input given (number_validator()), or a negative number (number_validator(-1)), or a non-integer number (number_validator(3.5)), ...

Now that we have some tests, let's try rewriting that method slightly to something more elegant. We can be confident that it still works, because the tests should still pass!

Rather than using Array#each with multiple return statements, we can instead use Enumerable#all? to do the same thing in much less code (if you're willing to drop the puts statements):

def number_validator(*numbers)
  numbers.all? { |number| number.is_a?(Integer) && number > 0 && number <= 100 }
end

We can then simplify this even further, using Comparable#between?:

def number_validator(*numbers)
  numbers.all? { |number| number.is_a?(Integer) && number.between?(1, 100) }
end

Upvotes: 4

dengsauve
dengsauve

Reputation: 54

Nadnerb, return will end any further continuation of the code, whereas break will exit the current loop and continue on to the next set of instructions.

Upvotes: 1

Related Questions