bookkeeper 0.1.0.0 → 0.1.1.0
raw patch · 5 files changed
+52/−21 lines, 5 files
Files
- bookkeeper.cabal +1/−1
- src/Bookkeeper.hs +8/−0
- src/Bookkeeper/Internal.hs +20/−0
- test/BookkeeperSpec.hs +18/−18
- test/Readme.lhs +5/−2
bookkeeper.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack name: bookkeeper-version: 0.1.0.0+version: 0.1.1.0 description: Please see README.md homepage: http://github.com/turingjump/bookkeeper#readme bug-reports: https://github.com/turingjump/bookkeeper/issues
src/Bookkeeper.hs view
@@ -8,12 +8,17 @@ -- >>> let julian :: Person = emptyBook & #age =: 28 & #name =: "Julian K. Arni" -- -- The OverloadedLabels and TypeOperators extensions are also required.+--+-- A word of warning: The signatures for most of the functions are quite+-- arcane, even though their behaviour is intuitive. -- * Initialization emptyBook+ -- * Getters , (?:) , get+ -- * Setters , set , (=:)@@ -21,6 +26,9 @@ -- * Modifying , modify , (%:)++ -- * Deleting+ , delete -- * Types , Book
src/Bookkeeper/Internal.hs view
@@ -66,6 +66,7 @@ (?:) :: forall field book val. (Map.Submap '[field :=> val] book, Contains book field val ) => Book' book -> Key field -> val (?:) = flip get+infixl 3 ?: -- | Sets or updates a field to a value. --@@ -104,6 +105,7 @@ ) => Key field -> val -> Book' old -> Book' new (=:) = set+infix 3 =: -- | Apply a function to a field.@@ -151,6 +153,24 @@ , Map.AsMap new ~ new ) => Key field -> (val -> val') -> Book' old -> Book new (%:) = modify+infixr 3 %:+++-- | Delete a field from a 'Book', if it exists. If it does not, returns the+-- @Book@ unmodified.+--+-- >>> get #name $ delete #name julian+-- ...+-- ... • The provided Book does not contain the field "name"+-- ... Book type:+-- ... '["age" ':-> Int]+-- ... • In the expression: get #name+-- ...+delete :: forall field old .+ ( Map.Submap (Map.AsMap (old Map.:\ field)) old+ ) => Key field -> Book' old -> Book (old Map.:\ field)+delete _ (Book bk) = Book $ Map.submap bk+ -- * Mapping
test/BookkeeperSpec.hs view
@@ -7,12 +7,12 @@ spec :: Spec spec = describe "books" $ do+ let p :: Person+ = emptyBook+ & #name =: "Julian K. Arni"+ & #age =: 28 it "allows creation" $ do- let _p :: Person- = emptyBook- & #name =: "Julian K. Arni"- & #age =: 28 typeLevelTest it "allows creation out of order" $ do@@ -23,29 +23,29 @@ typeLevelTest it "allows access" $ do- let p :: Person- = emptyBook- & #name =: "Julian K. Arni"- & #age =: 28 get #name p `shouldBe` "Julian K. Arni" it "allows update" $ do- let p :: Person- = emptyBook- & #name =: "Julian K. Arni"- & #age =: 28- & #name %: fmap toUpper- get #name p `shouldBe` "JULIAN K. ARNI"+ let p' :: Person+ = p & #name %: fmap toUpper+ get #name p' `shouldBe` "JULIAN K. ARNI" it "allows extension" $ do- let p :: Person- = emptyBook- & #name =: "Julian K. Arni"- & #age =: 28 let p' = #email =: "jkarni<at>turingjump<dot>com" $ p get #email p' `shouldBe` ("jkarni<at>turingjump<dot>com" :: String) + it "allows deleting" $ do+ let _p = delete #name p+ typeLevelTest++ it "allows nested updates" $ do+ let timeTravelingJulian = p & #child =: p+ p' = timeTravelingJulian & #child %: #name %: fmap toUpper+ p' ?: #name `shouldBe` "Julian K. Arni"+ p' ?: #child ?: #name `shouldBe` "JULIAN K. ARNI"+ type Person = Book '[ "name" :=> String , "age" :=> Int]+ typeLevelTest :: Expectation typeLevelTest = True `shouldBe` True
test/Readme.lhs view
@@ -18,6 +18,9 @@ -- "Jane" ~~~ +It bears some similarities to Nikita Volkov's [record](https://nikita-volkov.github.io/record/)+library, but requires no Template Haskell.+ Accesing a field that does not exist is a type error, made nicer with GHCs new custom type errors: @@ -32,10 +35,10 @@ The order in which fields are inserted or appear in types does not matter. That is, in: -~~ {.haskell ignore}+~~~ {.haskell} -- type A = Book '[ "field1" :=> Int, "field2" :=> Bool] -- type B = Book '[ "field2" :=> Bool "field1" :=> Int ]-~~+~~~ Types `A` and `B` are the same.