3

I am working on Test First Ruby with rspec examples testing...

which I need to pass this test.

it "tokenizes a string" do
    calculator.tokens("1 2 3 * + 4 5 - /").should ==
      [1, 2, 3, :*, :+, 4, 5, :-, :/]
  end

And here is my code

def tokens(str)
    data = str.split(' ')
    outcomes = []
    data.collect do |x|
      if x.to_i != 0
        outcomes.push(x.to_i)
      elsif x.to_i == 0
        temp = x.gsub('"', '')
        outcomes.push(":#{temp}")
      end
    end
    outcomes
  end

However, I got these feedback. Have no idea how to get rid of the quotation mark.

Failure/Error: [1, 2, 3, :*, :+, 4, 5, :-, :/]                                                                                                                               
       expected: [1, 2, 3, :*, :+, 4, 5, :-, :/]                                                                                                                                  
            got: [1, 2, 3, ":*", ":+", 4, 5, ":-", ":/"] (using ==)   
Yumiko
  • 448
  • 5
  • 16

4 Answers4

3

The problem are not the quotation marks. Quotes mean that the element is a String type, your spec expects a Symbol.

outcomes.push(":#{temp}")

should be

outcomes.push(temp.to_sym)

To give you an idea

2.1.2 :006 > :*.class
 => Symbol 
2.1.2 :007 > ":*".class
 => String 
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
Simone Carletti
  • 173,507
  • 49
  • 363
  • 364
3

Try this:

outcomes.push(:"#{temp}")

":#{temp}" is string but this :"#{temp}" symbol with string interpolation.

=>:"+".class
#> Symbol
=> ":+".class
#> String
Roman Kiselenko
  • 43,210
  • 9
  • 91
  • 103
  • 1
    Thank you very much, it works now! Sorry I don't have enough reputation to vote you up yet :( – Yumiko Nov 14 '14 at 09:47
2

Simone Carletti already provided a solution for your problem (using to_sym), but you can further improve your code:

  • split(' ') can (in this case) be replaced with split (without arguments)
  • instead of elsif x.to_i == 0 you can use else
  • collect (or map) already creates and returns an array, you just have to provide the values

Applied to your code:

def tokens(str)
  str.split.map do |x|
    if x.to_i != 0
      x.to_i
    else
      x.to_sym
    end
  end
end

You can even write this in one line using a ternary if:

def tokens(str)
  str.split.map { |x| x.to_i != 0 ? x.to_i : x.to_sym }
end

You might have to modify your condition, since x.to_i != 0 returns false for x = "0".

Community
  • 1
  • 1
Stefan
  • 109,145
  • 14
  • 143
  • 218
  • How about `if x =~ /^[+-]?\d+$/` in place of `if x.to_i == 0` to squash the bug @JörgWMittag mentioned? Yumiko, in a real app, you also need to worry about bad data. For example, "9cats".to_i => 9`. – Cary Swoveland Nov 14 '14 at 15:25
1

":#{temp}" generates a String that starts with a colon.

But you want to translate your temp string to a symbol, like this temp.to_sym. Or you want to build a symbol like this: :"#{temp}" (note that the colon is in front of the string).

spickermann
  • 100,941
  • 9
  • 101
  • 131