Search code examples
rubyrake-testtest-first

String can't be coerced into Fixnum in TestFirst lesson


I'm working through the TestFirst.org tutorials and have gotten an error message I can't untangle:

 Failure/Error: repeat("hello").should == "hello hello"
 TypeError:
   String can't be coerced into Fixnum
 # ./03_simon_says/simon_says.rb:13:in `+'
 # ./03_simon_says/simon_says.rb:13:in `block in repeat'
 # ./03_simon_says/simon_says.rb:12:in `times'
 # ./03_simon_says/simon_says.rb:12:in `repeat'
 # ./03_simon_says/simon_says_spec.rb:39:in `block (3 levels) in <top (required)>'

Here is the code those errors are talking about ("def repeat" is line 09)

def repeat (say, how_many=2)
    repetition = say
    how_many = how_many-1

    how_many.times do |repetition|
        repetition = repetition + " " + say
    end

    return repetition
end

And here is the rake test that set it off:

it "should repeat a number of times" do
  repeat("hello", 3).should == "hello hello hello"
end

I understand that the error message is about trying to use a string like a numeric value but I can't see how or where that is happening


Solution

  • The below is the problem source

    repetition = repetition + " " + say
    #              ^ this is a Fixnum
    

    In the line repetition + " " + say, you are trying to do a concatenation between a Fixnum and String instance, which caused the error String can't be coerced into Fixnum.

    2.1.2 :001 > 1 + ""
    TypeError: String can't be coerced into Fixnum
            from (irb):1:in `+'
            from (irb):1
            from /home/arup/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'
    2.1.2 :002 >
    

    Your code can be written as :

    #!/usr/bin/env ruby
    
    def repeat (say, how_many = 1)
      ("#{say} " * how_many).strip
    end
    

    In my test_spec.rb file :-

    require_relative "../test.rb"
    
    describe "#repeat" do
      it "returns 'hello' 3 times" do
        expect(repeat('hello', 3)).to eq('hello hello hello')
      end
    end
    

    Lets run the test :-

    arup@linux-wzza:~/Ruby> rspec spec/test_spec.rb
    .
    
    Finished in 0.00129 seconds (files took 0.1323 seconds to load)
    1 example, 0 failures
    arup@linux-wzza:~/Ruby>
    

    update

    repetition = say
    how_many = how_many-1
      how_many.times do |repetition|
    

    If you think, repetition declared outside of the block and inside the block are same, you are completely wrong. They are different, as they created in 2 different scopes. See the below example :-

    var = 2
    2.times { |var| var = 10 } # shadowing outer local variable - var
    var # => 2