I've written the classic fizzbuzz code.
The spec:
describe "can determine fizzbuxx output for" do
it "3" do
expect(Fizzbuzz.nums(3)).to eq "123fizz"
end
end
The code:
class Fizzbuzz
def self.nums(n)
result=""
(1..n).each do |inner|
puts "inner #{inner}"
result << inner
if (inner % 3)==0
result << 'fizz'
end
if (inner % 5)==0
result << 'buzz'
end
end
result
end
end
Why am I getting \u001
... instead of 1
?
Failures:
1) can determine fizzbuxx output for 3
Failure/Error: expect(Fizzbuzz.nums(3)).to eq "123fizz"
expected: "123fizz"
got: "\u0001\u0002\u0003fizz"
(compared using ==)
# ./fizzbuzz_spec.rb:5:in `block (2 levels) in <top (required)>'
Is it some sort of utf-8 issue?
In Ruby for string concatenation: <<
, if the object is an Integer, it is considered as a codepoint, and is converted to a character before concatenation. And since Ruby 1.9 default encoding is UTF-8. The codepoints are forced to be encoded with UTF-8:
1.chr(Encoding::UTF_8)
# => "\u0001"
So, when you're doing this:
"" << 1
Ruby actually consider 1
as a codepoint and try to convert it to string with UTF-8 encoding, and will actually does this instead:
"" << 1.chr(Encoding::UTF_8)
#=> "\u0001"
So, to solve your problem. You can explicitly convert Fixnum to String by changing code to:
result << inner.to_s
or with String interpolation:
result << "#{inner}"
It is the expected behaviour of the String#<<
method. From the Ruby documentation:
Concatenates the given object to str. If the object is a Integer, it is considered as a codepoint, and is converted to a character before concatenation.
You have to explicitly convert the integer to a string before appending:
'' << 1 # => "\u0001"
'' << 1.to_s => "1"
For small numbers their type is a FixNum [ Holds Integer values that can be represented in a native machine word (minus 1 bit). ]
result << inner
Explicitly convert it to a String and you'll get the results you want.
result << inner.to_s