I have a ruby class called Duration that represents a unit of time.
It’s main attribute is a number that represents the duration in
seconds.
If I try to save it to a DB using Rails, I get a “Duration can not be
coerced into Float” error. Is there a way to modify the definition of
Duration to enable automatic coercion into a float? (I’m thinking of
something like adding a “to_float” method to the class.)
if other.class == @seconds.class
[@seconds, other]
else
[Float(@seconds), Float(other)]
end
end
end
Could you explain what this is doing? I don’t get the effect.
my understanding of coerce is that it’s used to produce a pair of
operands -
myself and other - which can be used to perform operations.
so, in the case of Fixnum#+ we might see
def + other
x, y = other.coerce self
x + y
end
which is to say Fixnum need not know about how to add every possible
class -
rather it leaves that knowledge up to those classes to export via thier
coerce
method. as i understand it that method should return two new objects
which
interoperate so, in the case above (which is made up) we might have
duration = Duration::new 42.0
42 + duration
here would call duration(42) and expect back an x and y which could be
added
together. so, if @seconds happens to be a Fixnum the result will be
another
Fixnum. if @seconds happens to a Float the result would be a Float.
i admit that i’m not crystal clear on this, but it sure seems to work:
harp:~ > cat a.rb
class Duration
def initialize seconds
@seconds = seconds
end
def coerce other
if other.class == @seconds.class
[@seconds, other]
else
[Float(@seconds), Float(other)]
end
end
def + other
x, y = coerce(other)
x + y
end
end
def Duration(*a, &b); Duration::new(*a, &b); end
p( 40 + Duration(2.0) ) # Float 42.0
p( 40 + Duration(2) ) # Fixnum 42
p( 40.0 + Duration(2.0) ) # Float 42.0
p( 40.0 + Duration(2) ) # Float 42.0
p( Duration(40) + 2 ) # Fixnum 42
p( Duration(40) + 2.0 ) # Float 42.0
p( Duration(40.0) + 2) # Float 42.0
p( Duration(40.0) + 2.0 ) # Float 42.0
harp:~ > ruby a.rb
42.0
42
42.0
42.0
42
42.0
42.0
42.0
i assume one would do something nice with the coerce method using Time,
Date,
and DateTime objects too…
There’s a gottcha here. Coerce is used to implement double dispatch and
so needs to return the coerced values in the opposite order (see Pick
Axe)–(other,self), not (self,other).
The way you wrote it works fine for addition & multiplication, but
you’ll pull your hair out the first time you try to subtract or divide.
–MarkusQ
P.S. And I think (as Tom noted) that “to_f” was the answer to the
original question.