com.thoughtworks.dsl.keywords
Type members
Classlikes
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.ReadFileimport 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
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
- 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
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
- Companion
- object
Iterates though each element in elements.
Iterates though each element in elements.
- Companion
- object
- Companion
- object
- Companion
- object
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 beO
.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
- Companion
- object
- Companion
- object
Types
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 withtry
/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!"))
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.
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)
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
comprehension if you want to use traditional
for
comprehension instead of !-notation.- Example
This
Yield
keyword must be put inside a function that returnsSeq[Element]
orSeq[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"))