除了.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”是我打算在数组中定义的类中定义的方法。我想我会通过将字符串转换为数组然后在其上运行自定义方法来“评估”字符串,但我不知道该怎么做。
答案 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