Repository: sindresorhus/is
Pull request #4 (2017-09-24 00:44:03)

Add `is.generator()` and `is.generatorFunction()`
Took one thing off of the list! Feel free to merge. ❤️

PS: Yes, I notice there's some code duplication in my tests. Don't know how `ava` works in the slightest. If anyone knows how to group two tests into one to allow variable reuse, I'm more than willing to update the PR. 💪

sindresorhus: > PS: Yes, I notice there's some code duplication in my tests. Don't know how ava works in the slightest.

That's not a problem. Tests should be atomic.
yeskunall: Thanks for the review. I'll ping you once I've made the changes 😄
yeskunall: @gioragutt I don't believe there's a need to use the existing function, but if @sindresorhus agrees to it as well, sure, I'll rewrite the check to use `is.function` 😄
sindresorhus: > Use existing checks in is, f.e is.function for generator, checking that next and error are functions. Reuse whenever possible.

👍 
yeskunall: @sindresorhus ping! This PR is ready to be merged once you approve my wording for documenting that `is.generator` is a naive check. Here's what I came up with, but maybe the sentence could be improved?
<hr />

`is.generator`
> Returns `true` for any object that implements its own `.next()` and `.throw()` methods and has a function definition for `Symbol.iterator`.
yeskunall: Hey @sindresorhus, you seem to be busy. But anyway, on Node 4.x.x, the check `getObjectType` on a generator function returns `Function`, so do you suggest I go back to my original check, or should I provision for Node 4.x.x, check for which version the user is running, and do two different checks?

Here's why the Travis build is failing:

```shell
yeskunall:~/workspace $ nvm use 4
Now using node v4.2.1 (npm v2.14.7)
```

```node
yeskunall:~/workspace $ node
> const toString = Object.prototype.toString;
undefined
> const getObjectType = x => toString.call(x).slice(8, -1);
undefined
> getObjectType(function* () { yield 42 });
'Function'
> const gen = function* () { yield 42; };
undefined
> gen.constructor.name;
'GeneratorFunction'
> # 🤔
```

Whenever you find time to respond. ❤️ 
sindresorhus: > the check getObjectType on a generator function returns Function, so do you suggest I go back to my original check, or should I provision for Node 4.x.x, check for which version the user is running, and do two different checks?

Let's just go back to the old check, but include a comment about switching to the `getObjectType` check when we target Node.js 6 or newer.
sindresorhus: Can you also fix the merge conflict?
yeskunall: I'll make the changes as requested. Heading to work now, you should be able to merge this PR by today. 👍
yeskunall: Hey @gioragutt, all done. Feel free to merge when you can. 👍

Patch:
diff --git a/index.js b/index.js
index befda91..02036be 100644
--- a/index.js
+++ b/index.js
@@ -82,6 +82,11 @@ const hasPromiseAPI = x =>
 
 is.promise = x => is.nativePromise(x) || hasPromiseAPI(x);
 
+is.generator = x => is.iterable(x) && is.function(x.next) && is.function(x.throw);
+
+// Change to use `isObjectOfType` once Node 4.x.x LTS is dropped
+is.generatorFunction = x => x.constructor.name === 'GeneratorFunction';
+
 is.regExp = isObjectOfType('RegExp');
 is.date = isObjectOfType('Date');
 is.error = isObjectOfType('Error');
diff --git a/readme.md b/readme.md
index 0962385..be284c4 100644
--- a/readme.md
+++ b/readme.md
@@ -78,6 +78,12 @@ Keep in mind that [functions are objects too](https://developer.mozilla.org/en-U
 
 Returns `true` for any object with a `.then()` and `.catch()` method. Prefer this one over `.nativePromise()` as you usually want to allow userland promise implementations too.
 
+##### .generator(value)
+
+Returns `true` for any object that implements its own `.next()` and `.throw()` methods and has a function definition for `Symbol.iterator`.
+
+##### .generatorFunction(value)
+
 ##### .map(value)
 ##### .set(value)
 ##### .weakMap(value)


Test patch:
diff --git a/test.js b/test.js
index 316bb41..89b4a41 100644
--- a/test.js
+++ b/test.js
@@ -58,6 +58,9 @@ const types = new Map([
 		PromiseSubclassFixture.resolve()
 	]],
 	['promise', {then() {}, catch() {}}],
+	['generator', (function * () {
+		yield 42;
+	})()],
 	['map', new Map()],
 	['set', new Set()],
 	['weakMap', new WeakMap()],
@@ -86,7 +89,7 @@ const types = new Map([
 	['integer', 6]
 ]);
 
-// This ensure a certain method matches only the types
+// This ensures a certain method matches only the types
 // it's supposed to and none of the other methods' types
 const testType = (t, type, exclude) => {
 	for (const [key, value] of types) {
@@ -170,6 +173,17 @@ if (isNode8orHigher) {
 	});
 }
 
+test('is.generator', t => {
+	testType(t, 'generator', ['function']);
+});
+
+test('is.generatorFunction', t => {
+	const gen = function * () {
+		yield 42;
+	};
+	t.true(m.generatorFunction(gen));
+});
+
 test('is.map', t => {
 	testType(t, 'map');
 });