2

There is something that i don't understand about ruby class instance variable or methods**. So i have this code that keeps on giving me this error and i cant understand

Looks ruby thinks that i am trying to call for Float.in_celsius but I want to make this call within my class instance.

#-----------------------------------
def ftoc(fr)
fr = fr.to_f
if (fr == 32)
    c = 0
elsif (fr == 212)
    c = 100
else 
    c = (fr-32.0)*(5.0/9.0)
end

return c
end

def ctof (cl)
cl = cl.to_f
f = (cl*(9.0/5.0))+32.0
return f
end
#-----------------------------------

class Temperature
attr_accessor :in_celsius, :in_fahrenheit 

#class metods 
def self.from_celsius(cel)
    puts "from celsious\n"
    puts "cel: #{cel}\n"
    @in_fahrenheit = cel
    @in_celsius = ctof(cel)
    puts "==============================\n"
    return @in_celsius
end

def self.in_celsius
    @in_celsius
end


end


puts "==============================\n"
puts Temperature.from_celsius(50).in_celsius
puts Temperature.from_celsius(50).in_fahrenheit

and Error is test.rb:54: in '<main>' : undefined method 'in_celsius' for 122.0:float (noMethod Error) enter code here

4
  • You probably want to use a module for this sort of thing - just my 2c Commented Feb 9, 2014 at 19:09
  • Grag, you can simplify ftoc(fr) to def ftoc(fr) (fr-32.0)*(5.0/9.0) end. You don't need to convert fr to a float, because fr-32.0 will do that, and you don't need return because Ruby returns the last calculation performed. Same for ctof(). Commented Feb 9, 2014 at 20:14
  • @CarySwoveland OP is having confusion about the class instance variables and instance variables of class instances.. That needs to be fixed first. Commented Feb 9, 2014 at 20:17
  • WEll yes .. my main issue is with Class instance variables here :/ Commented Feb 10, 2014 at 22:14

3 Answers 3

3

You have a fundamental misunderstanding of how classes work in Ruby. Right now all of your variables and methods are defined at class level. That means that everything you do in the methods is acting directly on the class itself. Instead, you should create instances of Temperature.

class Temperature
  # special method called when creating a new instance
  def initialize celsius
    @in_celsius = celsius
    @in_fahrenheit = celsius * 9 / 5.0 + 32
  end

  def self.from_celsius celsius
    new celsius # built in method to create an instance, passes argument to initialize
  end

  # we defined initialize using celsius, so here we must convert
  def self.from_fahrenheit fahrenheit
    new((fahrenheit - 32) * 5 / 9.0)
  end

  private_class_method :new # people must use from_celsius or from_fahrenheit

  # make instance variables readable outside the class
  attr_accessor :in_celsius, :in_fahrenheit
end

Temperature.from_celsius(50).in_celsius

This code isn't perfect (from_fahrenheit does a redundant conversion) but it should give you the idea of how to redesign your class.

Sign up to request clarification or add additional context in comments.

1 Comment

new((fahrenheit - 32) * 5 / 9.0) Did the trick. My code different allot but this solved my problem ... Great thanks !
0

from_celsius is returning a float which doesn't have an in_celsius method. You need it to return an instance of Temperature which would have that method.

Got to say your intent is a tad confusing, unless you have some other uses for the class Temperature, so it's bit hard to say which way you should go.

5 Comments

I think return @in_celsius useless, so it can be removed. As OP has the line attr_accessor :in_celsius, :in_fahrenheit, def self.in_celsius.. doesn't make sense although.
with the use of class level methods returning an instance of Temperature would not work for him either
@Arup Rakshit Why do you say that attr_accessor :in_celsius, :in_fahrenheit, def self.in_celsius does not make sense ?
@Arup Rakshit I am very new to ruby and syntax is still very confusing for me here. I was using attr_accessor :in_celsius as it is required to make Temperature.in_celsius call. So what i am trying to achieve is to chain my requests, as you can see in puts Temperature.from_celsius(50).in_celsius
@user3290330, I Would have expected Temperature to be a value and unit and any conversion to change both value and unit.
0

Let's see the code puts Temperature.from_celsius(50).in_celsius in details:

  1. Call to singleton method ::from_celsius of Temperature class. That is ok (with some stranges), and t returns as instance of Float class because of result of #ctof method.

  2. Call to instance method #in_celsius of object, which is returned from the previous method. Since it was the Float, the interpreter searches for its instance method #in_celsius, hasn't find it out, and throws the NoMethodError exception.

How to fix.

Since you treat ::from_celsius as a constructor of Temperature class, I believe, that you shell to pass the floating value into the new method, and return created object. You will have class code as follows:

def initialize( value )
   @in_fahrenheit = cel
   @in_celsius = ctof(cel)
end

def self.from_celsius(cel)
   puts "from celsious\n"
   puts "cel: #{cel}\n"
   temp = Temperature.new( cel )
   puts "==============================\n"
   return temp
end

2 Comments

Hmm .. that looks like something i read about Ruby classes ... I think i get an idea Will try it later today ...
Thank you ... for response ... I yet can not add point for your answer as i have no reputation in here yet.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.