2011-06-09 53 views
1

我仍在ScalaTest FeatureSpec DSL上工作。如何通過塊類型重載Scala方法?

我想要我的given函數的3個變種。所有取tokens: Any,然後或者

A. A嵌段block: => Unit稍後執行

given("user visits", the[AdminHomePage]) { 
    // just code 
} 

B. A嵌段與令牌

given("user visits", the[AdminHomePage]) { 
    x: Any => x match { 
    case ("user visits", pageClass:Class[Page]) => 
     startPage(pageClass) 
    } 
} 

C.否塊以後執行block: Any => Unit ,其中令牌由另一功能處理

given("user visits", the[AdminHomePage]) 

現在,當我定義所有三種方法時

def given(tokens: Any) = ... 
def given(tokens: Any)(block: Any => Unit) = block(tokens) 
def given(tokens: Any)(block: => Unit) = block 

編譯器認爲它們不明確。

ambiguous reference to overloaded definition, both method given in trait GivenWhenThenFeatureSpec of type (tokens: Any)(block: => Unit)Unit and method given in trait GivenWhenThenFeatureSpec of type (tokens: Any)(block: (Any) => Unit)Unit match argument types 

如何消除歧義,或者寫出一個可以區分塊(或缺少)的方法?

+0

你的意思是寫'令牌:任何*'還是我失去了一些東西? – 2011-06-09 16:29:44

+0

啊是的,或者說沒有。它是'tokens:Any',參數被打包成一個我匹配的元組(上面的a-la B)。 – 2011-06-09 16:36:00

+0

因此,DSL的最終處理是一種在元組上匹配並且由第一個(非塊)形式觸發的許多情況的方法。塊形式在那裏讓我原型的情況下實現。 – 2011-06-09 16:39:14

回答

2

我喜歡@ MachAndy的解決方案上面,除了unit2emptyfunction的轉換,這是我看到的可能的干擾或覆蓋其他類型的錯誤的進口。

相反,如果你定義如下:

object Given { 
    trait Processor { 
    def process(tokens: Any) 
    } 
    class ProcessorA(block: =>Unit) extends Processor { 
    def process(tokens: Any) = { 
     block // execute or store block for later, ignoring tokens 
    } 
    } 
    class ProcessorB(block: Any=>Unit) extends Processor { 
    def process(tokens: Any) = { 
     block(tokens) // or store block for later execution 
    } 
    } 
    class ProcessorC extends Processor { 
    def process(tokens: Any) = { 
     // do something defaultish with the tokens 
    } 
    } 

    implicit def blockToProcessorA(block: =>Unit) = new ProcessorA(block) 
    implicit def blockToProcessorB(block: Any=>Unit) = new ProcessorB(block) 
    implicit val processorC = new ProcessorC 

    def given(tokens: Any)(implicit p: Processor) = p.process(tokens) 
} 

然後,您可以簡單地說:

import Given._ 

given("user visits", the[AdminHomePage]) 
given("user visits", the[AdminHomePage]) { 
    // some stuff that ignores tokens 
} 
given("user visits", the[AdminHomePage]) { x: Any => 
    x match { 
    // do something that looks at the tokens 
    } 
} 
+0

到目前爲止,這種方法運行良好,我必須將所有塊聲明爲'=> Any',以便允許塊內容評估爲某些內容(將其丟棄)。謝謝。 – 2011-06-09 22:52:37

+0

哦,另一個小小的改進是'隱式對象ProcessorC'允許我刪除隱式的val。 – 2011-06-09 23:02:02

+0

** **是我尋找的增強功能!非常感謝您的解決方案。 – 2011-06-10 07:52:05

1

我在這裏有一個解決方案,但我認爲它可以得到增強。

我使用單一given方法條目和隱式提供或不體

def given[A](tokens: A)(implicit block: A => Unit) { 
    block(tokens) 
} 

首先這裏是能夠使用Unit塊作爲Any => Unit

implicit def unit2emptyfunction(body: Unit): Any => Unit = { 
    case _ => body 
} 

爲了能夠在C case中工作,我提供了一個缺省主體來填充block參數,該參數什麼也不做。

implicit val doNothing: Any => Unit = { } 

現在你可以以這種方式使用它:

/* 
* A case, block is implicitly converted into a A => Unit 
* although it doesn't use the argument 
*/ 
given("user visits", the[AdminHomePage]) { 
    // just code 
} 


/* 
* B case, block is fully provided and thus not implicitly converted 
*/ 
given("user visits", the[AdminHomePage]) { 
    case ("user visits", pageClass: Class[Page]) => 
     startPage(pageClass) 
} 

// C case, block implicitly provided by doNothing implicit val 
given("user visits", the[AdminHomePage]) 
+0

我也對這些暗示感到緊張,所以我要和Mitch的答案一起去,但是謝謝你表明這是可能的,因爲它讓我能夠寫出一些測試,知道我能夠解析它們。 – 2011-06-09 22:54:11