我很难理解为什么我的RPN计算器中的方法收到错误消息

时间:2016-11-27 17:21:51

标签: ruby calculator rpn

除了.evaluate方法之外,我的代码中的所有内容似乎都在运行。

我收到错误消息:

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方法应该适用于Arrays。所以,我想了解发生了什么。有一些根本问题吗?还是有拼写错误?一般来说,为什么我收到错误消息?

编辑:这是我需要传递的规范:

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 个答案:

答案 0 :(得分: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是一个数组,但Arrays对您的各种方法一无所知,因为它们是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