Coder Social home page Coder Social logo

47degrees / case-classy Goto Github PK

View Code? Open in Web Editor NEW
68.0 68.0 8.0 2.16 MB

configuration with less hassle

Home Page: http://47deg.github.io/case-classy/

License: Apache License 2.0

Scala 99.89% CSS 0.11%
configuration functional-programming scala scalajs

case-classy's People

Contributors

47degdev avatar anamariamv avatar andyscott avatar diesalbla avatar eddsteel avatar franciscodr avatar juanpedromoreno avatar maureenelsberry avatar peterneyens avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

case-classy's Issues

error: could not find implicit value for parameter ev: classy.generic.derive.MkDecoder[com.typesafe.config.Config, MyConfig]

I've got a simple example project and test that may highlight the problem I'm having in my application code.

Here is the test from a simple example:

package classy

import classy.Fruits.{Apple, FruityConfig}
import org.scalatest.{FlatSpec, Matchers}
import com.typesafe.config.ConfigFactory
import classy.config._
import classy.generic.auto._
import classy.core.DecodeError

class FruitsSpec extends FlatSpec with Matchers {

  "A properly decoded config" should "contain two fruits" in {
    val rawConfig = ConfigFactory load
    val decoder = ConfigDecoder[FruityConfig]
    val result0: Either[DecodeError, FruityConfig] = decoder.decode(rawConfig)
    result0.isRight shouldBe true
    result0.right.get.fruits should have size 2

    val apple = result0.right.get.fruits.head.asInstanceOf[Apple]

    apple.location.city shouldBe "cadiz"
  }
}

This executes correctly, but ensime detects a missing implicit value ev: ConfigDecoder.

In my application code I have nearly the opposite problem- my ide does not detect a problem, but there is a compiler error indicating a missing implicit value ev: MkDecoder.

Can someone explain how I the MkDecoder is intended to be imported? I've tried a number of different imports but am still getting a compiler error.

My assumption from the examples is that import classy.generic._ should import an implicit MkDecoder.

However, previously there was an example that used import classy.generic.auto._ which is what I used in my example above.

Referring to non-existent method classy.generic.derive.MkDecoder$.mkDecoderHList

with following dependencies,

name := "upd-frontend"

enablePlugins(ScalaJSPlugin)

version := "0.1"

scalaVersion := "2.12.6"

scalaJSUseMainModuleInitializer := true

libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "0.9.5"

libraryDependencies += "org.querki" %%% "jquery-facade" % "1.2"

// required
libraryDependencies += "com.47deg" %% "classy-core"            % "0.4.0"

// at least one required
libraryDependencies += "com.47deg" %% "classy-config-typesafe" % "0.4.0"
libraryDependencies += "com.47deg" %% "classy-config-shocon"   % "0.4.0"

libraryDependencies += "com.47deg" %% "classy-generic"         % "0.4.0"

libraryDependencies ++= Seq("com.chuusai" %% "shapeless" % "2.3.3")

I could not compile to JS

    import classy.generic._
    import classy.config._

    case class Env(uri: String, heartbeatResource: String, handoffResource: String)
    case class ApplicationConfig(dev: Env)

    import com.typesafe.config.Config
    val decoder1 = deriveDecoder[Config, ApplicationConfig]

    val config: Either[DecodeError, ApplicationConfig] = decoder1.fromString("""{
                          |  dev {
                          |      uri = "uri"
                          |      heartbeatResource = hb""
                          |      handoffResource = "hr"
                          |  }
                          |}
                          |""")

The stack-trace is

[error] Referring to non-existent method classy.generic.derive.MkRead$.mkReadNested(classy.Read,shapeless.Lazy)classy.generic.derive.MkRead
[error]   called from UpdFrontend$anon$mkDecoderGeneric$macro$22$1.inst$macro$7$lzycompute()classy.generic.derive.MkRead
[error]   called from UpdFrontend$anon$mkDecoderGeneric$macro$22$1.inst$macro$7()classy.generic.derive.MkRead
[error]   called from UpdFrontend$anon$mkDecoderGeneric$macro$22$1.$$anonfun$inst$macro$5$1()classy.generic.derive.MkRead
[error]   called from UpdFrontend$anon$mkDecoderGeneric$macro$22$1.inst$macro$5$lzycompute()classy.generic.derive.MkDecoder
[error]   called from UpdFrontend$anon$mkDecoderGeneric$macro$22$1.inst$macro$5()classy.generic.derive.MkDecoder
[error]   called from UpdFrontend$.main([java.lang.String)scala.Unit
[error]   called from core module module initializers
[error] involving instantiated classes:
[error]   UpdFrontend$anon$mkDecoderGeneric$macro$22$1
[error]   UpdFrontend$
[error] Referring to non-existent method classy.generic.package$.deriveDecoder(classy.generic.derive.MkDecoder)classy.Decoder
[error]   called from UpdFrontend$.main([java.lang.String)scala.Unit
[error]   called from core module module initializers
[error] involving instantiated classes:
[error]   UpdFrontend$
[error] org.scalajs.core.tools.linker.LinkingException: There were linking errors
[error] 	at org.scalajs.core.tools.linker.frontend.BaseLinker.linkInternal(BaseLinker.scala:160)
[error] 	at org.scalajs.core.tools.linker.frontend.BaseLinker.linkInternal(BaseLinker.scala:108)
[error] 	at org.scalajs.core.tools.linker.frontend.LinkerFrontend.$anonfun$link$3(LinkerFrontend.scala:63)
[error] 	at org.scalajs.core.tools.logging.Logger.time(Logger.scala:28)
[error] 	at org.scalajs.core.tools.logging.Logger.time$(Logger.scala:26)
[error] 	at org.scalajs.sbtplugin.Loggers$SbtLoggerWrapper.time(Loggers.scala:7)
[error] 	at org.scalajs.core.tools.linker.frontend.LinkerFrontend.link(LinkerFrontend.scala:62)
[error] 	at org.scalajs.core.tools.linker.Linker.$anonfun$link$1(Linker.scala:52)
[error] 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error] 	at org.scalajs.core.tools.linker.Linker.guard(Linker.scala:69)
[error] 	at org.scalajs.core.tools.linker.Linker.link(Linker.scala:50)
[error] 	at org.scalajs.core.tools.linker.ClearableLinker.$anonfun$link$1(ClearableLinker.scala:52)
[error] 	at org.scalajs.core.tools.linker.ClearableLinker.$anonfun$link$1$adapted(ClearableLinker.scala:52)
[error] 	at org.scalajs.core.tools.linker.ClearableLinker.linkerOp(ClearableLinker.scala:63)
[error] 	at org.scalajs.core.tools.linker.ClearableLinker.link(ClearableLinker.scala:52)
[error] 	at org.scalajs.sbtplugin.ScalaJSPluginInternal$.$anonfun$scalaJSStageSettings$11(ScalaJSPluginInternal.scala:315)
[error] 	at sbt.util.FileFunction$.$anonfun$cached$1(FileFunction.scala:73)
[error] 	at sbt.util.FileFunction$.$anonfun$cached$4(FileFunction.scala:147)
[error] 	at sbt.util.Difference.apply(Tracked.scala:313)
[error] 	at sbt.util.Difference.apply(Tracked.scala:293)
[error] 	at sbt.util.FileFunction$.$anonfun$cached$3(FileFunction.scala:143)
[error] 	at sbt.util.Difference.apply(Tracked.scala:313)
[error] 	at sbt.util.Difference.apply(Tracked.scala:288)
[error] 	at sbt.util.FileFunction$.$anonfun$cached$2(FileFunction.scala:142)
[error] 	at org.scalajs.sbtplugin.ScalaJSPluginInternal$.$anonfun$scalaJSStageSettings$10(ScalaJSPluginInternal.scala:320)
[error] 	at sbt.std.Transform$$anon$3.$anonfun$apply$2(System.scala:44)
[error] 	at sbt.std.Transform$$anon$4.work(System.scala:64)
[error] 	at sbt.Execute.$anonfun$submit$2(Execute.scala:257)
[error] 	at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
[error] 	at sbt.Execute.work(Execute.scala:266)
[error] 	at sbt.Execute.$anonfun$submit$1(Execute.scala:257)
[error] 	at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:167)
[error] 	at sbt.CompletionService$$anon$2.call(CompletionService.scala:32)
[error] 	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error] 	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[error] 	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error] 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[error] 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[error] 	at java.lang.Thread.run(Thread.java:748)
[error] (compile:fastOptJS) org.scalajs.core.tools.linker.LinkingException: There were linking errors
[error] Total time: 22 s, completed Jul 13, 2018 12:04:19 PM

Improve toString of various error types

Improve toString of RootDecodeError and friends so that errors logged to stdout are more readable. For example:

Oh no!: Left(classy.package$RootDecodeError)

is not particularly useful.

Support for Recursive ADTs?

This may be impossible with the current approach to automatically deriving decoders, but I have a situation like this:

import classy._
import clasy.config._
import classy.generic._
import com.typesafe.config._

object Models{
  sealed trait TopLevel
  case class A(b: TopLevel) extends TopLevel
  case class B(c: String) extends TopLevel
  val topLevelDecoder = deriveDecoder[Config, TopLevel]
}

This doesn't compile... near as I can tell due to Stack Overflow during the macro (?) expansion... In the REPL you get something like:

java.lang.StackOverflowError
  at classy.generic.derive.MkReadInstances0$$anonfun$mkReadNested$1.apply(MkDecoder.scala:162)
  at classy.generic.derive.MkRead.apply(MkDecoder.scala:151)
  at classy.generic.derive.MkDecoderInstances0$$anonfun$mkDecoderHListDerived$1.apply(MkDecoder.scala:129)
  at classy.generic.derive.MkDecoderInstances0$$anonfun$mkDecoderHListDerived$1.apply(MkDecoder.scala:128)
  at classy.generic.derive.MkDecoder.decoder(MkDecoder.scala:30)
  at classy.generic.derive.MkDecoderInstances2$$anonfun$mkDecoderGeneric$1.apply(MkDecoder.scala:80)
  at classy.generic.derive.MkDecoderInstances2$$anonfun$mkDecoderGeneric$1.apply(MkDecoder.scala:80)
  at classy.generic.derive.MkDecoder.decoder(MkDecoder.scala:30)
  at classy.generic.derive.MkDecoderInstances0$$anonfun$mkDecoderCoproductDerived$1.apply(MkDecoder.scala:144)
  at classy.generic.derive.MkDecoderInstances0$$anonfun$mkDecoderCoproductDerived$1.apply(MkDecoder.scala:143)
  at classy.generic.derive.MkDecoder.decoder(MkDecoder.scala:30)
...

For expressing complex domain models and being able to readily marshal them to and from config it would be really nice to have support for this. I'm not entirely sure how libraries like Play JSON achieve recursive structure support, but it would be really great if Case Classy could also support it as well.

I'm not terribly experienced with Scala metaprogramming, but if someone can point me in the right direction I'm happy to help try to find a solution for this... just not quite sure where to start...

P.S.: Thank you for Case Classy - it's generally quite awesome :-)

Add built in support for decoding system env/props

This functionality exists, but it's currently only in the code for the ScalaDays slides. I'll be pulling it out and turning it into a full blown implementation so that the core module has basic decoding of Map[String, String].

Decoder creation from Try

It would be useful to be able to create decoders directly from A => Try[B]. The error can be directly turned into the underlying error wrapper.

For example, for monix-kafka:

implicit val decodeKafkaProducerConfig: ConfigDecoder[KafkaProducerConfig] =
    Decoder.instance(c => Try(KafkaProducerConfig(c)).toEither.leftMap(DecodeError.Underlying(_)))  

this ideally could just be written as:

implicit val decodeKafkaProducerConfig: ConfigDecoder[KafkaProducerConfig] =
    Decoder.instance(c => Try(KafkaProducerConfig(c)))

Automatically deriving decoders for enums

I have the following hierarchy:

sealed trait SomeType
case object Type1 extends SomeType
case object Type2 extends SomeType

case class MyConfig(t: SomeType)

and the following config:

t: type1

I know it's possible with a manual decoder but I wonder if wouldn't be possible with automatically derived decoders?

Support for optional ADT

If we go back to the example in the readme, I'd like to be able to do:

import classy.generic._
import classy.config._

sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(length: Double, width: Double) extends Shape

case class MyConfig(
  someString: String,
  shape: Option[Shape])

import com.typesafe.config.Config
val decoder1 = deriveDecoder[Config, MyConfig]

decoder1.fromString("""someString = hello""")

Documentation Review

Hoping to get a review of the documentation, in particular everything included on the microsite. Feedback on language and technical content welcomed.

Logo design

@jorgegalindocruces
I'm gearing up for an official release with PR #11. It would be really great to get a logo soon, since I writing some tutorials/documentation this weekend and I'd like to spin up a microsite.

Generic ADT Updates

  • support coproducts
  • support default values pulled from case class constructors

Add summoners to Read

The following should be added to the Read companion object:

def apply[A, B](implicit ev: Read[A, B]): Read[A, B] = ev
def apply[A, B](path: String)(implicit ev: Read[A, B]): Decoder[A, B] = ev(path)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.