Skip to content

Commit

Permalink
resolve #47 about adding --all-required flag (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
carueda authored Jul 25, 2019
1 parent 98690da commit 4204db6
Show file tree
Hide file tree
Showing 16 changed files with 132 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ language: scala
scala:
- "2.11.6"

jdk: oraclejdk8
jdk: openjdk8

script: "sbt clean coverage test"
after_success: "sbt coverageReport coveralls"
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
lazy val tscfgVersion = setVersion("0.9.9")
lazy val tscfgVersion = setVersion("0.9.91")

organization := "com.github.carueda"
name := "tscfg"
Expand Down
8 changes: 8 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
2019-07-22 - 0.9.91

- set openjdk8 for travis ci

- resolve #47 about adding `--all-required` flag.
The new `--all-required` flag strictly forces all entries (even objects)
to be required (even the `@optional` annotation is ignored)

2019-02-01 - 0.9.9

- publish v0.9.9 with new `--durations` flag to generate
Expand Down
15 changes: 8 additions & 7 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ from the [releases](https://github.com/carueda/tscfg/releases).
> Or run `sbt assembly` under a clone of this repo to generate the fat jar.
```shell
```
$ java -jar tscfg-x.y.z.jar
tscfg x.y.z
Expand All @@ -191,14 +191,15 @@ Options (default):
--pn <packageName> (tscfg.example)
--cn <className> (ExampleCfg)
--dd <destDir> (/tmp)
--j7 generate code for java <= 7 (8)
--scala generate scala code (java)
--scala:fp report full path (see #36) (false)
--scala:bt use backticks (see #30) (false)
--java generate java code (the default)
--j7 generate code for java <= 7 (>= 8)
--java:getters generate getters (see #31) (false)
--java:optionals use Optional instead of null (false)
--java:optionals use optionals (false)
--scala generate scala code (java)
--scala:bt use backticks (see #30) (false)
--scala:fp report full path (see #36) (false)
--durations use java.time.Duration (false)
--all-required assume all properties are required (see #47)
--tpl <filename> generate config template (no default)
--tpl.ind <string> template indentation string (" ")
--tpl.cp <string> prefix for template comments ("##")
Expand Down Expand Up @@ -446,7 +447,7 @@ and even put them in my own classes**
Sure. However, as the number of configuration properties and levels of nesting increase,
the benefits of automated generation of the typesafe, immutable objects,
along with the centralized verification, shall become more apparent. All of this
–worth emphasizing– based on an explicit schema for the configuration.
–worth emphasizing– based on an explicit *schema* for the configuration.
**Any tscfg best practice for my development workflow?**
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application.conf
Original file line number Diff line number Diff line change
@@ -1 +1 @@
tscfg.version = 0.9.9
tscfg.version = 0.9.91
20 changes: 13 additions & 7 deletions src/main/scala/tscfg/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ object Main {

val defaultGenOpts = GenOpts(
packageName = "tscfg.example",
className = "ExampleCfg",
j7 = false
className = "ExampleCfg"
)

val defaultDestDir: String = "/tmp"
Expand All @@ -32,14 +31,15 @@ object Main {
| --pn <packageName> (${defaultGenOpts.packageName})
| --cn <className> (${defaultGenOpts.className})
| --dd <destDir> ($defaultDestDir)
| --java generate java code (the default)
| --j7 generate code for java <= 7 (8)
| --java:getters generate getters (see #31) (false)
| --java:optionals use optionals (false)
| --scala generate scala code (java)
| --scala:bt use backticks (see #30) (false)
| --scala:fp report full path (see #36) (false)
| --java generate java code (the default)
| --java:getters generate getters (see #31) (false)
| --java:optionals use optionals (false)
| --durations use java.time.Duration (false)
| --all-required assume all properties are required (see #47)
| --tpl <filename> generate config template (no default)
| --tpl.ind <string> template indentation string ("${templateOpts.indent}")
| --tpl.cp <string> prefix for template comments ("${templateOpts.commentPrefix}")
Expand All @@ -52,6 +52,7 @@ object Main {
packageName: String = defaultGenOpts.packageName,
className: String = defaultGenOpts.className,
destDir: String = defaultDestDir,
assumeAllRequired: Boolean = false,
j7: Boolean = false,
language: String = "java",
reportFullPath: Boolean = false,
Expand Down Expand Up @@ -92,6 +93,9 @@ object Main {
case "--dd" :: destDir :: rest =>
traverseList(rest, opts.copy(destDir = chkVal(destDir)))

case "--all-required" :: rest =>
traverseList(rest, opts.copy(assumeAllRequired = true))

case "--j7" :: rest =>
traverseList(rest, opts.copy(j7 = true))

Expand Down Expand Up @@ -154,7 +158,9 @@ object Main {
val destFile = new File(destFilename)
val out = new PrintWriter(destFile)

val genOpts = GenOpts(opts.packageName, opts.className, opts.j7,
val genOpts = GenOpts(opts.packageName, opts.className,
assumeAllRequired = opts.assumeAllRequired,
j7 = opts.j7,
reportFullPath = opts.reportFullPath,
useBackticks = opts.useBackticks,
genGetters = opts.genGetters,
Expand All @@ -164,7 +170,7 @@ object Main {
println(s"parsing: $inputFilename")
val source = io.Source.fromFile(new File(inputFilename)).mkString.trim

val buildResult = ModelBuilder(source)
val buildResult = ModelBuilder(source, assumeAllRequired = opts.assumeAllRequired)
val objectType = buildResult.objectType

//println("\nobjectType:\n |" + objectType.format().replaceAll("\n", "\n |"))
Expand Down
22 changes: 17 additions & 5 deletions src/main/scala/tscfg/ModelBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ object buildWarnings {
Warning(ln, default, s"ignoring default value='$default' in list's element type: $elemType")
}

class ModelBuilder {
class ModelBuilder(assumeAllRequired: Boolean = false) {
import collection._
import buildWarnings._

Expand Down Expand Up @@ -77,9 +77,21 @@ class ModelBuilder {
// contains $, otherwise unquote the key in case is quoted.
val adjName = if (name.contains("$")) name else name.replaceAll("^\"|\"$", "")

// effective optional and default:
val (effOptional, effDefault) = if (assumeAllRequired)
(false, None) // that is, all strictly required.
// A possible variation: allow the `@optional` annotation to still take effect:
//(optFromComments, if (optFromComments) default else None)
else
(optional || optFromComments, default)

//println(s"ModelBuilder: effOptional=$effOptional effDefault=$effDefault " +
// s"assumeAllRequired=$assumeAllRequired optFromComments=$optFromComments " +
// s"adjName=$adjName")

adjName -> model.AnnType(childType,
optional = optional || optFromComments,
default = default,
optional = effOptional,
default = effDefault,
comments = commentsOpt
)
}.toMap
Expand Down Expand Up @@ -257,9 +269,9 @@ object ModelBuilder {

import com.typesafe.config.ConfigFactory

def apply(source: String): ModelBuildResult = {
def apply(source: String, assumeAllRequired: Boolean = false): ModelBuildResult = {
val config = ConfigFactory.parseString(source).resolve()
new ModelBuilder().build(config)
new ModelBuilder(assumeAllRequired).build(config)
}

// $COVERAGE-OFF$
Expand Down
17 changes: 9 additions & 8 deletions src/main/scala/tscfg/gen4tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,11 @@ object gen4tests {
}

private def generate(confFile: File): Unit = {
println(s"gen4tests: confFile=$confFile")
val source = io.Source.fromFile(confFile).mkString.trim
val buildResult = ModelBuilder(source)
val objectType = buildResult.objectType

val baseGenOpts = GenOpts("tscfg.example", "?", j7 = false)

def updatedGenOpts(className: String): GenOpts = {
var genOpts = baseGenOpts.copy(className = className)
val baseGenOpts: GenOpts = {
var genOpts = GenOpts("tscfg.example", "?")
val opts = {
val linePat = """\s*//\s*GenOpts:(.*)""".r
source.split("\n")
Expand All @@ -34,6 +31,7 @@ object gen4tests {
case "--java:getters" genOpts = genOpts.copy(genGetters = true)
case "--java:optionals" genOpts = genOpts.copy(useOptionals = true)
case "--durations" genOpts = genOpts.copy(useDurations = true)
case "--all-required" genOpts = genOpts.copy(assumeAllRequired = true)

// $COVERAGE-OFF$
case opt println(s"WARN: $confFile: unrecognized GenOpts argument: `$opt'")
Expand All @@ -42,6 +40,9 @@ object gen4tests {
genOpts
}

val buildResult = ModelBuilder(source, assumeAllRequired = baseGenOpts.assumeAllRequired)
val objectType = buildResult.objectType

val name = confFile.getName
val (base, _) = name.span(_ != '.')
val classNameSuffix = util.upperFirst(base.replace('-', '_')) + "Cfg"
Expand All @@ -55,8 +56,8 @@ object gen4tests {
val fileName = className + "." + lang.toLowerCase
val targetFile = new File(targetScalaDir, fileName)
// $COVERAGE-OFF$
if (confFile.lastModified >= targetFile.lastModified) {
val genOpts = updatedGenOpts(className)
if (true || confFile.lastModified >= targetFile.lastModified) {
val genOpts = baseGenOpts.copy(className = className)
println(s"generating for $name -> $fileName")
val generator: Generator = lang match {
case "Scala" new ScalaGen(genOpts)
Expand Down
7 changes: 2 additions & 5 deletions src/main/scala/tscfg/generators/Generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,11 @@ abstract class Generator(genOpts: GenOpts) {

/**
* Generation options
*
* @param packageName package name
* @param className class name
* @param j7 true to generate code for Typesafe Config v &lt;= 1.2.1
*/
case class GenOpts(packageName: String,
className: String,
j7: Boolean,
assumeAllRequired: Boolean = false,
j7: Boolean = false,
reportFullPath: Boolean = false,
useBackticks: Boolean = false,
genGetters: Boolean = false,
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/tscfg/generators/JavaGenMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ object JavaGenMain {
println(model.util.format(objectType))

val className = "JCfg"
val genOpts = GenOpts("tscfg.example", className, j7 = false)
val genOpts = GenOpts("tscfg.example", className)
val gen = new JavaGen(genOpts)
val res = gen.generate(objectType)
println(s"classNames: ${res.classNames}")
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/tscfg/generators/ScalaGenMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ object ScalaGenMain {
println(model.util.format(objectType))

val className = "Cfg"
val genOpts = GenOpts("tscfg.example", className, j7 = false)
val genOpts = GenOpts("tscfg.example", className)
val gen = new ScalaGen(genOpts)
val res = gen.generate(objectType)
println(s"classNames: ${res.classNames}")
Expand Down
11 changes: 9 additions & 2 deletions src/main/scala/tscfg/generators/java/JavaGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ class JavaGen(genOpts: GenOpts) extends Generator(genOpts) {

private def objectInstance(a: AnnType, res: Res, path: String): String = {
val className = res.javaType.toString

if (genOpts.assumeAllRequired)
s"""new $className(c.getConfig("$path"))"""
else
if (a.optional) {
if (genOpts.useOptionals) {
s"""c.$hasPath("$path") ? java.util.Optional.of(new $className(c.getConfig("$path"))) : java.util.Optional.empty()"""
Expand Down Expand Up @@ -329,6 +333,8 @@ object JavaGen {

// $COVERAGE-OFF$
def generate(filename: String, showOut: Boolean = false,
j7: Boolean = false,
assumeAllRequired: Boolean = false,
genGetters: Boolean = false, useOptionals:Boolean = false,
useDurations:Boolean = false): GenResult = {
val file = new File("src/main/tscfg/" + filename)
Expand All @@ -344,7 +350,7 @@ object JavaGen {
util.upperFirst(symbol) + "Cfg"
}

val buildResult = ModelBuilder(source)
val buildResult = ModelBuilder(source, assumeAllRequired = assumeAllRequired)
val objectType = buildResult.objectType
if (showOut) {
println("\nobjectType:\n |" + model.util.format(objectType).replaceAll("\n", "\n |"))
Expand All @@ -354,8 +360,9 @@ object JavaGen {
}
}

val genOpts = GenOpts("tscfg.example", className, j7 = false,
val genOpts = GenOpts("tscfg.example", className, j7 = j7,
genGetters = genGetters, useOptionals = useOptionals,
assumeAllRequired = assumeAllRequired,
useDurations = useDurations)

val generator = new JavaGen(genOpts)
Expand Down
12 changes: 9 additions & 3 deletions src/main/scala/tscfg/generators/scala/ScalaGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ object ScalaGen {

// $COVERAGE-OFF$
def generate(filename: String,
j7: Boolean = false,
assumeAllRequired: Boolean = false,
showOut: Boolean = false,
useBackticks: Boolean = false
): GenResult = {
Expand All @@ -180,7 +182,7 @@ object ScalaGen {
util.upperFirst(symbol) + "Cfg"
}

val buildResult = ModelBuilder(source)
val buildResult = ModelBuilder(source, assumeAllRequired = assumeAllRequired)
val objectType = buildResult.objectType
if (showOut) {
println("\nobjectType:\n |" + model.util.format(objectType).replaceAll("\n", "\n |"))
Expand All @@ -190,7 +192,7 @@ object ScalaGen {
}
}

val genOpts = GenOpts("tscfg.example", className, j7 = false,
val genOpts = GenOpts("tscfg.example", className, j7 = j7,
useBackticks = useBackticks)

val generator = new ScalaGen(genOpts)
Expand Down Expand Up @@ -347,7 +349,11 @@ private[scala] case class Getter(genOpts: GenOpts, hasPath: String, accessors: A
}
else {
val ppArg = if (genOpts.reportFullPath) s""", s"$${parentPath}$path."""" else ""
s"""$className(if(c.$hasPath("$path")) c.getConfig("$path") else com.typesafe.config.ConfigFactory.parseString("$path{}")$ppArg)"""

if (genOpts.assumeAllRequired)
s"""$className(c.getConfig("$path")$ppArg)"""
else
s"""$className(if(c.$hasPath("$path")) c.getConfig("$path") else com.typesafe.config.ConfigFactory.parseString("$path{}")$ppArg)"""
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/main/tscfg/example/issue47.spec.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// GenOpts: --all-required
service {
url = "http://example.net/rest"
poolSize = 32
debug = true
doLog = false
factor = 0.75
}
Loading

0 comments on commit 4204db6

Please sign in to comment.