Skip to content

Commit

Permalink
doc: reworked the indentation on the user guide
Browse files Browse the repository at this point in the history
  • Loading branch information
symbiont-eric-torreborre committed Sep 12, 2021
1 parent d92f620 commit 8f23fd1
Show file tree
Hide file tree
Showing 54 changed files with 1,334 additions and 1,417 deletions.
2 changes: 2 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ align.stripMargin = true
align.preset = some

spaces.inByNameTypes = false

project.excludePaths = ["glob:**/guide/**/*.scala"]
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ Robustness
"""

def snippet1 =
s2""" code: ${snippet {got {1 + 1}}} """.trimmedTexts(1) === "`got {1 + 1}`"
s2""" code: ${snippet{got {1 + 1}}} """.trimmedTexts(1) === "`got {1 + 1}`"

def snippet2 =
s2""" code: ${snippet {
s2""" code: ${snippet{
got {
var n = 0
n = 1
Expand All @@ -74,7 +74,7 @@ got {
|}
|```""".stripMargin

def snippet3 = s2""" code: ${snippet {
def snippet3 = s2""" code: ${snippet{
// 8<--
var n = 0
// 8<--
Expand All @@ -86,7 +86,7 @@ n = 0
|n = 1
|```""".stripMargin

def snippet4 = s2""" code: ${snippet {
def snippet4 = s2""" code: ${snippet{
// 8<--
var n = 0
// 8<--
Expand All @@ -104,9 +104,9 @@ i = 1
|```""".stripMargin

def snippet5 =
s2""" code ${snippet { "e1" ! {ok} /**/; 1 /**/ }}""".trimmedTexts(1) === """`"e1" ! {ok} /**/; 1 /**/`"""
s2""" code ${snippet{ "e1" ! {ok} /**/; 1 /**/ }}""".trimmedTexts(1) === """`"e1" ! {ok} /**/; 1 /**/`"""

def offset1 = s2""" code: ${snippet {
def offset1 = s2""" code: ${snippet{
// 8<--
var n = 0
// 8<--
Expand All @@ -118,7 +118,7 @@ n = 0
| n = 1
|```""".stripMargin

def offset2 = s2""" code: ${snippet {
def offset2 = s2""" code: ${snippet{
// 8<--
var n = 0
// 8<--
Expand All @@ -145,7 +145,7 @@ n = 0
" snippet{ hello \n}.eval " !! "hello" |
" snippet{ hello \n}.offsetIs(2) " !! "hello" | { (c, r) => trimApproximatedSnippet(c) === r }

def results1 = s2""" code: ${snippet {
def results1 = s2""" code: ${snippet{
var n = 1
n = 1 + n
n
Expand Down Expand Up @@ -192,7 +192,7 @@ n = 0

def effects2 =
var i = 0
s2""" start ${snippet { i = 1; i }} end """
s2""" start ${snippet{ i = 1; i }} end """
i === 0

// HELPERS
Expand Down
72 changes: 35 additions & 37 deletions guide/src/test/scala/org/specs2/guide/AddKeywords.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,20 @@ package org.specs2.guide
object AddKeywords extends UserGuidePage {
def is = s2"""

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

class MySpecification extends mutable.Specification:
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
}
}

"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:
```
Expand All @@ -27,41 +26,40 @@ This will print:
```
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
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 ExtendedBlockDsl:
extension (description: String)
infix def to(f: =>Fragment): Fragment =
(description + " to") >> f
trait ToKeyword extends ExtendedBlockDsl:
extension (description: String)
infix def to(f: =>Fragment): Fragment =
(description + " to") >> f

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

class MySpecification extends org.specs2.mutable.Specification with ToKeyword:
class MySpecification extends org.specs2.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
}
}
}}
"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' function is used to
+ return true when passed true, true
+ return false when passed true, false
```

"""

}
10 changes: 5 additions & 5 deletions guide/src/test/scala/org/specs2/guide/ArgumentsReference.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import org.specs2.main.FilesRunnerArguments.*
object ArgumentsReference extends UserGuidePage {
def is = "Arguments reference".title ^ s2"""

Arguments can be passed on the command line, or declared inside a specification, using the `args(name=value)` syntax:${snippet {
Arguments can be passed on the command line, or declared inside a specification, using the `args(name=value)` syntax:${snippet{

class MySpec extends Specification:
def is = args(xonly = true) ^ s2"""
class MySpec extends Specification:
def is = args(xonly = true) ^ s2"""

Clever spec title
And some intro text
brilliant expectation $success
"""
}}
}}

They can also be passed as system properties: `-Dspecs2.name=value` (`-Dname=value` also works but you might have collisions with other properties).

Expand Down Expand Up @@ -131,7 +131,7 @@ For ${"the HTML output" ~/ HtmlOutput} the following options can be used:

## Arguments API

From inside a specification, the `args` method provides the most frequent arguments as `args(argumentName = argumentValue)`. In the least frequent cases you will have to write:${snippet {
From inside a specification, the `args` method provides the most frequent arguments as `args(argumentName = argumentValue)`. In the least frequent cases you will have to write:${snippet{
// for selection arguments
args.select(ex = "example \\d*")

Expand Down
39 changes: 19 additions & 20 deletions guide/src/test/scala/org/specs2/guide/AsResultTypeclass.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,28 @@ There are many ways to define expectations in $specs2:
* Forms
$p

All of these types implement the `org.specs2.execute.AsResult` typeclass, meaning that they can be transformed into a `Result`:${snippet {
trait AsResult[T] {
def asResult(t: =>T): Result
}
}}
All of these types implement the `org.specs2.execute.AsResult` typeclass, meaning that they can be transformed into a `Result`:${snippet{
trait AsResult[T]:
def asResult(t: =>T): Result
}}

This gives some flexibility in integrating any kind of custom definition of a "result" into $specs2 and this is why you find this typeclass as a requirement to build examples or to declare contexts.
You can take advantage of this type class by defining your own kind of result and providing a typeclass instance for it:${snippet {
You can take advantage of this type class by defining your own kind of result and providing a typeclass instance for it:${snippet{
// A new type of results for cluster execution
trait ClusterExecution:
def succeeded: Boolean
def errorMessage: String

object ClusterExecution:
given AsResult[ClusterExecution] =
new AsResult[ClusterExecution]:
def asResult(t: =>ClusterExecution): Result =
try {
val result = t
if (result.succeeded) Success()
else Failure(t.errorMessage)
} catch { case e: Throwable => Error(e) }
}}
trait ClusterExecution:
def succeeded: Boolean
def errorMessage: String

object ClusterExecution:
given AsResult[ClusterExecution] =
new AsResult[ClusterExecution]:
def asResult(t: =>ClusterExecution): Result =
try {
val result = t
if (result.succeeded) Success()
else Failure(t.errorMessage)
} catch { case e: Throwable => Error(e) }
}}

#### Decorated results

Expand Down
49 changes: 24 additions & 25 deletions guide/src/test/scala/org/specs2/guide/AutoExamples.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@ import collection.Seqx.*
object AutoExamples extends UserGuidePage {
def is = "Auto-examples".title ^ s2"""

When you want to specify an API, most of your examples are self-describing:${snippet {
class SeqSpecification extends mutable.Specification:
"updateLast modifies the last element of a Seq".p
"when the collection has 1 element" >> { Seq(1).updateLast(_ + 1) must ===(Seq(2)) }
"when the collection has 2 elements" >> { Seq(1, 2).updateLast(_ + 1) must ===(Seq(1, 3)) }
"when the collection is empty" >> { Seq[Int]().updateLast(_ + 1) must ===(Seq[Int]()) }
}}

It is a bit redundant to provide a textual description for these 3 examples because the code is pretty clear and simple. In this situation you can use the `eg` operator to create an example where the description will be the code itself:${snippet {
class SeqSpecification extends mutable.Specification:
"updateLast modifies the last element of a Seq".p
eg { Seq(1).updateLast(_ + 1) must ===(Seq(2)) }
eg { Seq(1, 2).updateLast(_ + 1) must ===(Seq(1, 3)) }
eg { Seq[Int]().updateLast(_ + 1) must ===(Seq[Int]()) }
}}
When you want to specify an API, most of your examples are self-describing:${snippet{
class SeqSpecification extends mutable.Specification:
"updateLast modifies the last element of a Seq".p
"when the collection has 1 element" >> { Seq(1).updateLast(_ + 1) must ===(Seq(2)) }
"when the collection has 2 elements" >> { Seq(1, 2).updateLast(_ + 1) must ===(Seq(1, 3)) }
"when the collection is empty" >> { Seq[Int]().updateLast(_ + 1) must ===(Seq[Int]()) }
}}

It is a bit redundant to provide a textual description for these 3 examples because the code is pretty clear and simple.
In this situation you can use the `eg` operator to create an example where the description will be the code itself:${snippet{
class SeqSpecification extends mutable.Specification:
"updateLast modifies the last element of a Seq".p
eg { Seq(1).updateLast(_ + 1) must ===(Seq(2)) }
eg { Seq(1, 2).updateLast(_ + 1) must ===(Seq(1, 3)) }
eg { Seq[Int]().updateLast(_ + 1) must ===(Seq[Int]()) }
}}

This prints:
```
Expand All @@ -32,27 +33,25 @@ This prints:

#### In an acceptance specification

Acceptance specifications are using interpolated strings so you can directly write:${snippet {
class SeqSpecification extends Specification:
def is = s2"""
Acceptance specifications are using interpolated strings so you can directly write:${snippet{
class SeqSpecification extends Specification:
def is = s2"""

updateLast modifies the last element of a Seq
${Seq(1).updateLast(_ + 1) must ===(Seq(2))}
${Seq(1, 2).updateLast(_ + 1) must ===(Seq(1, 3))}
${Seq[Int]().updateLast(_ + 1) must ===(Seq[Int]())}
"""
}}

}}

There is a huge gotcha though! Each of these expressions needs an implicit conversion to be included in the interpolated spec. And in Scala, if you have a block of code returning a value of type `T`, ***only the last expression of the block is converted***. This means that if there is a statement in the block that throws an exception, this exception won't be caught and the whole specification will fail to be instantiated! So if you want to use blocks as auto-examples you should better wrap them with an `eg` call:${snippet {
class SeqSpecification extends Specification:
def is = s2"""
There is a huge gotcha though! Each of these expressions needs an implicit conversion to be included in the interpolated spec. And in Scala, if you have a block of code returning a value of type `T`, ***only the last expression of the block is converted***. This means that if there is a statement in the block that throws an exception, this exception won't be caught and the whole specification will fail to be instantiated! So if you want to use blocks as auto-examples you should better wrap them with an `eg` call:${snippet{
class SeqSpecification extends Specification:
def is = s2"""

This is a problematic specification
${ sys.error("ouch, this one is going to blow up the spec"); Seq(1).updateLast(_ + 1) must ===(Seq(2)) }
${eg { sys.error("it's ok, this one is well protected"); Seq(1).updateLast(_ + 1) must ===(Seq(2)) }}
"""
}}

}}
"""
}
10 changes: 5 additions & 5 deletions guide/src/test/scala/org/specs2/guide/CaptureSnippets.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Here is an example of using the `snippet` method:

```
s2$triple
This is a multi-line string with a code snippet: $${ snippet {
This is a multi-line string with a code snippet: $${snippet{
def factorial(n: Int): Int = if (n == 1) n else (n * factorial(n - 1))
factorial(3) == 6
}}
Expand All @@ -38,7 +38,7 @@ Since snippets are compiled code, you might have to include many declarations, l

```
s2$triple
This is a snippet of code with one relevant line: $${ snippet {
This is a snippet of code with one relevant line: $${snippet{
// 8<--
def factorial(n: Int): Int = if (n == 1) n else (n * factorial(n - 1))
// 8<--
Expand All @@ -52,7 +52,7 @@ The snippet above will only show `factorial(3) == 6`. You can repeat this patter

```
s2$triple
This is a snippet of code with 2 relevant lines: $${ snippet {
This is a snippet of code with 2 relevant lines: $${snippet{
// 8<--
def factorial(n: Int): Int = if (n == 1) n else (n * factorial(n - 1))
// 8<--
Expand All @@ -78,7 +78,7 @@ By default the last value of a Snippet is not shown but you can display it with

```
s2$triple
This is a snippet of code with a result: $${ snippet {
This is a snippet of code with a result: $${snippet{
factorial(3)
}.eval}
$triple
Expand All @@ -99,7 +99,7 @@ It is possible to adjust the margin of captured source code by adding or removin

```
s2$triple
This is a snippet of code with a negative offset to align the code to the border of the screen: $${ snippet {
This is a snippet of code with a negative offset to align the code to the border of the screen: $${snippet{
def factorial(n: Int): Int = if (n == 1) n else (n * factorial(n - 1))
factorial(3)
}.offsetIs(-3)}
Expand Down
Loading

0 comments on commit 8f23fd1

Please sign in to comment.