2016-11-27 5 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

それに '.times'を呼び出すために、配列がどのように知っておく必要がありますので、' @のcalculator'は、配列であります'.x 'に応答します。私は、配列ではなく、RPNCalculatorのインスタンスで '.times'を呼びたいと思います。インスタンスメソッドから '.times'を呼び出すので、' self.times'を呼び出すか、Rubyの規約に従うために 'self'を省略し、' n ==:* 'なら' times 'を呼び出します。オペランドの配列が 'calculator 'の代わりに' operand'のように呼ばれていた場合は、全体が少し混乱するかもしれません。 – moveson

+1

* .timesメソッドは配列のために機能するはずです* ArrayクラスのRubyドキュメントはこちら:http://ruby-doc.org/core-2.3.3/Array.html。 times()メソッドはどこにありますか? *一般的に、なぜエラーメッセージが表示されるのですか?*あなたは '[1,2,3] x()'や '@calculator = [1、2、3];と書くことができません。 @ calculator.times() 'Arrayクラスは' times() 'メソッドを定義していないためです。 – 7stud

+0

ようこそスタックオーバーフローへ。 「[mcve]」をお読みください。問題を再現するのに必要な最低限のコードに減らすと、役立ちます。そして、そのプロセスの間にあなた自身が問題を見つけることがよくあります。 –

答えて

1

私はそれをこのような何かしたい:あなたは正しくRPNCalculatorのクラス定義を使用していない

3.1415929203539825 

:、実行すると、出力

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 

を。あなたのコードでは、@calculatorは配列ですが、配列は配列ではなくRPNCalculatorの一部であるため、さまざまなメソッドについては何も分かりません。変数がクラスにあるからといって、そのクラスのメソッドを継承しているわけではありません。まだそれがどんなタイプであってもそれは始まりました。

注:あなたは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

関連する問題