diff --git a/README.md b/README.md index 17a0b98..82fa320 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Latest release](http://img.shields.io/github/release/purescript/purescript-foreign-object.svg)](https://github.com/purescript/purescript-foreign-object/releases) [![Build status](https://travis-ci.org/purescript/purescript-foreign-object.svg?branch=master)](https://travis-ci.org/purescript/purescript-foreign-object) -Functions for working with homogeneous JavaScript objects from PureScript. +Functions for working with homogeneous JavaScript objects from PureScript. Similar to using `Map String a` but simply reusing JavaScript objects. ## Installation @@ -11,6 +11,43 @@ Functions for working with homogeneous JavaScript objects from PureScript. bower install purescript-foreign-object ``` +## Example + +```purs +example = do + let + -- make an empty Object + empty = FO.empty + + -- insert to an empty Object + inserted = FO.insert "a" 1 empty + + -- or: use the singleton function + -- singleton FO.singleton "a" 1 + + -- lookup values for existing in the Object as a result of Maybe + let lookup = FO.lookup "a" inserted + Assert.assertEqual { actual: lookup, expected: Just 1 } + + -- delete a value from an Object + let deleted = FO.delete "a" inserted + Assert.assertEqual { actual: deleted, expected: FO.empty } + + let + -- convert homogeneous records to Object + converted = FO.fromHomogeneous { a: 1, b: 2, c: 3} + -- check that the converted is equal to a regularly built Object + built + = FO.empty + # FO.insert "a" 1 + # FO.insert "b" 2 + # FO.insert "c" 3 + + Assert.assertEqual { actual: converted, expected: built } +``` + +See the [tests](test/Main.purs) for more examples. + ## Documentation Module documentation is [published on Pursuit](http://pursuit.purescript.org/packages/purescript-foreign-object). diff --git a/bower.json b/bower.json index 2937586..bceae05 100644 --- a/bower.json +++ b/bower.json @@ -23,17 +23,19 @@ "purescript-arrays": "^5.0.0", "purescript-foldable-traversable": "^4.0.0", "purescript-functions": "^4.0.0", - "purescript-gen": "^2.0.0", + "purescript-gen": "^2.1.0", "purescript-lists": "^5.0.0", "purescript-maybe": "^4.0.0", - "purescript-prelude": "^4.0.0", + "purescript-prelude": "^4.1.0", "purescript-st": "^4.0.0", "purescript-tailrec": "^4.0.0", "purescript-tuples": "^5.0.0", - "purescript-unfoldable": "^4.0.0" + "purescript-unfoldable": "^4.0.0", + "purescript-typelevel-prelude": "^3.0.0" }, "devDependencies": { "purescript-quickcheck": "^5.0.0", - "purescript-minibench": "^2.0.0" + "purescript-minibench": "^2.0.0", + "purescript-assert": "^4.0.0" } } diff --git a/src/Foreign/Object.purs b/src/Foreign/Object.purs index 00a696f..0776a64 100644 --- a/src/Foreign/Object.purs +++ b/src/Foreign/Object.purs @@ -15,6 +15,7 @@ module Foreign.Object , toAscUnfoldable , fromFoldable , fromFoldableWith + , fromHomogeneous , delete , pop , member @@ -56,6 +57,8 @@ import Data.Tuple (Tuple(..), fst, uncurry) import Data.Unfoldable (class Unfoldable) import Foreign.Object.ST (STObject) import Foreign.Object.ST as OST +import Type.Row.Homogeneous (class Homogeneous) +import Unsafe.Coerce (unsafeCoerce) -- | `Object a` represents a homogeneous JS Object with values of type `a`. foreign import data Object :: Type -> Type @@ -170,7 +173,7 @@ isEmpty = all (\_ _ -> false) -- | Calculate the number of key/value pairs in a map foreign import size :: forall a. Object a -> Int --- | Create a map with one key/value pair +-- | Create an `Object a` with one key/value pair singleton :: forall a. String -> a -> Object a singleton k v = runST (OST.poke k v =<< OST.new) @@ -209,7 +212,7 @@ alter f k m = case f (k `lookup` m) of update :: forall a. (a -> Maybe a) -> String -> Object a -> Object a update f k m = alter (maybe Nothing f) k m --- | Create a map from a foldable collection of key/value pairs +-- | Create an `Object a` from a foldable collection of key/value pairs fromFoldable :: forall f a. Foldable f => f (Tuple String a) -> Object a fromFoldable l = runST do s <- OST.new @@ -218,7 +221,7 @@ fromFoldable l = runST do foreign import _lookupST :: forall a r z. Fn4 z (a -> z) String (STObject r a) (ST r z) --- | Create a map from a foldable collection of key/value pairs, using the +-- | Create an `Object a` from a foldable collection of key/value pairs, using the -- | specified function to combine values for duplicate keys. fromFoldableWith :: forall f a. Foldable f => (a -> a -> a) -> f (Tuple String a) -> Object a fromFoldableWith f l = runST (do @@ -226,6 +229,11 @@ fromFoldableWith f l = runST (do for_ l (\(Tuple k v) -> runFn4 _lookupST v (f v) k s >>= \v' -> OST.poke k v' s) pure s) +-- | Create an `Object a` from a homogeneous record, i.e. all of the record +-- | fields are of the same type. +fromHomogeneous :: forall r a. Homogeneous r a => { | r } -> Object a +fromHomogeneous = unsafeCoerce + foreign import toArrayWithKey :: forall a b . (String -> a -> b) -> Object a -> Array b -- | Unfolds a map into a list of key/value pairs diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 6dc7d42..0b9edd7 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -2,11 +2,47 @@ module Test.Main where import Prelude +import Data.Maybe (Maybe(..)) import Effect (Effect) import Effect.Console (log) +import Foreign.Object as FO +import Test.Assert as Assert import Test.Foreign.Object (objectTests) +example :: Effect Unit +example = do + let + -- make an empty Object + empty = FO.empty + + -- insert to an empty Object + inserted = FO.insert "a" 1 empty + + -- or: use the singleton function + -- singleton FO.singleton "a" 1 + + -- lookup values for existing in the Object as a result of Maybe + let lookup = FO.lookup "a" inserted + Assert.assertEqual { actual: lookup, expected: Just 1 } + + -- delete a value from an Object + let deleted = FO.delete "a" inserted + Assert.assertEqual { actual: deleted, expected: FO.empty } + + let + -- convert homogeneous records to Object + converted = FO.fromHomogeneous { a: 1, b: 2, c: 3} + -- check that the converted is equal to a regularly built Object + built + = FO.empty + # FO.insert "a" 1 + # FO.insert "b" 2 + # FO.insert "c" 3 + + Assert.assertEqual { actual: converted, expected: built } + main :: Effect Unit main = do log "Running StrMap tests" + example objectTests