Testfirst.org - rpn_calculator - 如何在方法之间传递变量?

时间:2014-02-11 06:54:31

标签: ruby rpn test-first

我正在努力做this lesson,我显然错过了一些明显的东西!

require "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
    calculator.value.should == 5
  end

  ...

  # extra credit
  it "evaluates a string" do
    calculator.evaluate("1 2 3 * +").should ==
      ((2 * 3) + 1)

  ...

  end

end

除了@numbers之外,一切都在为我的新手工作。从evaluate方法设置@numbers不会影响其他方法中的@numbers,我真的不明白为什么。我已经尝试了所有可以google的内容,包括将@numbers更改为@@数字,但似乎没有任何帮助。我可以只评估evaluate方法中的字符串...但我已经有了一个很好的加法方法,我可以使用!

class RPNCalculator
  attr_accessor :numbers

  def initialize
    @numbers = []
  end  

  def push(n)
    @numbers.push(n)  
  end

  def plus
    @numbers.length > 1 ? @numbers.push(@numbers.pop(2).reduce(:+) ) : fail
  end

  def minus
    @numbers.length > 1 ? @numbers.push(@numbers.pop(2).reduce(:-) ) : fail
  end  

  def divide
    @numbers.length > 1 ? @numbers.push(@numbers.pop(2).inject{|x,y| x.to_f / y} ) : fail
  end

  def times
    @numbers.length > 1 ? @numbers.push(@numbers.pop(2).reduce(:*) ) : fail
  end

  def value
    @value = @numbers[-1]
  end

  def tokens(pol)
    pol.split(' ').map{|n| n.to_i.to_s == n ? n.to_i : n.to_sym}
  end

  def evaluate(pol)
    order = []
    opps = {:+ => plus, :- => minus, :/ => divide, :* => times }
    tokens(pol).reverse.chunk{|n| n.is_a?(Integer)}.each{|e,a| e == true ? a.reverse.each{|a| push(a) } : a.each {|a| order.push(a) }}
    order.reverse.each {|o| (opps[o]) }
  end

  def fail
    begin
      raise Exception.new("calculator is empty")
    end
  end

end

结果是加号返回失败,因为@numbers为空....

RPNCalculator
  adds two numbers
  adds three numbers
  subtracts the second number from the first number
  adds and subtracts
  multiplies and divides
  resolves operator precedence unambiguously
  fails informatively when there's not enough values stacked away
  tokenizes a string
  evaluates a string (FAILED - 1)

Failures:

  1) RPNCalculator evaluates a string
     Failure/Error: calculator.evaluate("1 2 3 * +").should ==
     Exception:
       calculator is empty
     # ./12_rpn_calculator/rpn_calculator.rb:59:in `fail'
     # ./12_rpn_calculator/rpn_calculator.rb:14:in `plus'
     # ./12_rpn_calculator/rpn_calculator.rb:39:in `evaluate'
     # ./12_rpn_calculator/rpn_calculator_spec.rb:134:in `block (2 levels) in '

感谢Frank Schmitt我得到了它的工作。显然,人们不会简单地将方法存储在哈希中。

正确的评估方法:

  def evaluate(pol)
    @numbers = [] # because this does 4 tests without clearing @numbers
    opps = {:+ => Proc.new {plus}, :- => Proc.new{minus}, :/ => Proc.new{divide}, :* => Proc.new{times} } # method in proc, thank you Frank :D
    tokens(pol).chunk{|n| n.is_a?(Integer)}.each{|e,a| e == true ? a.each{|a| push(a) } : a.each {|o| (opps[o].call) }}
    @numbers[0]
  end

1 个答案:

答案 0 :(得分:0)

显然,Ruby会在您将这些方法存储在opps哈希中时调用这些方法。要解决此问题,您可以使用此代码的修改版本:

  def evaluate(pol)
    order = []
    opps = {:+ => Proc.new {plus}, :- => Proc.new{minus}, :/ => Proc.new{divide}, :* => Proc.new{times} }
    tokens(pol).reverse.chunk{|n| n.is_a?(Integer)}.each{|e,a| e == true ? a.reverse.each{|a| push(a) } : a.each {|a| or
der.push(a) }}
    order.reverse.each {|o| (opps[o].call) }
  end

此版本

  • 将procs存储在opps哈希中,只需调用您的方法
  • 使用Proc.call实际调用您的方法