diff --git a/README.md b/README.md
index 6bb8ef3..2c29a3e 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,7 @@ These are the functions under the `kudoJS.*` namespace
* [`kudoJS.compose`](docs/helper-functions.md#kudojscompose)
* [`kudoJS.constant`](docs/helper-functions.md#kudojsconstant)
* [`kudoJS.fmap`](docs/helper-functions.md#kudojsfmap)
+* [`kudoJS.assoc`](docs/helper-functions.md#kudojsassoc)
* [`kudoJS.bimap`](docs/helper-functions.md#kudojsbimap)
* [`kudoJS.chain`](docs/helper-functions.md#kudojschain)
* [`kudoJS.caseOf`](docs/helper-functions.md#kudojscaseof)
@@ -44,6 +45,7 @@ These are the functions under the `kudoJS.*` namespace
* [`kudoJS.liftA4`](docs/helper-functions.md#kudojslifta4)
* [`kudoJS.liftA5`](docs/helper-functions.md#kudojslifta5)
* [`kudoJS.when`](docs/helper-functions.md#kudojswhen)
+* [`kudoJS.pick`](docs/helper-functions.md#kudojspick)
* [`kudoJS.prop`](docs/helper-functions.md#kudojsprop)
* [`kudoJS.eitherToMaybe`](docs/helper-functions.md#kudojseithertomaybe)
* [`kudoJS.maybeToEither`](docs/helper-functions.md#kudojsmaybeToEither)
diff --git a/docs/helper-functions.md b/docs/helper-functions.md
index 701c23e..50136c2 100644
--- a/docs/helper-functions.md
+++ b/docs/helper-functions.md
@@ -9,6 +9,7 @@ These are the functions under the `kudoJS.*` namespace
- [`kudoJS.compose`](#kudojscompose)
- [`kudoJS.constant`](#kudojsconstant)
- [`kudoJS.fmap`](#kudojsfmap)
+ - [`kudoJS.assoc`](#kudojsassoc)
- [`kudoJS.bimap`](#kudojsbimap)
- [`kudoJS.chain`](#kudojschain)
- [`kudoJS.caseOf`](#kudojscaseof)
@@ -19,6 +20,7 @@ These are the functions under the `kudoJS.*` namespace
- [`kudoJS.liftA5`](#kudojslifta5)
- [`kudoJS.when`](#kudojswhen)
- [`kudoJS.prop`](#kudojsprop)
+ - [`kudoJS.pick`](#kudojspick)
- [`kudoJS.eitherToMaybe`](#kudojseithertomaybe)
- [`kudoJS.maybeToEither`](#kudojsmaybetoeither)
@@ -107,6 +109,22 @@ Takes a function and a functor, applies the function to each of the functor's va
----
+
+### `kudoJS.assoc`
+
+Associates a value to the specified key in the object. This returns a clone of the original object
+
+`assoc(key: string, value: A, o: {[k:string]: A}): {[k:string]: A}`
+
+
+| Param | Type | Description |
+| --- | --- | --- |
+| key | string
| Key |
+| value | function
| Value to be assigned to key in object |
+| o | Object
| Object to which value needs to be assigned against the Key |
+
+----
+
### `kudoJS.bimap`
Maps both sides of the disjunction
@@ -259,6 +277,19 @@ Returns a Maybe Just if value exists for the given key else returns a Nothing
----
+
+### `kudoJS.pick`
+Returns a Maybe Just containing the object with just the keys if values exists for the given keys else returns a Nothing
+
+`pick( keys: Array, o: { [k: string]: A}): Maybe<{[k:string]: A}>`
+
+| Param | Type | Description |
+| --- | --- | --- |
+| keys | Array
| Keys |
+| o | Object
| Key Value Object |
+
+----
+
### `kudoJS.eitherToMaybe`
Converts an Either type to a Maybe Type
diff --git a/src/adt/Maybe/index.ts b/src/adt/Maybe/index.ts
index 527bbb6..404f36a 100644
--- a/src/adt/Maybe/index.ts
+++ b/src/adt/Maybe/index.ts
@@ -196,5 +196,15 @@ const _prop = (
if (!o) return Maybe.Nothing();
return key in o ? Maybe.fromNullable(o[key]) : Maybe.Nothing();
};
-
export const prop = curry(_prop);
+
+function _pick(arr: Array, o: any) {
+ if (!o || arr.length <= 0) return Maybe.Nothing();
+ const v = arr.reduce((acc: any, key) => {
+ if (o[key]) acc[key] = o[key];
+ return acc;
+ }, {});
+
+ return Object.keys(v).length > 0 ? Maybe.Just(v) : Maybe.Nothing();
+}
+export const pick = curry(_pick);
diff --git a/src/adt/Maybe/maybe.test.ts b/src/adt/Maybe/maybe.test.ts
index b85ebb7..b0df8d5 100644
--- a/src/adt/Maybe/maybe.test.ts
+++ b/src/adt/Maybe/maybe.test.ts
@@ -4,7 +4,7 @@ import compose from "../../function/compose";
import fmap from "../../function/fmap";
import id from "../../function/id";
import Either from "../Either";
-import Maybe, { eitherToMaybe, prop } from ".";
+import Maybe, { eitherToMaybe, prop, pick } from ".";
// const laws: any = require("laws");
// console.log(laws);
@@ -216,5 +216,23 @@ test("Maybe", t => {
"prop returns a Nothing if value does not exists"
);
+ t.equals(
+ Maybe.isNothing(pick(["d"], undefined)),
+ true,
+ "should return 'Nothing' if object is undefined"
+ );
+
+ t.equals(
+ Maybe.isNothing(pick(["d"], {})),
+ true,
+ "should return 'Nothing' if object is does not have key"
+ );
+
+ t.equals(
+ pick(["d"], { d: 1 }).getValue().d,
+ 1,
+ "should return 'Just(value)' if object has key"
+ );
+
t.end();
});
diff --git a/src/function/assoc/assoc.test.ts b/src/function/assoc/assoc.test.ts
new file mode 100644
index 0000000..d97081f
--- /dev/null
+++ b/src/function/assoc/assoc.test.ts
@@ -0,0 +1,15 @@
+import * as test from "tape";
+import assoc from "./";
+
+test("assoc", t => {
+ t.throws(
+ () => assoc("d", 1, undefined),
+ "should throw error if object is undefined"
+ );
+
+ t.equals(assoc("d", 1, {}).d, 1, "should set the value to a key in object");
+
+ const o = {};
+ t.notEquals(assoc("d", 1, o), o, "should not mutate original object");
+ t.end();
+});
diff --git a/src/function/assoc/index.ts b/src/function/assoc/index.ts
new file mode 100644
index 0000000..61b3d80
--- /dev/null
+++ b/src/function/assoc/index.ts
@@ -0,0 +1,11 @@
+import curry from "../curry";
+import objectDeepClone from "../deepClone";
+
+function assoc(key: string, val: A, obj: any): any {
+ if (!obj || typeof obj !== "object")
+ throw new Error("assoc: expects an object");
+ const o = objectDeepClone(obj);
+ o[key] = val;
+ return o;
+}
+export default curry(assoc);
diff --git a/src/function/deepClone/deepClone.test.ts b/src/function/deepClone/deepClone.test.ts
new file mode 100644
index 0000000..48076a3
--- /dev/null
+++ b/src/function/deepClone/deepClone.test.ts
@@ -0,0 +1,16 @@
+import * as test from "tape";
+import deepClone from "./";
+
+test("deep clone", t => {
+ t.equals(deepClone(1), 1, "should return value if type is not object");
+ const o1 = { d: 1 };
+ t.notEquals(deepClone(o1), o1, "should not mutate original object");
+ const s = { p: 1 };
+ const o2 = { d: s };
+ t.notEquals(
+ deepClone(o2).d,
+ o2.d,
+ "returned value should not be deep equal to original value"
+ );
+ t.end();
+});
diff --git a/src/function/deepClone/index.ts b/src/function/deepClone/index.ts
new file mode 100644
index 0000000..655cb9d
--- /dev/null
+++ b/src/function/deepClone/index.ts
@@ -0,0 +1,11 @@
+export default function objectDeepClone(o: any) {
+ if (o == null || typeof o !== "object") return o;
+ const clone: any = Array.isArray(o) ? [] : {};
+ Object.keys(o).map(k => {
+ if (o.hasOwnProperty(k)) {
+ clone[k] = objectDeepClone(o[k]);
+ }
+ });
+
+ return clone;
+}
diff --git a/src/index.ts b/src/index.ts
index 8db6e34..e2ad9b5 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,11 +1,12 @@
/* istanbul ignore file */
import Either, { maybeToEither } from "./adt/Either";
-import Maybe, { eitherToMaybe, prop } from "./adt/Maybe";
+import Maybe, { eitherToMaybe, pick, prop } from "./adt/Maybe";
import Pair from "./adt/Pair";
import Reader from "./adt/Reader";
import State from "./adt/State";
import Task from "./adt/Task";
+import assoc from "./function/assoc";
import bimap from "./function/bimap";
import caseOf from "./function/caseOf";
import chain from "./function/chain";
@@ -27,6 +28,7 @@ export default {
Reader,
State,
Task,
+ assoc,
bimap,
caseOf,
chain,
@@ -42,5 +44,6 @@ export default {
maybeToEither,
ocurry,
once,
+ pick,
prop
};