Skip to content

Commit

Permalink
#685 refactored the BlockDsl trait to allow the easy definition
Browse files Browse the repository at this point in the history
of other keywords than "can", "should",...
  • Loading branch information
etorreborre committed Jul 6, 2018
1 parent c9815ec commit 2fdbc76
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 12 deletions.
1 change: 0 additions & 1 deletion common/shared/src/main/scala/org/specs2/control/Use.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package org.specs2.control
* Utility object to show a parameter as used
* In particular this is useful to avoid warnings with ImplicitParameters
*/
private[specs2]
object Use {

def apply(t: Any, ts: Any*): Unit =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,36 @@ package specification
package dsl
package mutable

import control.ImplicitParameters._
import execute.AsResult
import org.specs2.specification.core.{Fragment, Fragments, StacktraceLocation}
import org.specs2.control.Use
import org.specs2.specification.core.{Fragment, Fragments, StacktraceLocation}
import specification.create.FragmentsFactory
import org.specs2.control.ImplicitParameters._

/**
* Create blocks of examples in a mutable specification
*/
private[specs2]
trait BlockDsl extends BlockCreation {
implicit class describe(d: String) {
def >>(f: => Fragment): Fragment = addBlock(d, f, addFragmentBlock)
def should(f: => Fragment): Fragment = addBlock(s"$d should", f, addFragmentBlock)
def can(f: => Fragment): Fragment = addBlock(s"$d can", f, addFragmentBlock)
def >>(f: => Fragment): Fragment = addFragmentBlockWithText(d, f)
def should(f: => Fragment): Fragment = addFragmentBlockWithText(s"$d should", f)
def can(f: => Fragment): Fragment = addFragmentBlockWithText(s"$d can", f)

def >>(fs: => Fragments)(implicit p1: ImplicitParam1): Fragments =
Use.ignoring(p1)(keyword(d, fs))
addFragmentsBlockWithText(d, fs)(p1)

def should(fs: => Fragments)(implicit p1: ImplicitParam1): Fragments =
Use.ignoring(p1)(keyword(s"$d should", fs))
addFragmentsBlockWithText(s"$d should", fs)(p1)

def can(fs: => Fragments)(implicit p1: ImplicitParam1): Fragments =
Use.ignoring(p1)(keyword(s"$d can", fs))
addFragmentsBlockWithText(s"$d can", fs)(p1)
}

def keyword(text: String, fs: =>Fragments): Fragments =
addBlock(text, fs, addFragmentsBlock)
def addFragmentBlockWithText(text: String, f: =>Fragment): Fragment =
addBlock(text, f, addFragmentBlock)

def addFragmentsBlockWithText(text: String, fs: =>Fragments)(implicit p1: ImplicitParam1): Fragments =
Use.ignoring(p1)(addBlock(text, fs, addFragmentsBlock))

/**
* adding a conflicting implicit to warn the user when a `>>` was forgotten
Expand Down
70 changes: 70 additions & 0 deletions guide/src/test/scala/org/specs2/guide/AddKeywords.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.specs2.guide

object AddKeywords extends UserGuidePage { def is = s2"""

Mutable specifications offer a predefined "vocabulary" to define examples: ${snippet{
import org.specs2._

class MySpecification extends mutable.Specification {

"the and function" should {
"return true when passed true, true" >> {
true && true ==== true
}
"return false when passed true, false" >> {
true && false ==== false
}
}

}
}}

This will print:
```
the and function should
+ return true when passed true, true
+ return false when passed true, false
```
And you can see that the word "should" has been added to the first description.

However one size does not fit all and you might want to add your own predefined words. Here is how to do it: ${snippet{
import org.specs2._
import org.specs2.specification.core.{Fragment, Fragments}
import org.specs2.specification.dsl.mutable._
import org.specs2.control.ImplicitParameters

trait ToKeyword extends BlockDsl {
implicit class DescribeTo(description: String) {
def to(f: =>Fragment): Fragment =
addFragmentBlockWithText(description + " to", f)

// this implementation of `to` uses an implicit parameter. This is used to overload
// the method for different arguments: Fragment and Fragments
def to(fs: =>Fragments)(implicit p1: ImplicitParameters.ImplicitParam1): Fragments =
addFragmentsBlockWithText(description + " to", fs)
}
}

class MySpecification extends mutable.Specification with ToKeyword {

"the and function is used" to {
"return true when passed true, true" >> {
true && true ==== true
}
"return false when passed true, false" >> {
true && false ==== false
}
}
}
}}

Now this will print
```
the and is use to

This comment has been minimized.

Copy link
@genrym

genrym Jul 6, 2018

typo: should be the and function is used to

This comment has been minimized.

Copy link
@etorreborre

etorreborre Jul 7, 2018

Author Owner

Thanks, I fixed it now on master. I will publish the new user guide soon now that 4.3.1 is out.

+ return true when passed true, true
+ return false when passed true, false
```

"""

}
1 change: 1 addition & 0 deletions guide/src/test/scala/org/specs2/guide/HowTo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Can I create an example description spanning several lines?
How to isolate each example from another so that they don't share variables | ${link(Isolation).mute}
How to timeout examples? | ${link(TimeoutExamples).mute}
Can I use parts of an example description in the example itself? | ${link(ExampleDescription).mute}
Add my own keywords (other than '>>', 'should', 'can') to a mutable specification | ${link(AddKeywords).mute}
Help, I need to troubleshoot my issues! | ${link(Troubleshooting).mute}

"""
Expand Down

0 comments on commit 2fdbc76

Please sign in to comment.