Yumiko
Yumiko

Reputation: 468

Ruby Class setter

I have difficulties understanding the setter and how to apply the value in use.

In the below example,

  def time_string=(seconds)
    @time_string = calculator(seconds)
  end

How can I get the seconds' value from setter?

Thanks a lot

class Timer
  def seconds
    @seconds = 0
  end

  def time_string
    @time_string
  end

  def seconds=(t)
    @seconds = t
  end

  def time_string=(seconds)
    @time_string = calculator(seconds)
  end

  def calculator(x)
    array = []
    sec = (x % 60).to_s
    min = ((x / 60 ) % 60).to_s
    hour = (x / 3600).to_s
    temp = [hour, min, sec]
    temp.map {|i| i.length < 2 ? array.push("0#{i}") : array.push("#{i}") }
    array.join(":")
 end

end

Upvotes: 0

Views: 639

Answers (2)

daremkd
daremkd

Reputation: 8424

I think I get what you're trying to accomplish. First, all that calculate code...why? Why not use the methods in the Time class? Second, there are not such thing as setters in Ruby. Everything in Ruby is a method. So technically, what you call a setter is a method that acts like a setter. In your code, both methods seconds= and seconds act as a setter (the first sets @seconds to the return value of the calculator call, and the second method sets @seconds to 0).

You can't get the seconds value from a setter method, the purpose of a setter method is, after all, to SET something. If you want to get something, use a getter method. And it's pretty simple to create a getter method, just change your seconds method to this:

def seconds
     @seconds # we GET the value of @seconds now, we don't set it to 0
end

Ruby can create this method automatically in the background for you with just one line added inside your class, and that line is attr_reader :seconds. Each time you see this in some Ruby code, assume that what Ruby does in the background is generate something similar to the seconds method above. In the same fashion, if you want Ruby to also automatically generate a setter method code like this:

def seconds=(t)
    @seconds = t
end

then use attr_writer :seconds. These attr_reader and attr_writer methods exist because making setter and getter methods is so common that this shortens your program significantly, especially if you have, say, 10 instance variables (you have @seconds and @time_string now , but you could also have instance variables for minutes, hours, days, etc. that would be a lot of methods for getting/setting the instance variables!). In the same fashion, you could also create a getter method automatically for @time_string as well:

def time_string
    @time_string
end

But NOT a setter method because your set logic for @time_string is kinda different than the method Ruby would create (attr_reader and attr_writer create simple getter/setter methods), if you type attr_writer :time_string, then Ruby would create this method in the background:

def time_string=(some_value)
  @time_string = some_value
end

which is not what you want. You can simplify your code a lot, here's my version:

class Timer
  attr_reader :seconds, :time_string
  attr_writer :seconds

  def time_string=(seconds)
    @time_string = calculator(seconds)
  end

  def calculator(x)
    Time.at(x).utc.strftime("%H:%M:%S")
  end

end

a = Timer.new
a.seconds = 30
p a.seconds #=> 30
a.time_string = 50
p a.time_string #=> "00:00:50"

You could also further simplify this code by using attr_accessor for seconds, for that I recommend this excellent answer which explains more about these shortcuts.

Upvotes: 2

Prasad Shinde
Prasad Shinde

Reputation: 662

Not sure why do you want to return value from setters. setters are used to applying initial values to the class variables. you can use accessors to retrieve the value of your instance variables.

If you have problems understanding setters and accessors I would suggest reading the following link : Trying to learn / understand Ruby setter and getter methods

Upvotes: 1

Related Questions