2017-02-22 23 views
0

我有我使用默认值创建嵌套case类的结构构建的路径定义可选值使用Monocle时需要非默认的元素。与由光学

使用isos很容易。我可以组成指定的导航,然后使用set修改内部元件:

object Beta { 
    val alphaI: Iso[Beta, Alpha] = GenIso[Beta, Alpha] 
} 
object Alpha { 
    val textI: Iso[Alpha, String] = GenIso[Alpha, String] 
} 

(Beta.alphaI composeIso Alpha.textI).set("foo")(Beta()) shouldBe Beta(Alpha("foo")) 
与prims

不幸的是它似乎并不优雅,如set/modify只会更改内部元件,如果所有选项中导航定义(Some(...)

object Gamma { 
    val betaI: Iso[Gamma, Option[Beta]] = GenIso[Gamma, Option[Beta]] 
    val betaP: Prism[Gamma, Beta] = Prism[Gamma, Beta](_.beta)(a => Gamma(Some(a))) 
} 

val navigateToText: Prism[Gamma, String] = Gamma.betaP composeIso Beta.alphaI composeIso Alpha.textI 

navigateToText.set("foo")(Gamma(None)) shouldBe Gamma(None) 
navigateToText.set("foo")(Gamma(Some(Beta()))) shouldBe Gamma(Some(Beta(Alpha("foo")))) 

我拿出迄今使用由光学设置为Some()路径的每个可选元素,然后由视神经一路下跌的最好的事情设置我们感兴趣的元素开始。

(Gamma.betaI.set(Some(Beta())) andThen navigateToText.set("foo")) (Gamma()) shouldBe Gamma(Some(Beta(Alpha("foo")))) 

理想情况下,我想组成的每个构建块,如果他们是最初None可选的值设置为Some(defaultValue)。显然,构建块需要被定义,包括路径步骤的适当默认值。 有什么建议吗?

全部代码,包括进口:https://github.com/jcaraballo/navigating-fixtures-with-monocle/blob/master/src/test/scala/pr/NavigateIntoOptionSpec.scala

回答

1

你可以使用从Prismbelow如在光学成分的类型匹配:

import monocle.macros.GenIso 
import scalaz.std.option._ 
case class Alpha(text: String = "content") 
case class Beta(alpha: Alpha = Alpha()) 
case class Gamma(beta: Option[Beta] = None) 

val navigateToText = GenIso[Gamma, Option[Beta]] composePrism 
    GenIso[Beta, Alpha].asPrism.below[Option] composePrism 
    GenIso[Alpha, String].asPrism.below[Option] 

navigateToText.set(Some("foo"))(Gamma(None))      // Gamma(Some(Beta(Alpha(foo)))) 
navigateToText.set(Some("foo"))(Gamma(Some(Beta(Alpha("bar"))))) // Gamma(Some(Beta(Alpha(foo)))) 
+0

优秀,工作得非常好! 它也适用于带有可选孩子的家长有其他孩子的镜头。 (我无法在这里正确地设置代码的格式,但我已经在https://github.com/jcaraballo/navigating-fixtures-with-monocle/blob/master/src/test /scala/pr/NavigateIntoOptionSpec.scala) – qtwo