com.thoughtworks.dsl.keywords

Type members

Classlikes

trait AsynchronousIo[Value]

The base keyword to perform asynchronous IO in domains.task.Tasks.

The base keyword to perform asynchronous IO in domains.task.Tasks.

Example

The following readAll is a Task to read file content with the help of AsynchronousIo.ReadFile

        import java.nio._, file._, channels._
        import com.thoughtworks.dsl.bangnotation._
        import com.thoughtworks.dsl.comprehension._
        import com.thoughtworks.dsl.domains.Task
        import com.thoughtworks.dsl.keywords._
        import com.thoughtworks.dsl.keywords.Shift._
        import com.thoughtworks.dsl.keywords.AsynchronousIo.ReadFile
        import scala.collection.mutable.ArrayBuffer
        import scala.io.Codec
        def readAll(channel: AsynchronousFileChannel, temporaryBufferSize: Int = 4096): Task[ArrayBuffer[CharBuffer]] = *[Task] {
          val charBuffers = ArrayBuffer.empty[CharBuffer]
          val decoder = Codec.UTF8.decoder
          val byteBuffer = ByteBuffer.allocate(temporaryBufferSize)
          var position: Long = 0L
          while (!ReadFile(channel, byteBuffer, position) != -1) {
            position += byteBuffer.position()
            byteBuffer.flip()
            charBuffers += decoder.decode(byteBuffer)
            byteBuffer.clear()
          }
          charBuffers
        }
    `Task`s created from !-notation can be used in `for`-comprehension,
    and other keywords can be used together in the same `for` block.
    For example, the following `cat` function contains a single `for` block to concatenate file contents.
    It asynchronously iterates elements `Seq`, `ArrayBuffer` and `String` with the help of [[keywords.Each]],
    managed native resources with the help of [[keywords.Using]],
    performs previously created `readAll` task with the help of [[keywords.Shift]],
    and finally converts the return type [[comprehension.ComprehensionOps.as as]] a `Task[Vector[Char]]`.
        import com.thoughtworks.dsl._
        import com.thoughtworks.dsl.bangnotation._
        import com.thoughtworks.dsl.keywords._
        import com.thoughtworks.dsl.keywords.Shift._
        import com.thoughtworks.dsl.domains.Task
        import java.net.URL
        def cat(paths: Path*) = {
          for {
            path <- Each(paths)
            channel <- Using(AsynchronousFileChannel.open(path))
            charBuffers <- Shift(readAll(channel))
            charBuffer <- Each(charBuffers)
            char <- Each(charBuffer.toString)
          } yield char
        }.as[Task[Vector[Char]]]
    Then the `cat` function is used to concatenate files from this project, as shown below:
        Task.toFuture(*[Task] {
          (!Shift(cat(Paths.get(".sbtopts"), Paths.get(".scalafmt.conf")))).mkString should be(
            "-J-XX:MaxMetaspaceSize=512M\n-J-Xmx5G\n-J-Xss6M\nversion = \"1.5.1\"\nmaxColumn = 120"
          )
        })
Companion
object
Companion
class
object Await
sealed
class Continue

The base type of Continue keyword.

The base type of Continue keyword.

See also

The Continue object, which is the only instance of this Continue class.

Companion
object
case
object Continue extends Continue

A keyword to skip the current iteration in a collection comprehension block.

A keyword to skip the current iteration in a collection comprehension block.

Authors

杨博 (Yang Bo)

See also

Each for creating collection comprehensions.

Note

This Continue keyword is usually used with Each, to skip an element in the loop.

Example

Each and Continue can be used to calculate composite numbers and prime numbers.

        import com.thoughtworks.dsl.bangnotation._
        def compositeNumbersBelow(maxNumber: Int) = *[collection.immutable.HashSet] {
          val factor = !Each(2 until math.ceil(math.sqrt(maxNumber)).toInt)
          !Each(2 * factor until maxNumber by factor)
        }
        compositeNumbersBelow(13) should be(Set(4, 6, 8, 9, 10, 12))
        def primeNumbersBelow(maxNumber: Int) = *[Seq] {
          val compositeNumbers = compositeNumbersBelow(maxNumber)
          val i = !Each(2 until maxNumber)
          if (compositeNumbers(i)) !Continue
          i
        }
        primeNumbersBelow(13) should be(Array(2, 3, 5, 7, 11))
Companion
class
final case
class Each[Element](elements: Iterable[Element])

Iterates though each element in elements.

Iterates though each element in elements.

Authors

杨博 (Yang Bo)

See also

comprehension if you want to use traditional for comprehension instead of !-notation.

Example

Each keywords can be used to calculate cartesian product.

        import com.thoughtworks.dsl.bangnotation._
        def cartesianProduct = reset (List(!Each(Array(1, 2, 3)) * !Each(Vector(1, 10, 100, 1000))))
        cartesianProduct should be(List(1, 10, 100, 1000, 2, 20, 200, 2000, 3, 30, 300, 3000))
Companion
object
object Each
Companion
class
final case
class FlatMap[Upstream, UpstreamValue, Mapped](upstream: Upstream, flatMapper: UpstreamValue => Mapped)
Companion
object
object FlatMap
Companion
class
final case
class ForEach[Element](elements: Iterable[Element])

Iterates though each element in elements.

Iterates though each element in elements.

Companion
object
object ForEach
Companion
class
final case
class Fork[Element](elements: Iterable[Element]) extends AnyVal
Companion
object
object Fork
Companion
class
final case
class Get[S]()
Authors

杨博 (Yang Bo)

See also
Companion
object
object Get
Companion
class
final case
class If[ConditionKeyword, ThenKeyword, ElseKeyword](cond: ConditionKeyword, thenp: ThenKeyword, elsep: ElseKeyword)
Companion
object
object If
Companion
class
object In
final case
class Map[UpstreamKeyword, UpstreamValue, Value](upstream: UpstreamKeyword, mapper: UpstreamValue => Value)
Companion
object
object Map
Companion
class
object Match
object Monadic
final case
class NoneSafe[A](option: Option[A]) extends AnyVal
Companion
object
object NoneSafe
Companion
class
object Pure
final case
class Put[S](value: S) extends AnyVal

Put is a Keyword to replace the value of the current context.

Put is a Keyword to replace the value of the current context.

Purely functional programming languages usually do not support native first-class mutable variables. In those languages, mutable states can be implemented in state monads.

Put and Get are the Dsl-based replacements of state monads.

We use unary function as the domain of mutable state. The parameter of the unary function can be read from the Get keyword, and changed by the Put keyword.

Authors

杨博 (Yang Bo)

See also
Example

The following example creates a function that accepts a string parameter and returns the upper-cased last character of the parameter.

import com.thoughtworks.dsl.bangnotation.{unary_!, reset}
def upperCasedLastCharacter = reset[String => Char] {
 val initialValue = !Get[String]()
 !Put(initialValue.toUpperCase)
 val upperCased = !Get[String]()
 Function.const(upperCased.last)
}

For example, given a string of foo, the upper-cased last character should be O.

upperCasedLastCharacter("foo") should be('O')

Put and Get support multiple states. The following code creates a formatter that Put parts of content into a Vector[Any] of string buffers.

import com.thoughtworks.dsl.bangnotation.{reset, unary_!}
def formatter = reset[Double => Int => Vector[Any] => String] {
 !Put(!Get[Vector[Any]]() :+ "x=")
 !Put(!Get[Vector[Any]]() :+ !Get[Double]())
 !Put(!Get[Vector[Any]]() :+ ",y=")
 !Put(!Get[Vector[Any]]() :+ !Get[Int]())
 !Return((!Get[Vector[Any]]()).mkString)
}
formatter(0.5)(42)(Vector.empty) should be("x=0.5,y=42")
Companion
object
object Put
Companion
class
object Return
object Shift extends LowPriorityShift0
object Suspend
case
class TryCatch[BlockKeyword, CaseKeyword](block: BlockKeyword, cases: Catcher[CaseKeyword])
Companion
object
object TryCatch
Companion
class
case
class TryCatchFinally[BlockKeyword, CaseKeyword, FinalizerKeyword](block: BlockKeyword, cases: Catcher[CaseKeyword], finalizer: FinalizerKeyword)
Companion
object
Companion
class
case
class TryFinally[TryKeyword, FinalizerKeyword](block: TryKeyword, finalizer: FinalizerKeyword)
Companion
object
object TryFinally
Companion
class
object Typed
object Using
case
class While[ConditionKeyword, BodyKeyword](condition: ConditionKeyword, body: BodyKeyword)
Companion
object
object While
Companion
class
final case
class WithFilter[UpstreamKeyword, UpstreamValue](upstream: UpstreamKeyword, condition: UpstreamValue => Boolean)
Companion
object
object WithFilter
Companion
class
object Yield extends LowPriorityYield0

Types

opaque type Await[Result]

Await is a Keyword to extract value from a scala.concurrent.Future.

Await is a Keyword to extract value from a scala.concurrent.Future.

This keyword is available in functions whose return types are Future, domains.task.Task, or any exception aware continuations as (_ !! Throwable !! _).

Authors

杨博 (Yang Bo)

Example

Given a Future:

import com.thoughtworks.dsl.bangnotation._
import scala.concurrent.Future
val myFuture40 = Future {
 40
}

You can Await the Future in another Future

def myFuture42 = *[Future] {
 !Await(myFuture40) + 2
}

A Future can be converted to a domains.task.Task with the help of Await.

import com.thoughtworks.dsl.domains.Task
import com.thoughtworks.dsl.keywords.Await
val myTask = *[Task] {
 !Await(myFuture42)
}

Then a domains.task.Task can be converted back to a scala.concurrent.Future via domains.task.Task.toFuture.

val myAssertionTask = *[Task] {
 !Shift(myTask) should be(42)
}
Task.toFuture(myAssertionTask)

!Await can be used together with try / catch / finally.

import scala.concurrent.Future
import com.thoughtworks.dsl.bangnotation._
val buffer = new StringBuffer
def recoverFuture = Future {
 buffer.append("Oh")
}
def exceptionalFuture = Future[StringBuffer] {
 throw new IllegalStateException("No")
}
def myFuture = *[Future] {
 try {
   !Await(exceptionalFuture)
 } catch {
   case e: IllegalStateException =>
     !Await(recoverFuture)
     buffer.append(' ')
     buffer.append(e.getMessage)
 } finally {
   buffer.append("!")
 }
}
myFuture.map(_.toString should be("Oh No!"))

Other keywords, including Return or Get, can be used together with Await

import scala.concurrent.Future
import com.thoughtworks.dsl.keywords.{Get, Return}
import com.thoughtworks.dsl.bangnotation._
val buffer = new StringBuffer
def recoverFuture = Future {
 buffer.append("Oh")
}
def exceptionalFuture = Future[StringBuffer] {
 throw new IllegalStateException("No")
}
def myFuture = reset[Char => Future[StringBuffer]](!Return {
 try {
   !Await(exceptionalFuture)
 } catch {
   case e: IllegalStateException =>
     !Await(recoverFuture)
     buffer.append(!Get[Char]())
     buffer.append(e.getMessage)
 } finally {
   buffer.append("!")
 }
})
myFuture(' ').map(_.toString should be("Oh No!"))
opaque type In[Element]
type Match[Keyword, Value, CaseSet] = FlatMap[Keyword, Value, CaseSet]
opaque type Monadic[Functor[_], Value]

A keyword for extracting monadic value from the monadic expression fa.

A keyword for extracting monadic value from the monadic expression fa.

See also

com.thoughtworks.dsl.domains.cats for using this Monadic keyword with cats.Monad.

com.thoughtworks.dsl.domains.scalaz for using this Monadic keyword with scalaz.Monad.

Todo

Monadic should be a scala.AnyVal after https://github.com/scala/bug/issues/10595 is resolved.

opaque type Pure[+Value]
opaque type Return[ReturnValue]

A Dsl.Keyword to early return a lifted value from the enclosing function.

A Dsl.Keyword to early return a lifted value from the enclosing function.

Authors

杨博 (Yang Bo)

opaque type Shift[R, A]
Authors

杨博 (Yang Bo)

opaque type Suspend[Keyword]
opaque type Typed[Keyword, Value]

A type annotated keyword

A type annotated keyword

opaque type Using[R <: AutoCloseable]

This Using keyword automatically manage resources in scala.concurrent.Future, domains.task.Task, and other asynchronous domains derived from Future or Task.

This Using keyword automatically manage resources in scala.concurrent.Future, domains.task.Task, and other asynchronous domains derived from Future or Task.

Authors

杨博 (Yang Bo)

See also

dsl for usage of this Using keyword in continuations

opaque type Yield[Element]
Authors

杨博 (Yang Bo)

See also

comprehension if you want to use traditional for comprehension instead of !-notation.

Example

This Yield keyword must be put inside a function that returns Seq[Element] or Seq[Element] !! ..., or it will not compile.

        import com.thoughtworks.dsl.bangnotation._
        "def f(): Int = !Yield(1)" shouldNot compile

Yield keywords can be used together with other keywords.

        import com.thoughtworks.dsl.bangnotation._
        def gccFlagBuilder(sourceFile: String, includes: String*) = reset[Stream[String]] {
          !Yield("gcc")
          !Yield("-c")
          !Yield(sourceFile)
          val include = !Each(includes)
          !Yield("-I")
          !Yield(include)
          !Continue
        }
        gccFlagBuilder("main.c", "lib1/include", "lib2/include") should be(Stream("gcc", "-c", "main.c", "-I", "lib1/include", "-I", "lib2/include"))