diff --git a/.gitignore b/.gitignore index d180f4bd6..05aac0216 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target/ local.sbt secret/ +.idea diff --git a/keywords-Using/build.sbt b/keywords-Using/build.sbt index 8eefca2fd..18caacb90 100644 --- a/keywords-Using/build.sbt +++ b/keywords-Using/build.sbt @@ -21,3 +21,4 @@ scalacOptions ++= { } libraryDependencies += "com.thoughtworks.dsl" %%% "keywords-await" % "1.3.1" % Test +libraryDependencies += "com.thoughtworks.dsl" %%% "domains-task" % "1.3.1" % Test diff --git a/keywords-Using/src/main/scala/com/thoughtworks/dsl/keywords/Using.scala b/keywords-Using/src/main/scala/com/thoughtworks/dsl/keywords/Using.scala index c8473846a..81221e08e 100644 --- a/keywords-Using/src/main/scala/com/thoughtworks/dsl/keywords/Using.scala +++ b/keywords-Using/src/main/scala/com/thoughtworks/dsl/keywords/Using.scala @@ -17,7 +17,23 @@ import scala.util.control.NonFatal */ final case class Using[R <: AutoCloseable](open: () => R) extends AnyVal with Keyword[Using[R], R] -object Using { +trait LowPriorityUsing { + + implicit def usingDsl[R <: AutoCloseable, Domain]: Dsl[Using[R], Domain, R] = + new Dsl[Using[R], Domain, R] { + def cpsApply(keyword: Using[R], handler: R => Domain): Domain = { + val r = keyword.open() + try { + handler(r) + } finally { + r.close() + } + } + } + +} + +object Using extends LowPriorityUsing { implicit def implicitUsing[R <: AutoCloseable](r: => R): Using[R] = Using[R](r _) diff --git a/keywords-Using/src/test/scala/com/thoughtworks/dsl/keywords/UsingSpec.scala b/keywords-Using/src/test/scala/com/thoughtworks/dsl/keywords/UsingSpec.scala new file mode 100644 index 000000000..fb26f03ab --- /dev/null +++ b/keywords-Using/src/test/scala/com/thoughtworks/dsl/keywords/UsingSpec.scala @@ -0,0 +1,121 @@ +package com.thoughtworks.dsl.keywords + +import java.util.concurrent.LinkedBlockingQueue + +import org.scalatest.{FreeSpec, Matchers} +import com.thoughtworks.dsl.domains.task.Task +import scala.concurrent.duration._ + +class UsingSpec extends FreeSpec with Matchers { + + "scopeExit" - { + import Using.scopeExit + + "execute sequence: function" in { + val queue = new LinkedBlockingQueue[Int]() + + def run() = { + !scopeExit(() => queue.offer(1)) + queue.offer(2) + } + + run() + + queue.poll() should be(2) + queue.poll() should be(1) + } + + "execute sequence: function contains call-by-name function call" in { + val queue = new LinkedBlockingQueue[Int]() + + def runOp(op: => Unit): Unit = op + + def run() = { + !scopeExit(() => queue.offer(1)) + runOp { + !scopeExit(() => queue.offer(3)) + } + queue.offer(2) + } + + run() + + queue.poll() should be(3) + queue.poll() should be(2) + queue.poll() should be(1) + } + + "execute sequence: function contains call of function accepts function literal execute sequence" in { + val queue = new LinkedBlockingQueue[Int]() + + def runOp(op: () => Unit): Unit = op() + + def run() = { + !scopeExit(() => queue.offer(1)) + runOp(() => !scopeExit(() => queue.offer(3))) + queue.offer(2) + } + + run() + + queue.poll() should be(3) + queue.poll() should be(2) + queue.poll() should be(1) + } + + "execute sequence: task" in { + val queue = new LinkedBlockingQueue[Int]() + + def run() = Task { + !scopeExit(() => queue.offer(1)) + queue.offer(2) + } + + Task.blockingAwait(run(), 1.minute) + + queue.poll() should be(2) + queue.poll() should be(1) + } + + + "execute sequence: task contains call-by-name function call" in { + val queue = new LinkedBlockingQueue[Int]() + + def runTask(op: => Task[Unit]): Unit = Task.blockingAwait(op, 1.minute) + + def run() = Task { + !scopeExit(() => queue.offer(1)) + runTask { + Task(!scopeExit(() => queue.offer(3))) + } + queue.offer(2) + } + + Task.blockingAwait(run(), 1.minute) + + queue.poll() should be(3) + queue.poll() should be(2) + queue.poll() should be(1) + } + + "execute sequence: task contains call of function accepts function literal execute sequence" in { + val queue = new LinkedBlockingQueue[Int]() + + def runOp(op: () => Task[Unit]): Unit = Task.blockingAwait(op(), 1.minute) + + def run() = { + !scopeExit(() => queue.offer(1)) + runOp(() => Task(!scopeExit(() => queue.offer(3)))) + queue.offer(2) + } + + run() + + queue.poll() should be(3) + queue.poll() should be(2) + queue.poll() should be(1) + } + + } + +}