confide (empty) → 0.1.0.0
raw patch · 7 files changed
+244/−0 lines, 7 filesdep +basedep +confidedep +deiko-configsetup-changed
Dependencies added: base, confide, deiko-config, exceptions, tasty, tasty-hunit, text
Files
- LICENSE +30/−0
- README.md +54/−0
- Setup.hs +2/−0
- confide.cabal +60/−0
- src/Data/Confide.hs +11/−0
- src/Data/Confide/Generic.hs +53/−0
- test/Test.hs +34/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Author name here (c) 2017++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Author name here nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,54 @@+# confide++[](https://travis-ci.org/amilkov3/confide)++[Confide](https://github.com/estatico/confide) port to Haskell (using `GHC.Generics` as opposed to Shapeless to generate +[FromConf](https://github.com/estatico/confide/blob/master/core/src/main/scala/io/estatico/confide/FromConf.scala) typeclass instances). Uses [deiko-config](https://hackage.haskell.org/package/deiko-config) to parse HOCON .conf file and read in types++## Usage++HOCON `.conf` file+```+a="hello"++b {+ y=true+ z {+ x=5+ }+}+```++```haskell++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}++module Test where++import Data.Confide+import Data.Confide.Generic+import qualified Data.Text as T++data Foo = Foo {x :: Integer} deriving (Generic, Show)+data Bar = Bar {y :: Bool, z :: Foo} deriving (Generic, Show)+data Baz = Baz {a :: T.Text, b :: Bar} deriving (Generic, Show)++instance FromConf Foo+instance FromConf Bar+instance FromConf Baz++main :: IO ()+main = do+ c <- loadConfig "project/path/to/confFile.conf"+ baz <- get @Baz "" c+ print baz++```++GHCI++```+$ main +Baz {a = "hello", b = Bar {y = True, z = Foo {x = 5}}}+```
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ confide.cabal view
@@ -0,0 +1,60 @@+-- This file has been generated from package.yaml by hpack version 0.20.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 6584c5878c7ff185a3a904a7924e5f3f5c0f1afb654c22dbe04eb9a545ca888d++name: confide+version: 0.1.0.0+synopsis: derive typeclass instances for decoding types from HOCON conf+category: Data+homepage: https://github.com/amilkov3/confide+bug-reports: https://github.com/amilkov3/confide/issues+author: Alex Milkov+maintainer: amilkov3@gmail.com+copyright: 2018 Alex Milkov+license: BSD3+license-file: LICENSE+build-type: Simple+cabal-version: >= 1.10++extra-source-files:+ README.md++source-repository head+ type: git+ location: https://github.com/amilkov3/confide++library+ hs-source-dirs:+ src+ default-extensions: DefaultSignatures DeriveGeneric FlexibleInstances FlexibleContexts MultiParamTypeClasses OverloadedStrings PolyKinds ScopedTypeVariables TypeOperators+ build-depends:+ base >=4.7 && <5+ , deiko-config >=0.5.0.1+ , exceptions ==0.8.3+ , text ==1.2.2.2+ exposed-modules:+ Data.Confide+ Data.Confide.Generic+ other-modules:+ Paths_confide+ default-language: Haskell2010++test-suite confide-test+ type: exitcode-stdio-1.0+ main-is: Test.hs+ hs-source-dirs:+ test+ default-extensions: DefaultSignatures DeriveGeneric FlexibleInstances FlexibleContexts MultiParamTypeClasses OverloadedStrings PolyKinds ScopedTypeVariables TypeOperators+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ base+ , confide+ , deiko-config+ , tasty+ , tasty-hunit+ , text+ other-modules:+ Paths_confide+ default-language: Haskell2010
+ src/Data/Confide.hs view
@@ -0,0 +1,11 @@++module Data.Confide ( loadConfig ) where++import qualified Data.Config as C+import Data.Text+import Control.Monad.Catch+import Control.Monad.IO.Class++-- | Re-export of `deiko-config`'s `Data.Config#loadConfig`+loadConfig :: (MonadIO m, MonadThrow m) => String -> m C.Config+loadConfig = C.loadConfig
+ src/Data/Confide/Generic.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE UndecidableInstances #-}++module Data.Confide.Generic( FromConf(..) ) where++import qualified Data.Text as T+import GHC.Generics+import Data.Config+import Data.Proxy+import System.IO.Unsafe+import Control.Monad.Catch (MonadThrow)++class FromConf a where+ -- | Decode an `a` from a `Config` given a `Text` path to its HOCON .conf object+ get :: MonadThrow m => T.Text -> Config -> m a++ -- | By default, convert to an `a` from its generic repr+ default get :: (Generic a, GFromConf (Rep a), MonadThrow m) => T.Text -> Config -> m a+ get p c = fmap to (gget p c)++instance FromConf T.Text where+ get = getString++instance FromConf Bool where+ get = getBool++instance FromConf Integer where+ get = getInteger++class GFromConf rep where+ gget :: MonadThrow m => T.Text -> Config -> m (rep a)++instance GFromConf U1 where+ gget _ _ = return U1++instance (GFromConf a, GFromConf b) => GFromConf (a :*: b) where+ gget p c = do+ x <- gget p c+ y <- gget p c+ return (x :*: y)++instance GFromConf a => GFromConf (M1 D x a) where+ gget p c = fmap M1 (gget p c)++instance GFromConf a => GFromConf (M1 C x a) where+ gget p c = fmap M1 (gget p c)++instance (GFromConf a, Selector s) => GFromConf (M1 S s a) where+ gget p c = fmap M1 (gget (p' `T.append` T.pack (selName (undefined :: M1 S s a ()))) c)+ where p' = if T.null p then p else p `T.append` "."++instance (FromConf a) => GFromConf (K1 R a) where+ gget p c = fmap K1 (get p c)+
+ test/Test.hs view
@@ -0,0 +1,34 @@++{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE OverloadedStrings #-}++import Test.Tasty+import Test.Tasty.HUnit+import Data.Confide.Generic+import Data.Confide+import System.IO.Unsafe+import GHC.Generics+import Data.Text as T++main = defaultMain tests++tests :: TestTree+tests = testGroup "Tests" [unitTests]++data Foo = Foo {x :: Integer} deriving (Generic, Show, Eq)+data Bar = Bar {y :: Bool, z :: Foo} deriving (Generic, Show, Eq)+data Baz = Baz {a :: T.Text, b :: Bar} deriving (Generic, Show, Eq)++instance FromConf Foo+instance FromConf Bar+instance FromConf Baz++myBaz = Baz "hello" (Bar True (Foo 5))++unitTests = testGroup "Unit tests"+ [ testCase "Load in type from conf" $ do+ c <- loadConfig "test/test.conf"+ baz <- get @Baz "" c+ assertEqual "test" baz myBaz+ ]