2016-11-27 1 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'는, 배열이다

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

inject을 활용, 마법의 일부이다 '.times '에 응답합니다. RPNCalculator의 인스턴스에서'.times'를 호출하고 Array에서는 호출하지 않으려한다고 생각합니다. 인스턴스 메소드에서'.times'를 호출하면'self.times'를 호출하거나, Ruby 규칙에 따라'self'를 생략하고'n == : * '이면'times를 호출하면됩니다. 당신의 피연산자 배열이'calculator '대신에'피연산자'와 같은 것으로 불려지면 모든 일이 다소 덜 혼란 스러울 수도 있습니다. – moveson

+1

* .times 메서드는 배열에 대해 작동해야합니다. * - 당신은 Array 클래스의 루비 문서는 다음과 같습니다 : 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

스택 오버플로에 오신 것을 환영합니다. "[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 

어떤, 실행, 출력 : 당신은 제대로 RPNCalculator의 클래스 정의를 사용하지 않는

3.1415929203539825 

. 귀하의 코드에서 @calculator은 배열이지만 배열은 배열이 아니라 RPNCalculator의 일부이기 때문에 다양한 메소드에 대해 아무것도 모릅니다. 변수가 클래스에 있다고해서 그것이 해당 클래스의 메소드를 상속 받았다는 것을 의미하지는 않습니다. 그것은 여전히 ​​어떤 유형이든간에 시작되었습니다.

참고 : 입니다. Ruby에서 다양한 방법으로 해당 클래스에 메소드를 추가하지만 그 도로 아래에 드래곤이 있으므로 의도하지 않게 휴식을 취할 수 있기 때문에 시도하기 전에 무엇을하는지 이해하고 싶을 것입니다. . , 배열 방법을 알고 있어야합니다 그것을`.times`를 호출하려면 있도록

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

감사합니다. 분명히 훨씬 깨끗합니다. 비록 나에게 배정 된 rspec 테스트를해야만한다. – Rory

관련 문제