diff options
author | Lex Spoon <lex@lexspoon.org> | 2006-03-21 14:29:49 +0000 |
---|---|---|
committer | Lex Spoon <lex@lexspoon.org> | 2006-03-21 14:29:49 +0000 |
commit | e7bdebbdf69c62404e93a3e69c6d4eba7f7fc62f (patch) | |
tree | 44bfba0c71686f46a850a34ea818517daaa62b37 /src/library | |
parent | 5c15a9a9d57409632582a6ffae350c636eaa720a (diff) | |
download | scala-e7bdebbdf69c62404e93a3e69c6d4eba7f7fc62f.tar.gz scala-e7bdebbdf69c62404e93a3e69c6d4eba7f7fc62f.tar.bz2 scala-e7bdebbdf69c62404e93a3e69c6d4eba7f7fc62f.zip |
Added a Fluid class, and used it to allow console
to have new input and output streams temporarily
pushed in a thread-sensible way.
Diffstat (limited to 'src/library')
-rw-r--r-- | src/library/scala/Console.scala | 74 | ||||
-rw-r--r-- | src/library/scala/util/Fluid.scala | 61 |
2 files changed, 123 insertions, 12 deletions
diff --git a/src/library/scala/Console.scala b/src/library/scala/Console.scala index a3e9a5383b..79a3c586d8 100644 --- a/src/library/scala/Console.scala +++ b/src/library/scala/Console.scala @@ -10,6 +10,7 @@ package scala; +import scala.util.Fluid; /** The <code>Console</code> object implements functionality for @@ -52,34 +53,83 @@ object Console { final val REVERSED = "\033[7m"; final val INVISIBLE = "\033[8m"; - private var out: PrintStream = java.lang.System.out; - private var in: BufferedReader = - new BufferedReader(new InputStreamReader(java.lang.System.in)); + private val outFluid = new Fluid[PrintStream](java.lang.System.out); + private val inFluid = new Fluid[BufferedReader]( + new BufferedReader(new InputStreamReader(java.lang.System.in))); + + private def out = outFluid.value + private def in = inFluid.value /** Set the default output stream. * * @param out the new output stream. */ - def setOut(out: PrintStream): Unit = { - this.out = out; - } + def setOut(out: PrintStream): Unit = outFluid.set(out) - /** Set the default input stream. + /** Set the default output stream for the duration + * of execution of one thunk. * - * @param in the new input stream. + * @param out the new output stream. + * @param thunk the code to execute with + * the new output stream active */ - def setIn(in: InputStream): Unit = { - this.in = new BufferedReader(new InputStreamReader(in)); - } + def withOut[T](out: PrintStream)(thunk: =>T): T = + outFluid.withValue(out)(thunk) + + /** Set the default output stream. + * + * @param@ out the new output stream. + */ + def setOut(out: OutputStream): Unit = + setOut(new PrintStream(out)) + + /** Set the default output stream for the duration + * of execution of one thunk. + * + * @param out the new output stream. + * @param thunk the code to execute with + * the new output stream active + */ + def withOut[T](out: OutputStream)(thunk: =>T): T = + withOut(new PrintStream(out))(thunk) + /** Set the default input stream. * * @param reader specifies the new input stream. */ def setIn(reader: Reader): Unit = { - this.in = new BufferedReader(reader); + inFluid.set(new BufferedReader(reader)) } + /** Set the default input stream for the duration + * of execution of one thunk. + * + * @param in the new input stream. + * @param thunk the code to execute with + * the new input stream active + */ + def withIn[T](reader: Reader)(thunk: =>T): T = + inFluid.withValue(new BufferedReader(reader))(thunk) + + + /** Set the default input stream. + * + * @param in the new input stream. + */ + def setIn(in: InputStream): Unit = + setIn(new InputStreamReader(in)) + + /** Set the default input stream for the duration + * of execution of one thunk. + * + * @param in the new input stream. + * @param thunk the code to execute with + * the new input stream active + */ + def withIn[T](in: InputStream)(thunk: =>T): T = + withIn(new InputStreamReader(in))(thunk) + /** Print an object on the terminal. * * @param obj the object to print. diff --git a/src/library/scala/util/Fluid.scala b/src/library/scala/util/Fluid.scala new file mode 100644 index 0000000000..09ea91cc80 --- /dev/null +++ b/src/library/scala/util/Fluid.scala @@ -0,0 +1,61 @@ +package scala.util + + +/** Fluids provide a binding mechanism where the current + * value is found through <em>dynamic scope</em>, but where + * access to the fluid itself is resolved through </em>static + * binding</em> to a variable referencing the fluid. + * + * The current value can be retrieved with the + * <code>value</code> method. New values can be + * pushed using the <code>withValue</code> method. + * Values pushed via <code>withValue</code> only + * stay valid while the <code>withValue</code>'s + * <em>second</em> argument, a parameterless closure, + * executes. When the second argument finishes, + * the fluid reverts to the previous value. + * + * Usage of <code>withValue</code> looks like this: + * <blockquote><pre> + * someFluid.withValue(newValue) { + * // ... code called in here that calls value ... + * // ... will be given back the newValue ... + * } + * </pre></blockquote> + * + * Each thread gets its own stack of bindings. When a + * new thread is created, the fluid gets a copy of + * the stack of bindings from the parent thread, and + * from then on the bindings for the new thread + * are independent of those for the original thread. + */ +class Fluid[T](init: T) { + private val tl = new InheritableThreadLocal + tl.set(init) + + /** Retrieve the current value */ + def value: T = tl.get.asInstanceOf[T] + + + /** Set the value of the fluid while executing the specified + * thunk. + * + * @param newval The value to which to set the fluid + * @param thunk The + */ + def withValue[S](newval: T)(thunk: =>S): S = { + val oldval = value + tl.set(newval) + + try { thunk } finally { + tl.set(oldval) + } + } + + /** Change the currently bound value, discarding the old value. + * Usually withValue() gives better semantics. + */ + def set(newval: T) = { tl.set(newval) } + + override def toString: String = "Fluid(" + value +")" +} |