2009-08-09 5 views
2

Я делаю небольшую систему управления выпуском в Лифте, чтобы узнать как Scala, так и Lift.Метод Зависимости и обработка ошибок

У меня есть представление, которое отображает одну проблему, относящуюся к проекту. Перед тем, как связать данные в шаблон представления, я хочу, чтобы проверить, что я все требуемые данные, поэтому я хочу специально проверить, что:

  • Проекта ID пары были поставлены
  • имеются проект с помощью прилагаемого проект ID
  • вопрос ID пары были поставлен
  • существует проблема с прилагаемым выпуском ID

И они должны быть оценены в порядке, так что, если я должен был писать теперь с моим пониманиемиз Scala, я бы сделал следующее:

class Project { 
    def findByID(xhtml:NodeSeq): NodeSeq = 
     param("projectID") match { 
      case Full(projectID) => 
       Project.findByID(projectID) match { 
        case Full(projectID) => 
         param("issueID") match { 
          .... 
         } 
        case _ => Text("Project does not exist") 
       } 
      case _ => Text("projectIDNotSupplied") 
     } 
} 

Так что мне интересно, есть ли более простой способ выполнить это? Я думаю, что выражение для выражения может выполнить нечто подобное. Имейте в виду, что Project.findByID возвращает Box [Project].

ответ

4

Жаль, что я так поздно шоу, но, как говорит Дэниел вы действительно можете использовать Box подъемника и? ~, Чтобы сделать что-то вроде этого. Например:

import net.liftweb.util.Box 
import net.liftweb.util.Box._ 

class Project { 
    def findByID(xhtml:NodeSeq): NodeSeq = 
    (for { 
     projectID <- param("projectID") ?~ "projectIDNotSupplied" 
     project <- Project.findById(projectID) ?~ "Project does not exist" 
     issueID <- param("issueID") ?~ "issueIDNotSupplied" 
     ... 
    } yield { 
     ... 
    }) match { 
     case Full(n) => n 
     case Failure(msg, _, _) => Text(msg) 
     case _ => Text("fail") 
    } 
} 

Что ~ делает превратить пустое поле в Failure Box с заданным сообщением об ошибке String, но ничего не делает для Full (успех) Box. Таким образом, возвращаемое значение findByID будет полным, если все будет успешным, или Failure (с данным сообщением об ошибке) в противном случае. Если вы хотите, чтобы сбои цепи, то используйте? ~! вместо.

+0

Hey Jorge выглядит так, как будто это будет работать, только это фрагмент, так как я знаю, что тип возвращаемого значения должен быть: NodeSeq. Если нет, я получаю сообщение об ошибке, когда метод не найден. Чтобы обойти это, я могу обернуть целое for() в блоке и вызвать openOr (текст («fail»)) на нем Но теперь, когда одна из зависимостей завершилась неудачно, я получаю сообщение «fail». Я пытался использовать метод run(), но я не совсем понял. есть идеи? –

+0

Я отредактировал фрагмент кода выше, чтобы вернуть NodeSeq. –

+0

Отлично, спасибо Хорхе. Это был один из тех, «почему я не подумал об этих случаях». еще раз спасибо –

1

Не знаю Лифт, но есть несколько вещей, которые я видел в его реализации. Один из них - методы отказа: ?~ и ?~!. Я точно не знаю, как можно их использовать, но, похоже, это полезно. Другой - open_!, чтобы исключить исключения.

Теперь карта поддержки Box, flatMap, фильтр и Еогеасп, поэтому он может быть в полной мере использовать внутри для понимания:

for(projectID <- param("projectID"); 
    if Project.findByID(projectID).isDefined; 
    issueID <- param("issueID"); 
    if Issue.findByID(issueID).isDefined) 
yield ... 

Это не поможет вам сообщения об ошибках. Для тех, я угадываю методы, которые я упомянул, или другие, такие как ~>, могут предоставить ответ.

+0

Спасибо, Дэниэл, я пытался использовать выражение для неправильного пути, чтобы справиться с этим, я до сих пор не понимаю их. Я попробую, когда вернусь домой и посмотрю, возвращают ли методы обработки ошибок Box конкретную информацию об ошибке. –

1

Я не знаю Подъем, поэтому я не могу ответить на любые вопросы, связанные с лифтом. Тем не менее, я придумал способ решить одну из ваших проблем, которая заключается в том, как написать последовательность действий с проверкой, а не прибегать к вложенному сопоставлению шаблонов.

Основной тип данных, используемый здесь, является вариантом, но я уверен, что будет легко адаптироваться к вашим потребностям. То, что мы хотим достичь здесь, чтобы сделать последовательность

  1. проверка состояния
  2. продолжать в случае успеха
  3. прекратить и вернуть то, что в противном случае

код делает вид короткого замыкания, как только он встречает a None, поэтому возвращаемое значение сохраняется, когда возвращается последовательность действий. Чтобы использовать, запускается с опцией, тогда пишите «ifSome», если опция «Some» и «ifNone», если параметр «None», продолжайте, пока последовательность не будет завершена. Если None встречается в любой точке последовательности, опция, возвращаемая из параметра по одному из имени «isNone», сохраняется и возвращается при вызове окончательного «toOption». Используйте «toOption», чтобы вернуть фактический результат Option.

Ознакомьтесь с примером в «основном» для некоторых случаев использования. Удачи!

object Options { 

    class RichOption[A](a: Option[A]) { 

    def ifSome[B](f: A => Option[B]): RichOption[B] = a match { 
     case Some(x) => new RichOption(f(x)) 
     case None => this.asInstanceOf[RichOption[B]] 
    } 

    def ifNone[B](f: => Option[B]): RichOption[B] = a match { 
     case Some(_) => this.asInstanceOf[RichOption[B]] 
     case None => new RichNone(f) 
    } 

    def toOption[A] = a 
    } 

    class RichNone[A](a: Option[A]) extends RichOption[A](a) { 

    override def ifSome[B](f: A => Option[B]): RichOption[B] = this.asInstanceOf[RichOption[B]] 

    override def ifNone[B](f: => Option[B]): RichOption[B] = this.asInstanceOf[RichOption[B]] 
    } 

    implicit def option2RichOption[A](a: Option[A]): RichOption[A] = new RichOption(a) 

    def main(args: Array[String]) { 
    println(Some("hello") ifSome(s => Some(s.toUpperCase)) toOption) // prints Some(HELLO) 
    println(Some("hello") ifNone(Some("empty")) toOption) // prints Some(hello) 
    println(Some("hello") ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) toOption) // prints Some(HELLO) 
    println(Some("hello") ifNone(Some("empty")) ifSome(s => Some(s.toUpperCase)) toOption) // prints Some(HELLO) 
    println((None: Option[String]) ifSome(s => Some(s.toUpperCase)) toOption) // prints None 
    println((None: Option[String]) ifNone(Some("empty")) toOption) // prints Some(empty) 
    println((None: Option[String]) ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) toOption) // prints Some(empty) 
    println((None: Option[String]) ifNone(Some("empty")) ifSome(s => Some(s.toUpperCase)) toOption) // prints Some(empty) 
    println(Some("hello world") ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(11) 
    println(Some("hello world") ifSome(_ => None) ifNone(Some("goodbye world")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(goodbye world) 
    println((None: Option[String]) ifSome(s => Some(s.toUpperCase)) ifNone(Some("empty")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(empty) 
    println((None: Option[String]) ifSome(_ => None) ifNone(Some("goodbye world")) ifSome(s => Some(s.length)) ifNone(None) toOption) // prints Some(goodbye world) 
    } 
} 
+0

Спасибо Уолтеру, это интересное решение. Я дам ему попробовать, когда вернусь домой, тренирую мышцы мозга Scala. –

Смежные вопросы