I am doing an "Intro to Classes" exercise through an online course. The objective is to create a class Calculator
that initializes with two numbers. The numbers can then be added, subtracted, multiplied, and divided. My code seems functional on local environment:
class Calculator
def initialize(x,y)
@x, @y = x, y
end
def self.description
"Performs basic mathematical operations"
end
def add
@x + @y
end
def subtract
@x - @y
end
def multiply
@x * @y
end
def divide
@x.to_f/@y.to_f
end
end
But the site has Rspec specs:
describe "Calculator" do
describe "description" do
it "returns a description string" do
Calculator.description.should == "Performs basic mathematical operations"
end
end
describe "instance methods" do
before { @calc = Calculator.new(7, 2) }
describe "initialize" do
it "takes two numbers" do
expect( @calc.x ).to eq(7)
expect( @calc.y ).to eq(2)
end
end
describe "add" do
it "adds the two numbers" do
expect( @calc.add ).to eq(9)
end
end
describe "subtract" do
it "subtracts the second from the first" do
expect( @calc.subtract ).to eq(5)
end
end
describe "multiply" do
it "should return a standard number of axles for any car" do
expect( @calc.multiply ).to eq(14)
end
end
describe "divide" do
it "divides the numbers, returning a 'Float' if appropriate" do
expect( @calc.divide ).to eq(3.5)
end
end
end
end
and the site's spec throws a NoMethodError:
NoMethodError
undefined method `x' for #<Calculator:0x007feb61460b00 @x=7, @y=2>
exercise_spec.rb:14:in `block (4 levels) in <top (required)>'
Just add this line
attr_reader :x, :y
Here is the corrected code :
class Calculator
attr_reader :x, :y
def initialize(x,y)
@x, @y = x, y
end
def self.description
"Performs basic mathematical operations"
end
def add
# once you defined reader method as above you can simple use x to get the
# value of @x. Same is true for only y instead of @y.
x + y
end
def subtract
x - y
end
def multiply
x * y
end
def divide
x.to_f/y.to_f
end
end
Look the below spec code :-
describe "initialize" do
it "takes two numbers" do
expect( @calc.x ).to eq(7)
expect( @calc.y ).to eq(2)
end
#...
You are calling @calc.x
and @calc.y
. But you didn't define any method named as #x
and #y
as instance methods inside the class Calculator
. Which is why you got very definitive exception as NoMethod error
.
When you will write attr_reader :x, :y
it will create those methods for you internally. Read this answer to understand reader and writer method in Ruby.