summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/library/scala/sys/Prop.scala101
-rw-r--r--src/library/scala/sys/PropImpl.scala58
-rw-r--r--src/library/scala/sys/SystemProperties.scala (renamed from src/library/scala/sys/PropertiesMap.scala)28
-rw-r--r--src/library/scala/sys/package.scala6
-rw-r--r--test/files/run/sysprops.scala50
5 files changed, 237 insertions, 6 deletions
diff --git a/src/library/scala/sys/Prop.scala b/src/library/scala/sys/Prop.scala
new file mode 100644
index 0000000000..8444976826
--- /dev/null
+++ b/src/library/scala/sys/Prop.scala
@@ -0,0 +1,101 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.sys
+
+/** A lightweight interface wrapping a property contained in some
+ * unspecified map. Generally it'll be the system properties but this
+ * is not a requirement.
+ *
+ * See `scala.sys.SystemProperties` for an example usage.
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+trait Prop[T] {
+ /** The full name of the property, e.g. "java.awt.headless".
+ */
+ def key: String
+
+ /** If the key exists in the properties map, converts the value
+ * to type `T` using valueFn. As yet no validation is performed:
+ * it will throw an exception on a failed conversion.
+ * @return the converted value, or `zero` if not in the map
+ */
+ def value: T
+
+ /** True if the key exists in the properties map. Note that this
+ * is not sufficient for a Boolean property to be considered true.
+ * @return whether the map contains the key
+ */
+ def isSet: Boolean
+
+ /** Sets the property.
+ *
+ * @param the new string value
+ * @return the old value, or null if it was unset.
+ */
+ def set(newValue: String): String
+
+ /** Gets the current string value if any. Will not return null: use
+ * `isSet` to test for existence.
+ * @return the current string value if any, else the empty string
+ */
+ def get: String
+
+ /** Removes the property from the underlying map.
+ */
+ def clear(): Unit
+
+ /** A value of type `T` for use when the property is unset.
+ * The default implementation delivers null for reference types
+ * and 0/0.0/false for non-reference types.
+ */
+ protected def zero: T
+}
+
+/** A few additional conveniences for Boolean properties.
+ */
+trait BooleanProp extends Prop[Boolean] {
+ /** The default implementation of `value` adheres to java's definition
+ * of truth, which means it is true only if there is a value in the map and
+ * that value, once converted to all lower case, is equal to "true".
+ *
+ * @return true if the current String is considered true, false otherwise
+ */
+ def value: Boolean
+
+ /** Alter this property so that `value` will be true. */
+ def enable(): Unit
+
+ /** Alter this property so that `value` will be false. */
+ def disable(): Unit
+
+ /** Toggle the property between enabled and disabled states. */
+ def toggle(): Unit
+}
+
+object Prop extends PropCompanion {
+ /** A creator of property instances. For any type `T`, if an implicit
+ * parameter of type Creator[T] is in scope, a Prop[T] can be created
+ * via this object's apply method.
+ */
+ trait Creator[T] {
+ /** Creates a Prop[T] of this type based on the given key. */
+ def apply(key: String): Prop[T]
+ }
+
+ implicit object BooleanProp extends BooleanCreatorImpl
+ implicit object StringProp extends CreatorImpl[String](s => s)
+ implicit object IntProp extends CreatorImpl[Int](_.toInt)
+ implicit object DoubleProp extends CreatorImpl[Double](_.toDouble)
+
+ def bool[T](key: String): BooleanProp = BooleanProp(key)
+ def apply[T: Creator](key: String): Prop[T] = implicitly[Creator[T]] apply key
+}
diff --git a/src/library/scala/sys/PropImpl.scala b/src/library/scala/sys/PropImpl.scala
new file mode 100644
index 0000000000..02f00f682b
--- /dev/null
+++ b/src/library/scala/sys/PropImpl.scala
@@ -0,0 +1,58 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.sys
+
+import scala.collection.mutable
+
+/** The internal implementation of scala.sys.Prop.
+ */
+private[sys] class PropImpl[T](val key: String, valueFn: String => T) extends Prop[T] {
+ def value: T = if (isSet) valueFn(get) else zero
+ def isSet = underlying contains key
+ def set(newValue: String): String = {
+ val old = if (isSet) get else null
+ underlying(key) = newValue
+ old
+ }
+ def get: String =
+ if (isSet) underlying(key)
+ else ""
+
+ def clear() = underlying -= key
+
+ /** The underlying property map, in our case always sys.props */
+ protected def underlying: mutable.Map[String, String] = scala.sys.props
+ protected def zero: T = null.asInstanceOf[T]
+ private def getString = if (isSet) "currently: " + get else "unset"
+ override def toString = "%s (%s)".format(key, getString)
+}
+
+trait PropCompanion {
+ self: Prop.type =>
+
+ private[sys] class BooleanPropImpl(key: String, valueFn: String => Boolean) extends PropImpl[Boolean](key, valueFn) with BooleanProp {
+ def enable() = this set "true"
+ def disable() = this.clear()
+ def toggle() = if (value) disable() else enable()
+ }
+ private[sys] abstract class CreatorImpl[T](f: String => T) extends Creator[T] {
+ def apply(key: String): Prop[T] = new PropImpl[T](key, f)
+ }
+ /** Implicit objects for the standard types. Custom ones can also be
+ * created by implementing Creator[T].
+ */
+ private[sys] trait BooleanCreatorImpl extends Creator[Boolean] {
+ self: BooleanProp.type =>
+
+ /** As implemented in java.lang.Boolean.getBoolean. */
+ private def javaStyleTruth(s: String) = s.toLowerCase == "true"
+
+ def apply(key: String): BooleanProp = new BooleanPropImpl(key, javaStyleTruth)
+ }
+}
diff --git a/src/library/scala/sys/PropertiesMap.scala b/src/library/scala/sys/SystemProperties.scala
index 68f8d10418..cc8131220f 100644
--- a/src/library/scala/sys/PropertiesMap.scala
+++ b/src/library/scala/sys/SystemProperties.scala
@@ -20,12 +20,34 @@ import scala.collection.JavaConverters._
* @version 2.9
* @since 2.9
*/
-class PropertiesMap extends mutable.Map[String, String] {
- override def empty = new PropertiesMap
+class SystemProperties extends mutable.Map[String, String] {
+ override def empty = new SystemProperties
override def default(key: String): String = null
def iterator: Iterator[(String, String)] = System.getProperties().asScala.iterator
def get(key: String) = Option(System.getProperty(key))
def -= (key: String): this.type = { System.clearProperty(key) ; this }
def += (kv: (String, String)): this.type = { System.setProperty(kv._1, kv._2) ; this }
-} \ No newline at end of file
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ private lazy val propertyHelp = mutable.Map[String, String]()
+ private def bool(key: String, helpText: String) = {
+ try Prop.bool(key)
+ finally propertyHelp(key) = helpText
+ }
+ def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4 = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+}
diff --git a/src/library/scala/sys/package.scala b/src/library/scala/sys/package.scala
index e8c17596ff..16faded419 100644
--- a/src/library/scala/sys/package.scala
+++ b/src/library/scala/sys/package.scala
@@ -49,10 +49,10 @@ package object sys {
/** A bidirectional, mutable Map representing the current system Properties.
*
- * @return a PropertiesMap.
- * @see `scala.sys.PropertiesMap`
+ * @return a SystemProperties.
+ * @see `scala.sys.SystemProperties`
*/
- def props: PropertiesMap = new PropertiesMap
+ def props: SystemProperties = new SystemProperties
/** An immutable Map representing the current system environment.
*
diff --git a/test/files/run/sysprops.scala b/test/files/run/sysprops.scala
new file mode 100644
index 0000000000..d3df22d634
--- /dev/null
+++ b/test/files/run/sysprops.scala
@@ -0,0 +1,50 @@
+import sys._
+
+/** Basic sys.Prop test. */
+object Test {
+ val key = "ding.dong.doobie"
+
+ def bool() = {
+ val prop = Prop.bool(key)
+ assert(prop.key == key)
+
+ prop.clear()
+ assert(!prop.value)
+ assert(!prop.isSet)
+ assert(prop.get != null)
+
+ prop set "dingus"
+ assert(prop.get == "dingus")
+ assert(!prop.value)
+ prop set "true"
+ assert(prop.value)
+ prop.toggle()
+ assert(!prop.value)
+ prop.enable()
+ assert(prop.value)
+ prop.disable()
+ assert(!prop.value)
+ }
+ def int() = {
+ val prop = Prop[Int](key)
+ prop.clear()
+ assert(prop.value == 0)
+ prop.set("523")
+ assert(prop.value == 523)
+ prop.set("DingusInt")
+
+ try { println(prop.value) ; assert(false, "should not get here") }
+ catch { case _: Exception => () }
+ }
+ def double() = {
+ val prop = Prop[Double](key)
+ prop.set("55.0")
+ assert(prop.value == 55.0)
+ }
+
+ def main(args: Array[String]): Unit = {
+ bool()
+ int()
+ double()
+ }
+}