Configs: use a uniform syntax without Match exceptions (#507)
* Configs: use a uniform syntax without Match exceptions The old style of specifying Configs used total functions. The only way to indicate that a key was not matched was to throw an exception. Not only was this a performance concern, but it also caused confusing error messages whenever you had a match failure from a lookup within a lookup. The exception could get handled by an outer-lookup that then reported the wrong key as missing.
This commit is contained in:
committed by
Henry Cook
parent
b448387899
commit
52bb6cd9d9
@ -3,9 +3,6 @@
|
||||
package config
|
||||
|
||||
class Field[T]
|
||||
class CDEMatchError() extends Exception {
|
||||
override def fillInStackTrace() = this
|
||||
}
|
||||
|
||||
abstract class View {
|
||||
final def apply[T](pname: Field[T]): T = apply(pname, this)
|
||||
@ -15,38 +12,28 @@ abstract class View {
|
||||
}
|
||||
|
||||
abstract class Parameters extends View {
|
||||
final def ++ (x: Parameters): Parameters = new ChainParameters(this, x)
|
||||
final def alter(f: (Any, View, View, View) => Any): Parameters = Parameters(f) ++ this
|
||||
final def alter(m: Map[Any,Any]): Parameters = Parameters(m) ++ this
|
||||
final def alter(f: PartialFunction[Any,Any]): Parameters = Parameters(f) ++ this
|
||||
final def alterPartial(f: PartialFunction[Any,Any]): Parameters = Parameters(f) ++ this
|
||||
final def ++ (x: Parameters): Parameters = new ChainParameters(this, x)
|
||||
final def alter(f: (View, View, View) => PartialFunction[Any,Any]): Parameters = Parameters(f) ++ this
|
||||
final def alterPartial(f: PartialFunction[Any,Any]): Parameters = Parameters((_,_,_) => f) ++ this
|
||||
|
||||
protected[config] def chain(site: View, tail: View, pname: Any): Any
|
||||
protected[config] def find(pname: Any, site: View) = chain(site, new TerminalView, pname)
|
||||
}
|
||||
|
||||
object Parameters {
|
||||
def empty: Parameters = new EmptyParameters
|
||||
def apply(f: (Any, View, View, View) => Any): Parameters = new FunctionParameters(f)
|
||||
def apply(m: Map[Any,Any]): Parameters = new MapParameters(m)
|
||||
def apply(f: PartialFunction[Any,Any]): Parameters = new PartialParameters(f)
|
||||
def partial(f: PartialFunction[Any,Any]): Parameters = new PartialParameters(f)
|
||||
def empty: Parameters = new EmptyParameters
|
||||
def apply(f: (View, View, View) => PartialFunction[Any,Any]): Parameters = new PartialParameters(f)
|
||||
def root(p: Parameters) = p
|
||||
}
|
||||
|
||||
class Config(p: Parameters) extends Parameters {
|
||||
def this(f: (Any, View, View) => Any) = this(Parameters((p,s,h,u) => f(p,s,h))) // backwards compat; don't use
|
||||
def this(f: (Any, View, View, View) => Any) = this(Parameters(f))
|
||||
def this(m: Map[Any,Any]) = this(Parameters(m))
|
||||
def this(f: PartialFunction[Any,Any]) = this(Parameters(f))
|
||||
def this(f: (View, View, View) => PartialFunction[Any,Any]) = this(Parameters(f))
|
||||
|
||||
protected[config] def chain(site: View, tail: View, pname: Any) = p.chain(site, tail, pname)
|
||||
override def toString = this.getClass.getSimpleName
|
||||
def toInstance = this
|
||||
}
|
||||
|
||||
class ConfigPartial(f: PartialFunction[Any,Any]) extends Config(Parameters(f))
|
||||
|
||||
// Internal implementation:
|
||||
|
||||
private class TerminalView extends View {
|
||||
@ -66,22 +53,9 @@ private class EmptyParameters extends Parameters {
|
||||
def chain(site: View, tail: View, pname: Any) = tail.find(pname, site)
|
||||
}
|
||||
|
||||
private class FunctionParameters(f: (Any, View, View, View) => Any) extends Parameters {
|
||||
private class PartialParameters(f: (View, View, View) => PartialFunction[Any,Any]) extends Parameters {
|
||||
protected[config] def chain(site: View, tail: View, pname: Any) = {
|
||||
try f(pname, site, this, tail)
|
||||
catch {
|
||||
case e: CDEMatchError => tail.find(pname, site)
|
||||
case e: scala.MatchError => tail.find(pname, site)
|
||||
}
|
||||
val g = f(site, this, tail)
|
||||
if (g.isDefinedAt(pname)) g.apply(pname) else tail.find(pname, site)
|
||||
}
|
||||
}
|
||||
|
||||
private class MapParameters(map: Map[Any, Any]) extends Parameters {
|
||||
protected[config] def chain(site: View, tail: View, pname: Any) =
|
||||
map.get(pname).getOrElse(find(pname, site))
|
||||
}
|
||||
|
||||
private class PartialParameters(f: PartialFunction[Any,Any]) extends Parameters {
|
||||
protected[config] def chain(site: View, tail: View, pname: Any) =
|
||||
if (f.isDefinedAt(pname)) f.apply(pname) else tail.find(pname, site)
|
||||
}
|
||||
|
Reference in New Issue
Block a user