Scala: рефакторинг оператора case для использования для понимания

Я пытаюсь разобрать следующий Json в объект Scala:

{
  "oneOf": [    
    { "$ref": "..." },
    { "$ref": "..." },
    { "$ref": "..." }
}

Поле «oneOf» также может быть «anyOf» или «allOf»; это будет только одно из этих значений. Я создаю класс case, ComplexType, используя библиотеку Play JSON. Логика проста; он ищет заданное поле и считывает его, если оно присутствует, в противном случае проверяет другое поле.

(json \ "allOf") match {
    case a:JsArray => ComplexType("object", "allOf", a.as[Seq[JsObject]].flatMap(_.values.map(_.as[String])))
    case _ => 
        (json \ "anyOf") match {
            case a:JsArray => ComplexType("object", "anyOf", a.as[Seq[JsObject]].flatMap(_.values.map(_.as[String])))
            case _ =>
                  (json \ "oneOf") match {
                        case a:JsArray => ComplexType("object", "oneOf", a.as[Seq[JsObject]].flatMap(_.values.map(_.as[String])))
                        case _ => ComplexType("object", "oneOf", "Unspecified" :: Nil)
                      }
                  }
              } 

Меня не устраивает такой синтаксис; хотя это работает, я не понимаю, зачем мне нужны вложенные операторы соответствия, если совпадение не найдено. Я считаю, что понимание будет работать хорошо: я могу проверить (json \ "allOf"), (json \ "oneOf) и т. д. в защитном предложении и получить доступный результат, но не знаю, как получить правильный синтаксис.

Есть ли более элегантный способ построить этот класс case?

Спасибо,

Майк


person mhamrah    schedule 05.06.2013    source источник


Ответы (1)


Я не думаю, что понимание полезно здесь.

Вы можете сделать свой код более читабельным с помощью настраиваемых экстракторов, например:

class Extractor(s: String) {
  def unapply(v: JsValue): Option[JsArray] = json \ s match {
    case a: JsArray => Some(a)
    case _ => None
  }
}

val AllOf = new Extractor("allOf")
val AnyOf = new Extractor("anyOf")
val OneOf = new Extractor("oneOf")

val (name, es) = json match {
    case AllOf(a) => "allOf" -> Some(a)
    case AnyOf(a) => "anyOf" -> Some(a)
    case OneOf(a) => "oneOf" -> Some(a)
    case _ => "oneOf" -> None
  }
val result =
  es.
    map{ a => ComplexType("object", name, a.as[Seq[JsObject]].flatMap(_.values.map(_.as[String]))) }.
    getOrElse("Unspecified" :: Nil)
person senia    schedule 05.06.2013