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 is.any() and is.all() methods #19

Merged
merged 5 commits into from Oct 11, 2017
Merged

Conversation

kodie
Copy link
Contributor

@kodie kodie commented Oct 6, 2017

Here is the any() and all() methods mentioned in #1.

I wasn't 100% sure how you envisioned it working but the way I did it was both methods accepts two arrays as parameters so that it's possible to check multiple variables for multiple types.

Let me know if you were thinking something different!

@melvin0008
Copy link
Contributor

@kodie At the bottom of the issue sindresorhus explained his idea of any and all. You can check it out. For eg. any(is.string, {}, true, '🦄');

@kodie
Copy link
Contributor Author

kodie commented Oct 6, 2017

@melvin0008 oh shoot! Completely missed that. I will update my PR.

@melvin0008
Copy link
Contributor

melvin0008 commented Oct 6, 2017

Sure.
It will something on the lines of this:

is.any = (func, ...values) => values.some(func);

is.all = (func, ...values) => values.every(func);

@kodie
Copy link
Contributor Author

kodie commented Oct 6, 2017

PR Updated. 🍻

@kodie
Copy link
Contributor Author

kodie commented Oct 6, 2017

ah, using rest parameters break Node v4 support. :/

@kodie
Copy link
Contributor Author

kodie commented Oct 6, 2017

There we go 👍

index.js Outdated
@@ -169,4 +169,30 @@ const isEmptyMapOrSet = x => (is.map(x) || is.set(x)) && x.size === 0;

is.empty = x => !x || isEmptyStringOrArray(x) || isEmptyObject(x) || isEmptyMapOrSet(x);

is.any = function (predicate, values) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

  1. See Array.prototype.some for the predicate check.
  2. Take the values as an array using (predicate, ...values) => { ... } instead of the slice.
  3. Use arrow functions instead of an anonymous function. All other methods use this syntax. You have to be consistent with the rest of the code.

basically, I think the code can look like is.any = (predicate, ...values) => values.some(predicate);
of course, you have to validate the values is an array using is.array.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I now see that ...values is impossible, So as I've said, put a comment stating the it's not possible due to node4 compatibility.

So keep the current logic, but use the array methods like before, and extract a common method to which you can pass the correct method (aka Array.prototype.some or Array.prototype.every).

index.js Outdated
@@ -169,4 +169,30 @@ const isEmptyMapOrSet = x => (is.map(x) || is.set(x)) && x.size === 0;

is.empty = x => !x || isEmptyStringOrArray(x) || isEmptyObject(x) || isEmptyMapOrSet(x);

is.any = function (predicate, values) {
let ret = false;
values = Array.prototype.slice.call(arguments, 1);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Generally, just a note, don't use arguments, ES5 has given has enough ways to deprecate usage pf arguments.

If you really end up having to use arguments, make sure you document it well.

Copy link
Contributor Author

@kodie kodie Oct 6, 2017

Choose a reason for hiding this comment

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

@gioragutt What would I use instead of arguments if I can't use ...values?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Notice the comment I've made above. I wrote it before I've went over the commits.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gioragutt oh, gotcha!

index.js Outdated
return ret;
};

is.all = function (predicate, values) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Array.prototype.every, same as before.

@@ -402,3 +402,17 @@ test('is.empty', t => {
tempSet.add(1);
t.false(m.empty(tempSet));
});

test('is.any', t => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Missing test cases:

  1. no items (aka m.any(m.integer))
  2. invalid predicate? what if the passed predicate is not a function? this should be validated

@sindresorhus say is.function(predicate) === false, do we throw an Error?

Copy link
Owner

Choose a reason for hiding this comment

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

say is.function(predicate) === false, do we throw an Error?

Yes

test.js Outdated
t.false(m.any(m.integer, true, 'lol', {}));
});

test('is.all', t => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

same as above

@gioragutt gioragutt mentioned this pull request Oct 6, 2017
@kodie
Copy link
Contributor Author

kodie commented Oct 6, 2017

@gioragutt PR Updated again, let me know what you think.

index.js Outdated
@@ -169,4 +169,35 @@ const isEmptyMapOrSet = x => (is.map(x) || is.set(x)) && x.size === 0;

is.empty = x => !x || isEmptyStringOrArray(x) || isEmptyObject(x) || isEmptyMapOrSet(x);

const isAnyOrAll = (all, predicate, values) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of passing all as a boolean, pass in a method param instead.

this would actually be either Array.prototype.some or Array.prototype.every,

and you'd call method.call(values, predicate).

it makes sense more than passing a boolean. If we're speaking clean code and SOLID, this violates both Single Responsibility Principle and Open Close Principle, because it makes isAnyOrAll (which should be renamed, for the same reasons) responsible for both having the the calls to the methods inside of it, and needing the logic to decide which method is called.

By passing the method from the caller, we can allow more methods to use isAnyOrAll.

I'm sure that there are more method of Array that receive a predicate.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense! What would you suggest we change the name of isAnyOrAll to?

Copy link
Collaborator

Choose a reason for hiding this comment

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

predicateOnArray

index.js Outdated
}

if (values.length === 0) {
throw new TypeError(`Invalid number of values: ${util.inspect(values.length)}`);
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can never really have a value other than 0, so why call inspect on this? instead, make the error more readable, f.e: No values passed to ${callerMethod}, where callerMethod can be passed as an argument.


// We have to use anonymous functions for the any() and all() methods
// to get the arguments since we can't use rest parameters in node v4.
is.any = function (predicate) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

is.any = predicate => isAnyOrAll(...)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Have to use an anonymous function in order to get the correct arguments object. For some reason the arguments object is weird with arrow functions.

Copy link
Collaborator

Choose a reason for hiding this comment

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

God I hate old js.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

Just for the sake of debugging, name the anonymous functions (isAll and isAny) so that they'll be named if they appear in a stack trace.

After that, I'll approve

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, we now have is.empty for length === 0

Copy link
Owner

Choose a reason for hiding this comment

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

Just for the sake of debugging, name the anonymous functions (isAll and isAny) so that they'll be named if they appear in a stack trace.

That is not necessary. JS engines are able to infer the name.

Copy link
Owner

Choose a reason for hiding this comment

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

Also, we now have is.empty for length === 0

I think it's overdoing it using is.empty for that.

@kodie
Copy link
Contributor Author

kodie commented Oct 7, 2017

@gioragutt Updated.


// We have to use anonymous functions for the any() and all() methods
// to get the arguments since we can't use rest parameters in node v4.
is.any = function (predicate) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just for the sake of debugging, name the anonymous functions (isAll and isAny) so that they'll be named if they appear in a stack trace.

After that, I'll approve


// We have to use anonymous functions for the any() and all() methods
// to get the arguments since we can't use rest parameters in node v4.
is.any = function (predicate) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, we now have is.empty for length === 0

Copy link
Collaborator

@gioragutt gioragutt left a comment

Choose a reason for hiding this comment

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

@sindresorhus If so, then this PR is done?

@sindresorhus sindresorhus merged commit 651f434 into sindresorhus:master Oct 11, 2017
@sindresorhus
Copy link
Owner

👌😎

@gioragutt
Copy link
Collaborator

@sindresorhus great! v0.3.0?

@sindresorhus
Copy link
Owner

Already done an hour ago ;)

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.

None yet

4 participants