2016-11-27 73 views
0

除了.evaluate方法外,我的代碼似乎都能正常工作。從程序我很努力去理解爲什麼我會在我的RPN計算器中收到一個錯誤消息

Failures: 

    1) RPNCalculator evaluates a string 
    Failure/Error: expect(calculator.evaluate("1 2 3 * +")).to eq(
    NoMethodError: 
     undefined method `times' for [1, 2, 3]:Array 
    # ./lib/12_rpn_calculator.rb:78:in `block in evaluate' 
    # ./lib/12_rpn_calculator.rb:75:in `each' 
    # ./lib/12_rpn_calculator.rb:75:in `evaluate' 
    # ./spec/12_rpn_calculator_spec.rb:144:in `block (2 levels) in <top (required)>' 

Finished in 0.00381 seconds (files took 0.10201 seconds to load) 
9 examples, 1 failure 

Failed examples: 

rspec ./spec/12_rpn_calculator_spec.rb:143 # RPNCalculator evaluates a string 

我收到錯誤消息

class RPNCalculator 





def initialize 
    @calculator = Array.new 
    end 

    def push(x) 
     @calculator << x 
    end 

    def value 
     @calculator.last 
    end 


    def plus 
     error_message 

      sum = @calculator.pop + @calculator.pop 
     @calculator << sum 
    end 



    def minus 
     error_message 
     #@calculator.reverse! 
     #difference = @calculator.pop - @calculator.pop 
     first = @calculator.pop 
     second = @calculator.pop 
     difference = second - first 
     # 
     @calculator << difference 
    end 

    def divide 
     error_message 
     @calculator = @calculator.map {|n| n.to_f} 
     divisor = @calculator.pop ; dividend = @calculator.pop 
     quotient = (dividend/divisor) 
     @calculator << quotient 

    end 

    def times 
     error_message 
     puts @calculator.inspect 

     @calculator.map! {|n| n.to_f} 
     product = @calculator.pop * @calculator.pop 
     @calculator << product 
    end 

    def error_message 
     raise "calculator is empty" if @calculator.size < 2 
    end 

    def tokens(string) 
     operators = ["+", "-", "/", "*"] 
     string.split.map! {|i| 
     if operators.include?(i) 
      i.to_sym 
     else 
      i.to_i 
     end 
     } 
    end 

    def evaluate(rpn) 
     @calculator = tokens(rpn).select {|t| t.is_a?Integer} 
     operators = tokens(rpn).select{|t| t.is_a?Symbol} 

     operators.each {|n| 
     @calculator.plus if n == :+ 
     @calculator.minus if n == :- 
     @calculator.times if n == :* 
     @calculator.divide if n == :/ } 

    end 

end 

在我看來,該.times方法應該用於數組。所以,我想了解發生了什麼。有一些基本問題嗎?還是有錯字?一般來說,爲什麼我會收到錯誤消息?

編輯:這裏有我需要通過規格:

require "12_rpn_calculator" 

describe RPNCalculator do 
    attr_accessor :calculator 

    before do 
    @calculator = RPNCalculator.new 
    end 

    it "adds two numbers" do 
    calculator.push(2) 
    calculator.push(3) 
    calculator.plus 
    expect(calculator.value).to eq(5) 
    end 

    it "adds three numbers" do 
    calculator.push(2) 
    calculator.push(3) 
    calculator.push(4) 
    calculator.plus 
    expect(calculator.value).to eq(7) 
    calculator.plus 
    expect(calculator.value).to eq(9) 
    end 

    it "subtracts the second number from the first number" do 
    calculator.push(2) 
    calculator.push(3) 
    calculator.minus 
    expect(calculator.value).to eq(-1) 
    end 

    it "adds and subtracts" do 
    calculator.push(2) 
    calculator.push(3) 
    calculator.push(4) 
    calculator.minus 
    expect(calculator.value).to eq(-1) 
    calculator.plus 
    expect(calculator.value).to eq(1) 
    end 

    it "multiplies and divides" do 
    calculator.push(2) 
    calculator.push(3) 
    calculator.push(4) 
    calculator.divide 
    expect(calculator.value).to eq((3.0/4.0)) 
    calculator.times 
    expect(calculator.value).to eq(2.0 * (3.0/4.0)) 
    end 

    it "resolves operator precedence unambiguously" do 
    # 1 2 + 3 * => (1 + 2) * 3 
    calculator.push(1) 
    calculator.push(2) 
    calculator.plus 
    calculator.push(3) 
    calculator.times 
    expect(calculator.value).to eq((1+2)*3) 

    @calculator = RPNCalculator.new 
    # 1 2 3 * + => 1 + (2 * 3) 
    calculator.push(1) 
    calculator.push(2) 
    calculator.push(3) 
    calculator.times 
    calculator.plus 
    expect(calculator.value).to eq(1+(2*3)) 
    end 

    it "fails informatively when there's not enough values stacked away" do 
    expect { 
     calculator.plus 
    }.to raise_error("calculator is empty") 

    expect { 
     calculator.minus 
    }.to raise_error("calculator is empty") 

    expect { 
     calculator.times 
    }.to raise_error("calculator is empty") 

    expect { 
     calculator.divide 
    }.to raise_error("calculator is empty") 
    end 

    # extra credit 
    it "tokenizes a string" do 
    expect(calculator.tokens("1 2 3 * + 4 5 - /")).to eq(
     [1, 2, 3, :*, :+, 4, 5, :-, :/] 
    ) 
    end 

    # extra credit 
    it "evaluates a string" do 
    expect(calculator.evaluate("1 2 3 * +")).to eq(
     ((2 * 3) + 1) 
    ) 

    expect(calculator.evaluate("4 5 -")).to eq(
     (4 - 5) 
    ) 

    expect(calculator.evaluate("2 3 /")).to eq(
     (2.0/3.0) 
    ) 

    expect(calculator.evaluate("1 2 3 * + 4 5 - /")).to eq(
     (1.0 + (2 * 3))/(4 - 5) 
    ) 
    end 
end 

,你可以看到,「.times」是,我打算在陣列工作類中定義的方法。我想我會「評估」一個字符串,將其轉換爲一個數組,然後在其上運行自定義方法,但我不知道該怎麼做。

+1

'@ calculator'是一個數組,所以爲了調用'.times'就可以了,陣列需要知道如何迴應'.times'。我想你想在RPNCalculator的一個實例上調用'.times',而不是在一個Array上。既然你是從一個實例方法調用'.times',你可以調用'self.times',或者遵循Ruby約定,只要省略'self'並且調用'if == ==:*'。整個事情可能會有點混亂,如果你的操作數數組被稱爲像'operands'而不是'calculator.' – moveson

+1

*在我看來,.times方法應該適用於數組。* - 你可以通過這裏是類Array的ruby文檔:http://ruby-doc.org/core-2.3.3/Array.html。你在哪裏看到times()方法? *一般來說,爲什麼我會收到錯誤信息?*因爲您不能寫:[1,2,3] .times()和'@calculator = [1,2,3]; @ calculator.times()'因爲Array類沒有定義'times()'方法。 – 7stud

+0

歡迎來到Stack Overflow。請閱讀「[mcve]」。它可以幫助我們在將代碼減少到複製問題所需的最低限度時爲您提供幫助。而且,在這個過程中,你經常會發現自己的問題。 –

回答

1

我會做這樣的事情:

class RPNCalculator 

    def initialize(s) 
    @operators = [] 
    @operands = [] 
    s.split.map { |i| 
     case i 
     when '+', '-', '/', '*' 
     @operators << i.to_sym 
     else 
     @operands << (i['.'] ? i.to_f : i.to_i) 
     end 
    } 
    end 

    def count_operands 
    raise "calculator is empty" if @operands.size < 2 
    end 

    def output 
    puts @operands.join(',') 
    end 

    def process(operator) 
    @operands.unshift([@operands.shift, @operands.shift].inject(operator)) 
    end 

    def evaluate 
    @operators.each do |o| 
     count_operands() 
     process(o) 
    end 
    end 
end 

rpn = RPNCalculator.new('355.0 113 /') 
rpn.evaluate 
rpn.output 

其中,在運行時,輸出:

3.1415929203539825 

你沒有正確使用RPNCalculator的類定義。在你的代碼中,@calculator是一個數組,但數組不知道你的各種方法,因爲它們是RPNCalculator的一部分,而不是Array。僅僅因爲變量在類中並不意味着它繼承了該類的方法;它仍然是任何類型的開始。

注:可以添加的方法在Ruby的各種方式這個類,但也有龍的這條道路,所以你想了解你在做什麼,你嘗試,因爲你可以打破無意中之前的事情。

[@operands.shift, @operands.shift].inject(operator) 

就是神奇的部分,採取的inject優勢:

[1] (pry) main: 0> [1, 1].inject(:+) 
2 
[2] (pry) main: 0> [355.0, 113].inject(:/) 
3.1415929203539825 
+0

謝謝,這顯然更清潔。儘管我必須使用分配給我的rspec測試。 – Rory

相關問題