Следующее нестандартно, но оно должно работать. Обратите внимание, что я предполагаю, что вам просто нужна пустая строка по обе стороны от разделителя, когда это значение пусто, и я не проверяю, что значение месяца находится между 1 и 12.
import argonaut._, Argonaut._
import scalaz._, Scalaz._
case class DateValue(year: Option[Int] = None, month: Option[Int] = None)
object YearMonth {
def unapplySeq(s: String) =
"""((?:\d\d\d\d)?)/((?:\d?\d)?)""".r.unapplySeq(s).map {
case List("", "") => List(None, None)
case List(y, "") => List(Some(y.toInt), None)
case List("", m) => List(None, Some(m.toInt))
case List(y, m) => List(Some(y.toInt), Some(m.toInt))
}
}
implicit val DateValueCodecJson: CodecJson[DateValue] = CodecJson(
{ case DateValue(year, month) => jString(~year + "/" + ~month) },
c => c.as[String].flatMap {
case YearMonth(y, m) => DecodeResult.ok(DateValue(y, m))
case _ => DecodeResult.fail("Not a valid date value!", c.history)
}
)
А потом:
val there = Parse.decodeValidation[DateValue](""""2013/12"""")
val back = there.map(DateValueCodecJson.encode)
Что дает нам:
scala> println(there)
Success(DateValue(Some(2013),Some(12)))
scala> println(back)
Success("2013/12")
Как и ожидалось.
Хитрость заключается в том, чтобы предоставить свои собственные функции кодирования и декодирования для CodecJson.apply
. Функция кодирования очень проста — она просто берет что-то из закодированного типа и возвращает значение Json
. Метод декодирования немного сложнее, так как он принимает HCursor
и возвращает DecodeResult
, но с ним также довольно легко работать.
person
Travis Brown
schedule
25.10.2013