I'm trying to create a simple api for dealing with intervals of hours. (I'm aware of joda time, and I'm not trying to reinvent it. This is rather an exercise).
What I would like to achieve is this:
(1)
assert(from("20:30").to("20:50") == Interval("20:30", "20:50") )
//same thing, but without implicit defs
assert(from(Time(20, 30)).to(Time(20, 50)) == Interval(Time(20, 30), Time(20, 50)))
assert(from("20:30").forMinutes(10) == from("20:30").to("20:40"))
I have managed to implement (1), like this: (ignoring toString, Ordered trait, a.s.o)
case class Time(hour: Int, minute: Int)
case class Interval(start: Time, end: Time)
object Interval {
case class HalfInterval(half: Time => Interval) {
def to(time: Time): Interval = half(time)
def forMinutes(minutes: Int): Interval = ???
}
def from(start: Time): HalfInterval = HalfInterval(Interval(start, _))
}
object Time {
def apply(hourMinute: String): Time = {
val tries = hourMinute.split(":").map(s => Try(s.toInt))
tries match {
case Array(Success(hour), Success(minute)) => Time(hour, minute)
case _ => throw new IllegalArgumentException
}
}
implicit def stringToTime(hourMinute: String) = Time(hourMinute)
}
However, I don't know how to implement (2) (that is: Interval.forMinutes).
def forMinutes(minutes: Int): Interval = {
val time = ?? // Based on what Time object could I construct a new Time object here?
half(time)
}
Can't seem to wrap my head around this.
Does this "HalfInterval" wrapper over Time => Interval
make sense at all?
I designed it empirically - just so that the from(..).to(..)
calls work as planned - rather than with some functional-conceptual model in mind.
Is there a better way to achieve this api?
Thanks
This is what I would do:
object Interval {
case class HalfInterval(start: Time) {
def to(end: Time): Interval = Interval(start, end)
def forMinutes(minutes: Int): Interval = to(getEnd(start, minutes))
private def getEnd(start: Time, minutes: Int) = ???
}
def from(start: Time): HalfInterval = HalfInterval(start)
}
getEnd() adds the minutes parameter to start.minute, divided by 60, adds the result to start.hours and the rest of the division to minutes and there you build the end Time. (Then maybe do the hour modulus 24 in case you go to the next day).
Edit: HalfInterval should be value class, but don't worry about that.