Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a bunch of Object related functions. #119

Merged
merged 1 commit into from
Apr 27, 2017
Merged

Add a bunch of Object related functions. #119

merged 1 commit into from
Apr 27, 2017

Conversation

evilsoft
Copy link
Owner

Sending some ❤️ to all the Objects

image

After a few people were using crocks on a project, one of the complaints was a lack of ❤️ in the Object department. This PR tries to address some of their concerns. I will be adding an evolve function similar to Ramda's evolve function. But for now this PR adds the following:

  • assign: Like Object.assign, but returns a shallow copy and reverses arguments for pointfree application.
  • assoc: Assosiate a key-value pair to a given object
  • defaultProps: Default properties in a given object, by specifying an object of defaults.
  • defaultTo: Not an Object function, but handy none the less. Give it a default value and it will use that value when passed a null, undefined or NaN.
  • fromPairs: Build an Object for either a List or Array of key-values Pairs
  • objOf: Allows you to create an Object with a given key and value.
  • omit: Reject key-value pairs in a given Object using an Array of keys.
  • pick: Filter key-values pairs in a given Object using an Array of keys.
  • toPairs: Transform an Object into a List of key-value Pairs

Also updated map to map over an Object and isNil predicate now returns true for NaN

All Object related functions will omit any keys in which the value is explicitly undefined. If for some reason you need to add keys as placeholders, use null instead.

As part of the build process, needed to add another babel plugin for computed properties.

@coveralls
Copy link

coveralls commented Apr 17, 2017

Coverage Status

Coverage remained the same at 100.0% when pulling 0b6e9cd on some-obj-funcs into 5143fdb on master.

README.md Outdated
```haskell
assoc : String -> a -> Object -> Object
```
There may come a time when you want to add a key-value pair to an `Object` and want control over how the key and value are applied. That is where `assoc` can come to your aid. Just provide a `String` key and a value of any type to be associated to the key. Finally pass it any `Object` and you will get back a shallow copy with your key-value pair merged in. This will overwrite any exiting keys with new value specified. Used with [`flip`](#flip), you can do some interesting things with this function, give it a play! If you just want to create an `Object` and not concatenate it to another `Object`, [`objOf`](#objOf) may be the function for you.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

link for objOf, needs to be "objof"

README.md Outdated
```haskell
assign : Object -> Object -> Object
```
When working with `Object`s, a common operation is to combine (2) of them. This can be accomplished in `crocks` by reaching for `assign`. Unlike the `Object.assign` that ships with JavaScript, this `assign` will combine your `Object`s into a new shallow copy of their merger. `assign` only takes two arguments and will overwrite keys present in the second argument with values from the first. As with most of the `crocks` `Object` based functions, `assign` will omit any key-value pairs that are `undefined`. Check out a related function named [`defaultProps`](#defaultProps) that will only assign values that are `undefined` in the second argument.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

link for defaultProps needs to be "defaultprops"

README.md Outdated
```haskell
fromPairs : [ (Pair String a) ] | List (Pair String a) -> Object
```
As an inverse to [`toPairs`](#toPairs), `fromPairs` takes either an `Array` or `List` of key-value `Pair`s and constructs an `Object` from it. The `Pair` must contain a `String` in the `fst` and any type of value in the `snd`. The `fst` will become the key for the value in the `snd`. All primitive values are copied into the new `Object`, while non-primitives are references to the original. If you provide an `undefined` values for the second, that `Pair` will not be represented in the resulting `Object`. Also, when if multiple keys share the same name, that last value will be moved over.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

link for toPairs needs to be "topairs"

README.md Outdated
```haskell
omit : ([ String ] | List String) -> Object -> Object
```
Sometimes you just want to strip `Object`s of unwanted properties by key. Using `omit` will help you get that done. Just pass it a `Foldable` structure with a series of `String`s as keys and then pass it an `Object` and you will get back not only a shallow copy, but also an `Object` free of any of those pesky `undefined` values. You can think of `omit` as a way to black-list or reject `Object` properties based on key names. This function ignores inherited properties and should only be used with POJOs. If you want to filter or white-list properties rather than reject them, take a look at `[pick](#pick)`.
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only surround pick in backticks.

README.md Outdated
```haskell
pick : ([ String ] | List String) -> Object -> Object
```
When dealing with `Object`s, sometimes it is necessary to only let some of the key-value pairs on an object through. Think of `pick` as a sort of white-list or filter for `Object` properties. Pass it a `Foldable` structure of `String`s that are the keys you would like to pick off of your `Object`. This will give you back a shallow copy of the key-value pairs you specified. This function will ignore inherited properties and should only be used with POJOs. Any `undefined` values will not be copied over, although `null` values are allowed. For black-listing properties, have a look at `[omit](#omit)`
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only surround omit in backticks

README.md Outdated
```haskell
toPairs : Object -> List (Pair String a)
```
When dealing with `Object`s, sometimes it makes more sense to work in a `Foldable` structure like a `List` of key-value `Pair`s. `toPairs` provides a means to take an object and give you back a `List` of `Pairs` that have a `String` that represents the key in the `fst` and the value for that key in the `snd`. The primitive values are copied, while non-primitive values are references. Like most of the `Object` functions in `crocks`, any keys with `undefined` values will be omitted from the result. `crocks` provides an inverse to this function named [`fromPairs`](#fromPairs).
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

link for fromPairs needs to be "frompairs"


// assign : Object -> Object -> Object
function assign(x, m) {
if(!isObject(x) || !isObject(m)) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That darn De Morgan, should probably be:

if(!(isObject(x) && isObject(m)) {
  ...
}

helpers/assoc.js Outdated
else if(!isObject(obj)) {
throw new TypeError('assoc: Object required for third argument')
}
return Object.assign({}, obj, { [key]: val })
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use the assign in the new object TypeRef.

}

return value !== undefined
? Object.assign({}, acc, { [key]: value })
Copy link
Owner Author

@evilsoft evilsoft Apr 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to assign into a new Object. should just reuse accumulator and keep creation cost down.

helpers/omit.js Outdated
function omitKeys(keys, obj) {
return function(acc, key) {
return keys.indexOf(key) === -1 && obj[key] !== undefined
? Object.assign({}, acc, { [key]: obj[key] })
Copy link
Owner Author

@evilsoft evilsoft Apr 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to assign into a new Object. should just reuse accumulator and keep creation cost down.

helpers/pick.js Outdated
throw new TypeError('pick: Foldable of Strings is required for first argument')
}
return key && obj[key] !== undefined
? Object.assign({}, acc, { [key]: obj[key] })
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to assign into a new Object. should just reuse accumulator and keep creation cost down.

@amsross
Copy link
Contributor

amsross commented Apr 17, 2017

Just curious: Is there a benefit to adding these to the library rather than just suggesting/expecting the user to use the ramda counterparts? Are they notably different than said counterparts?

@evilsoft
Copy link
Owner Author

@amsross that is a great question.
They are pretty much the same with some subtle differences:

  • These functions use the crocks curry, which differs from ramda in that it will continue to apply until a non-function is returned.
  • assign is like merge in ramda, except I have found myself constantly flipping merge for it to be pointfree.
  • And finally, I have found that when using functions like pick and omit with other 3rd party libs (like AWS api, some cookie libs, etc), I am forced to reject(isNil, someObj) to remove things that have been explicitly set to undefined. So for all Object related functions (that iterate over some Object) strip all undefineds. Of course this does not apply to map so it conforms to Functor identity laws.

@coveralls
Copy link

coveralls commented Apr 18, 2017

Coverage Status

Coverage remained the same at 100.0% when pulling a127b2f on some-obj-funcs into 5143fdb on master.

@coveralls
Copy link

coveralls commented Apr 18, 2017

Coverage Status

Coverage remained the same at 100.0% when pulling 6ae6d87 on some-obj-funcs into 5143fdb on master.

@coveralls
Copy link

coveralls commented Apr 18, 2017

Coverage Status

Coverage remained the same at 100.0% when pulling 3137f75 on some-obj-funcs into 5143fdb on master.

@evilsoft
Copy link
Owner Author

image

@evilsoft evilsoft merged commit 01b81d8 into master Apr 27, 2017
@evilsoft evilsoft deleted the some-obj-funcs branch April 27, 2017 01:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants