2012-09-19 57 views
2

在我的DSL我希望能够做到这样的功能对象的隐式方法:斯卡拉DSL -

val a = 5 

Parse("TYPE") { 
    a match { 
    case 3 => info("almost") 
    case s: String => error("wrong type") 
    case 5 => info("you won!") 
    case _ => error("omg") 
    } 
} 

与输出

[INFO] TYPE: you won! 

其中Parse是一个函数对象,它具有在apply(String)info(String)error(String)方法:

object Parse { 

    def apply(name: String)(parseF: => Unit) { parseF } 
    def info(text: String) { println("[INFO] " + name + ": " + text) } 
    def error(text: String) { println("[ERROR] " + name + ": " + text) } 

} 

诀窍是infoerror方法的输出在某种程度上应该是Parse对象的本地特性,并按照上面的示例构造消息。因此,他们

  1. 必须如示例中所示,没有任何导入。
  2. 必须有权访问传递给Parse()(示例中为“TYPE”)的第一个参数。
  3. 在工作期间不得创建任何实例或额外的对象。

这是一个理想的描述。我认为这将需要更多的样板。请建议,我该如何实现这个目标?

编辑:我最初的猜测申报apply方法里面infoerror方法并不能让他们在传递的parseF方法可见。嗯,不出所料..

回答

1

没有解决方案满足1-3。你可以有1和2或2和3,但语法略有不同。

1和2)

class Parse(val s:String) { 
    def info.... 

} 

new Parse("TYPE") { 

} 

2和3)

object Parse { 
    def apply(s:String)(f:String=>Unit) = ... 
} 

Parse("TYPE")(s => { 

}) 
2

也许是这样的:

object Parse { 
    val currentName = new util.DynamicVariable("<none>") 
    def apply(name: String)(parseF: => Unit) = currentName.withValue(name)(parseF) 
    def info(text: String) = println("[INFO] %s: %s" format (currentName.value, text) 
} 

// usage 
import Parse._ // there's no other way to get ability to call 'info' without 'Parse'. 
Parse("TYPE") { 
    // some code 
    info("some info") // prints: [INFO] TYPE: some info 
} 

info("some other info") // prints: [INFO] <none>: some other info 

如果需要的话,很容易使info抛出异常,如果它被称为外Parse {}块。