Método Dependências e tratamento de erros
Pergunta
Eu estou fazendo um sistema de gestão pequeno problema Elevação de aprender tanto Scala e Elevador.
Eu tenho uma visão que exibe uma única questão pertencente a um projeto. Antes de eu ligar dados para o modelo de visão, eu quero verificar que tenho exigido todos os dados, então eu quero verificar especificamente que:
- A ID projecto param foi fornecido
- Um projeto existe com o fornecido ID do projeto
- Uma param questão ID foi fornecido
- Existe um problema com o fornecido assunto ID
E estes necessidade de ser avaliada em ordem, por isso, se eu estava a escrevê-lo agora com o meu entendimento atual do Scala, eu faria o seguinte:
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")
}
}
Então, eu estou querendo saber se existe uma maneira mais fácil de realizar isso? Eu acho que uma para a expressão pode ser capaz de realizar algo semelhante. Esteja ciente de que Project.findByID retorna uma caixa [Project].
Solução
Desculpe o tão tarde para o show, mas como Daniel diz que você pode realmente usar Box e do elevador? ~ Para fazer algo assim. Por exemplo:
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")
}
}
O que? ~ Faz é transformar uma caixa vazia em uma falha Box com o dado mensagem de erro String, mas não faz nada para uma completa (sucesso) Box. Assim, o valor de retorno de findById será completa se tudo for bem sucedido, ou falha (com o dado mensagem de erro) de outra forma. Se você quer as falhas de corrente, em seguida, usar? ~! em seu lugar.
Outras dicas
Eu não sei elevador, mas há um par de coisas que eu já vi em sua implementação. Um deles é os métodos de falha: ?~
e ?~!
. Eu não sei exatamente como se poderia ir em usá-los, mas parece ser útil. Outra é open_!
, para lançar exceções.
Agora, um suporte mapa Box, flatMap, filtro e foreach, para que ele possa ser plenamente utilizado dentro de uma para a compreensão:
for(projectID <- param("projectID");
if Project.findByID(projectID).isDefined;
issueID <- param("issueID");
if Issue.findByID(issueID).isDefined)
yield ...
Este não vai chegar as mensagens de erro. Para aqueles, eu estou supondo que os métodos que eu mencionei, ou outros como ~>
, pode fornecer a resposta.
Eu não sei Elevador então não posso responder a quaisquer perguntas específicas-Lift. Eu, entretanto, veio com uma maneira de resolver um dos seu problema que é como escrever uma sequência de check-o então operar ações sem recorrer a correspondência de padrões aninhada.
O principal tipo de dados em uso aqui é opção, mas tenho certeza de que vai ser bastante fácil de se adaptar às suas necessidades. O que nós queremos realizar aqui é fazer uma seqüência de
- condição de verificação
- continuar se bem sucedida
- terminar e retornar algo de outra forma
O código faz uma espécie de curto-circuito, uma vez que encontra um None para que o valor de retorno é retida quando a sequência de ações retornos. Para usar, começa com uma opção, em seguida, escrever "ifSome" se Option é uma Alguns e "ifNone" se Option é um Nada, continue até que a seqüência seja concluída. Se um Nada é encontro a qualquer ponto na sequência, a opção de voltar de chamada-por-nome do parâmetro de "isNone" é retido e devolvido quando a final "toOption" é chamado. Use "toOption" para voltar o resultado Opção real.
Confira o exemplo na "principal" para alguns casos de uso. Boa sorte!
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)
}
}