Skip to content
This repository has been archived by the owner on Mar 11, 2020. It is now read-only.

Commit

Permalink
Merge pull request #51 from rossabaker/topic/2.12
Browse files Browse the repository at this point in the history
Release for 2.12
  • Loading branch information
timperrett authored Feb 24, 2017
2 parents 1a46eec + 0484e14 commit c758d62
Show file tree
Hide file tree
Showing 25 changed files with 347 additions and 90 deletions.
19 changes: 13 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,25 @@ matrix:
include:
# scala 2.10
- jdk: oraclejdk8
scala: 2.10.5
env: SCALAZ_STREAM_VERSION=0.7.3a
scala: 2.10.6
env: SCALAZ_VERSION=7.1.11
- jdk: oraclejdk8
scala: 2.10.5
env: SCALAZ_STREAM_VERSION=0.8.1a
scala: 2.10.6
env: SCALAZ_VERSION=7.2.7
# scala 2.11
- jdk: oraclejdk8
scala: 2.11.8
env: SCALAZ_STREAM_VERSION=0.8.1a
env: SCALAZ_VERSION=7.1.11
- jdk: oraclejdk8
scala: 2.11.8
env: SCALAZ_STREAM_VERSION=0.7.3a
env: SCALAZ_VERSION=7.2.7
# scala 2.12
- jdk: oraclejdk8
scala: 2.11.8
env: SCALAZ_VERSION=7.1.11
- jdk: oraclejdk8
scala: 2.12.1
env: SCALAZ_VERSION=7.2.7

branches:
only:
Expand Down
9 changes: 3 additions & 6 deletions core/build.sbt
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import verizon.build.ScalazPlugin._

resolvers ++= Seq(
"scalaz.bintray" at "http://dl.bintray.com/scalaz/releases",
"oncue.bintray" at "http://dl.bintray.com/oncue/releases"
)

libraryDependencies ++= {
val ermineVersion =
if(scalazStreamVersion.value.startsWith("0.7")) "0.3.3a"
else "0.3.3"

Seq(
"org.scalaz.stream" %% "scalaz-stream" % scalazStreamVersion.value,
"io.verizon.ermine" %% "parser" % ermineVersion
"org.scalaz.stream" %% "scalaz-stream" % scalazCrossVersioners.`scalaz-stream-0.8`(scalazVersion.value)("0.8.6"),
"io.verizon.ermine" %% "parser" % scalazCrossVersioners.default(scalazVersion.value)("0.4.7")
)
}
2 changes: 1 addition & 1 deletion core/src/main/scala/knobs/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ case class Config(env: Env) {

/** Look up the value under the key with the given name and error if it doesn't exist */
def require[A:Configured](name: Name): A =
lookup(name).getOrElse(throw KeyError(name))
lookup(name).getOrElse(env.get(name).fold(throw KeyError(name))(v => throw ValueError(name, v)))
}

object Config {
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/scala/knobs/Configured.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ trait Configured[A] {
}

object Configured {
def apply[A:Configured]: Configured[A] = implicitly[Configured[A]]

// second parameter (of any non-Unit) is required to get around SAM-derived ambiguities
def apply[A](implicit A: Configured[A], T: Trivial): Configured[A] = A

def apply[A](f: CfgValue => Option[A]): Configured[A] = new Configured[A] {
def apply(v: CfgValue) = f(v)
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/scala/knobs/MutableConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ case class MutableConfig(root: String, base: BaseConfig) {
*/
def require[A:Configured](name: Name): Task[A] = for {
v <- lookup(name)
r <- v.map(Task.now(_)).getOrElse(Task.fail(KeyError(name)))
r <- v.map(Task.now).getOrElse(
getEnv.map(_.get(name).fold(throw KeyError(name))(v => throw ValueError(name, v)))
)
} yield r

/**
Expand Down
16 changes: 7 additions & 9 deletions core/src/main/scala/knobs/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,18 @@ object ConfigParser {

/** Top-level parser of configuration files */
lazy val topLevel: Parser[List[Directive]] = "configuration" |: {
directives << skipLWS << realEOF
skipLWS >> directives << realEOF
}

/** Parser of configuration files that don't support import directives */
lazy val sansImport: Parser[List[Directive]] = {
val d = (skipLWS >> choice(bindDirective, groupDirective) << skipHWS)
d.map2(attempt(newline >> d).many)(_ :: _)
}
lazy val sansImport: Parser[List[Directive]] =
(choice(bindDirective, groupDirective) << skipHWS).sepEndBy(newline << skipLWS)

lazy val directives: Parser[List[Directive]] =
directive.map2(attempt(newline >> directive).many)(_ :: _)
(directive << skipHWS).sepEndBy(newline << skipLWS)

lazy val directive: Parser[Directive] =
(skipLWS >> choice(importDirective, bindDirective, groupDirective) << skipHWS) scope
"directive"
choice(importDirective, bindDirective, groupDirective) scope "directive"

lazy val importDirective = "import directive" |: {
word("import") >> skipLWS >> stringLiteral.map(Import(_))
Expand Down Expand Up @@ -98,7 +95,8 @@ object ConfigParser {

lazy val ident: Parser[Name] = for {
n <- satisfy(c => Character.isLetter(c)).map2(takeWhile(isCont))(_ +: _)
_ <- failWhen[Parser](n == "import", s"reserved word ($n) used as an identifier")
w <- unit(n.mkString)
_ <- failWhen[Parser](w == "import", s"reserved word ($w) used as an identifier")
} yield n.mkString

lazy val value: Parser[CfgValue] = "value" |: choice(
Expand Down
23 changes: 23 additions & 0 deletions core/src/main/scala/knobs/Trivial.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon. All Rights Reserved.
//:
//: Licensed under the Apache License, Version 2.0 (the "License");
//: you may not use this file except in compliance with the License.
//: You may obtain a copy of the License at
//:
//: http://www.apache.org/licenses/LICENSE-2.0
//:
//: Unless required by applicable law or agreed to in writing, software
//: distributed under the License is distributed on an "AS IS" BASIS,
//: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//: See the License for the specific language governing permissions and
//: limitations under the License.
//:
//: ----------------------------------------------------------------------------
package knobs

sealed trait Trivial

object Trivial {
implicit val trivial: Trivial = new Trivial {}
}
20 changes: 20 additions & 0 deletions core/src/main/scala/knobs/ValueError.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//: ----------------------------------------------------------------------------
//: Copyright (C) 2015 Verizon. All Rights Reserved.
//:
//: Licensed under the Apache License, Version 2.0 (the "License");
//: you may not use this file except in compliance with the License.
//: You may obtain a copy of the License at
//:
//: http://www.apache.org/licenses/LICENSE-2.0
//:
//: Unless required by applicable law or agreed to in writing, software
//: distributed under the License is distributed on an "AS IS" BASIS,
//: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//: See the License for the specific language governing permissions and
//: limitations under the License.
//:
//: ----------------------------------------------------------------------------
package knobs

case class ValueError(name: String, value: CfgValue) extends Exception(s"Key '$name' found but value '${value.pretty}' isn't the expected type.")

27 changes: 27 additions & 0 deletions core/src/main/scalaz-7.1/knobs/compatibility.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon. All Rights Reserved.
//:
//: Licensed under the Apache License, Version 2.0 (the "License");
//: you may not use this file except in compliance with the License.
//: You may obtain a copy of the License at
//:
//: http://www.apache.org/licenses/LICENSE-2.0
//:
//: Unless required by applicable law or agreed to in writing, software
//: distributed under the License is distributed on an "AS IS" BASIS,
//: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//: See the License for the specific language governing permissions and
//: limitations under the License.
//:
//: ----------------------------------------------------------------------------
package knobs

import scalaz.\/
import scalaz.concurrent.Task

object compatibility {
implicit class BedazledTask[A](task: Task[A]){ self =>
def unsafePerformAsync(g: (Throwable \/ A) => Unit): Unit = task.runAsync(g)
def unsafePerformSync: A = task.run
}
}
23 changes: 23 additions & 0 deletions core/src/main/scalaz-7.2/knobs/compatibility.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon. All Rights Reserved.
//:
//: Licensed under the Apache License, Version 2.0 (the "License");
//: you may not use this file except in compliance with the License.
//: You may obtain a copy of the License at
//:
//: http://www.apache.org/licenses/LICENSE-2.0
//:
//: Unless required by applicable law or agreed to in writing, software
//: distributed under the License is distributed on an "AS IS" BASIS,
//: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//: See the License for the specific language governing permissions and
//: limitations under the License.
//:
//: ----------------------------------------------------------------------------
package knobs

import scalaz.concurrent.Task

object compatibility {
// for source compatibility in both scalaz versions
}
11 changes: 0 additions & 11 deletions core/src/main/scalaz-stream-0.7/knobs/compatibility.scala

This file was deleted.

7 changes: 0 additions & 7 deletions core/src/main/scalaz-stream-0.8/knobs/compatibility.scala

This file was deleted.

7 changes: 7 additions & 0 deletions core/src/test/resources/all-comments.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

# param1=true
# param2="hello"

# group {
# this.group.is = "commented out"
# }
2 changes: 2 additions & 0 deletions core/src/test/resources/import-as-ident.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
evil.import.bad = "Yuck."

10 changes: 10 additions & 0 deletions core/src/test/resources/pathological.cfg
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@



# ^^^ Start with some irritating whitespace

# Comment

aa # Comment
Expand Down Expand Up @@ -41,3 +46,8 @@ dur = 5 seconds
ca.cb {
cd = "fuf"
}

# And finish with some more irritating whitespace



54 changes: 51 additions & 3 deletions core/src/test/scala/knobs/Test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import scalaz.concurrent.Task
import Prop._
import scala.concurrent.duration._
import compatibility._
import scalaz.\/

object Test extends Properties("Knobs") {

Expand Down Expand Up @@ -74,6 +75,15 @@ object Test extends Properties("Knobs") {
p2 = (acx == Some(1)) :| "nested"
} yield p1 && p2 }

lazy val importAsIdentTest: Task[Prop] =
load(List(Required(ClassPathResource("import-as-ident.cfg")))).attempt.map(_.fold(
{
case ConfigError(_, msg) => msg contains "reserved word (import) used as an identifier"
case _ => false
},
_ => false
))

lazy val loadPropertiesTest: Task[Prop] =
withLoad(List(Required(SysPropsResource(Prefix("path"))))) { cfg =>
cfg.lookup[String]("path.separator").map(_.isDefined)
Expand All @@ -98,9 +108,7 @@ object Test extends Properties("Knobs") {
lazy val fallbackErrorTest: Task[Prop] =
load(List(Required(ClassPathResource("foobar.cfg") or
ClassPathResource("foobar.cfg")))).attempt.map(_.fold(
e =>
{ println(e);
e.getMessage.toList.filter(_ == '\n').size == 3},
e => (e.getMessage.toList.filter(_ == '\n').size == 3),
a => false
))

Expand All @@ -124,12 +132,47 @@ object Test extends Properties("Knobs") {
case _ => false
}

lazy val immutableConfigValueErrorTest: Task[Prop] = {
sys.props += ("test.immutable.value.error" -> "12345")
withLoad(List(Required(SysPropsResource(Prefix("test.immutable"))))) {
mcfg => mcfg.immutable.map(
cfg => \/.fromTryCatchNonFatal(cfg.require[String]("test.immutable.value.error")).fold(
{
case ValueError(n, v) => true
case _ => false
},
_ => false
)
)
}
}

lazy val mutableConfigValueErrorTest: Task[Prop] = {
sys.props += ("test.mutable.value.error" -> "12345")
withLoad(List(Required(SysPropsResource(Prefix("test.mutable"))))) { cfg =>
cfg.require[String]("test.mutable.value.error").attempt.map(
_.fold(
{
case ValueError(n, v) => true
case _ => false
},
_ => false
)
)
}
}

lazy val allCommentsTest: Task[Prop] =
load(List(Required(ClassPathResource("all-comments.cfg")))).attempt.map(_.isRight)

property("load-pathological-config") = loadTest.unsafePerformSync

property("interpolation") = interpTest.unsafePerformSync

property("import") = importTest.unsafePerformSync

property("import-as-ident") = importAsIdentTest.unsafePerformSync

property("load-system-properties") = loadPropertiesTest.unsafePerformSync

property("system-properties-negative") = propertiesNegativeTest.unsafePerformSync
Expand All @@ -156,4 +199,9 @@ object Test extends Properties("Knobs") {
(Configured[FiniteDuration].apply(cfg): Option[Duration]) ?= Configured[Duration].apply(cfg)
}

property("immutable-config-value-error") = immutableConfigValueErrorTest.unsafePerformSync

property("mutable-config-value-error") = mutableConfigValueErrorTest.unsafePerformSync

property("all-comments") = allCommentsTest.unsafePerformSync
}
19 changes: 17 additions & 2 deletions project.sbt
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@

//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon. All Rights Reserved.
//:
//: Licensed under the Apache License, Version 2.0 (the "License");
//: you may not use this file except in compliance with the License.
//: You may obtain a copy of the License at
//:
//: http://www.apache.org/licenses/LICENSE-2.0
//:
//: Unless required by applicable law or agreed to in writing, software
//: distributed under the License is distributed on an "AS IS" BASIS,
//: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//: See the License for the specific language governing permissions and
//: limitations under the License.
//:
//: ----------------------------------------------------------------------------
organization in Global := "io.verizon.knobs"

crossScalaVersions in Global := Seq("2.11.8", "2.10.6")
crossScalaVersions in Global := Seq("2.12.1", "2.11.8", "2.10.6")

scalaVersion in Global := crossScalaVersions.value.head

Expand Down
Loading

0 comments on commit c758d62

Please sign in to comment.