Let me define an instance of your SimpleMath class:
sm = SimpleMath.new
Three notes:
sm is a variable. In Ruby, variables are lowercase letters, optionally separated by underscores (for example, my_var ).- while it’s OK, to add
() after new , when new has no arguments (otherwise called “parameters”), this is optional and usually fails. - If the
return keyword is missing, Ruby returns the last calculation performed by the method. Here you usually write the last line as just self , and this will be returned. Alas, this does not matter, since returning self with or without the return keyword is not what you want.
Try the following on IRB:
sm.add(2) #=> #<SimpleMath:0x000001020ca820>
You undoubtedly expected this to return 2+0 #=> 2 , but instead return self , which, as you can see above, is actually sm ( #<SimpleMath:0x000001020ca820> ).
You can fix this by simply deleting the line:
return self
from add and subtract :
class SimpleMath def add(a,b=0) a + b end def subtract(a,b=0) a - b end end
Now
sm = SimpleMath.new sm.add(2)
However, if we try to bind another add , we have another problem:
sm.add(2).add(2,3) #=> NoMethodError: undefined method `add' for 2:Fixnum
This message is very clear: the Fixnum class, of which 2 is an instance, does not have an instance method named add . This is because you defined it for the SimpleMath class, and not for Fixnum .
When Ruby executes sm.add(2).add(3,4) , it first evaluates sm.add(2) #=> 2 , which reduces the expression to 2.add(3,4) . Then he tries to send the add method (with its two parameters) to 2 , but finds that the class 2.class #=> Fixnum does not have an add instance method; hence the exception.
We can fix this error by defining these methods for the Fixnum class:
class Fixnum def add(a,b=0) a + b end def subtract(a,b=0) a - b end end
You can confirm that these methods have been added to the Fixnum class by running:
Fixnum.instance_methods.sort
Now one more problem:
sm = Fixnum.new #=> NoMethodError: undefined method `new' for Fixnum:Class
Oh my, the Fixnum class Fixnum not have a new method! This is because Fixnum instances are integers that cannot be created. You can easily confirm that integers are instances of Fixnum :
72.class #=> Fixnum -3.class #=> Fixnum
So, we can call the add method by sending it to any instance of Fixnum :
72.add(2) #=> 2 -3.add(2) #=> 2
Now try linking the add operations:
72.add(2).add(3,4) #=> 7 72.add(2000000).add(3,4) #=> 7
No exceptions, but no chains. A way to fix this is to change the methods again:
class Fixnum def add(b=0) puts "in add, self = #{self}, b = #{b}" self + b end def subtract(b=0) puts "in subtract, self = #{self}, b = #{b}" self - b end end
I added the puts statement in each method if necessary additional debugging. We will remove them when the code works correctly. Let the test:
2.add(3) #=> 5 in add, self = 2, b = 3 5.add #=> 5 in add, self = 5, b = 0 5.add(7) #=> 12 in add, self = 5, b = 7 2.add(3).add.add(7) #=> 12 in add, self = 2, b = 3 in add, self = 5, b = 0 in add, self = 5, b = 7 2.subtract(5) #=> -3 in subtract, self = 2, b = 5 -3.subtract #=> -3 in subtract, self = -3, b = 0 2.subtract(5).subtract #=> -3 in subtract, self = 2, b = 5 in subtract, self = -3, b = 0 2.add(3).subtract(5).add(7) #=> 7 in add, self = 2, b = 3 in subtract, self = 5, b = 5 in add, self = 0, b = 7
Success! Get it?