{"action":"opened","number":3433,"pull_request":{"url":"https://api.github.com/repos/codecombat/codecombat/pulls/3433","id":61035584,"html_url":"https://github.com/codecombat/codecombat/pull/3433","diff_url":"https://github.com/codecombat/codecombat/pull/3433.diff","patch_url":"https://github.com/codecombat/codecombat/pull/3433.patch","issue_url":"https://api.github.com/repos/codecombat/codecombat/issues/3433","number":3433,"state":"open","locked":false,"title":"Add initial support for built-in methods with generatorified callbacks","user":{"login":"UltCombo","id":2090712,"avatar_url":"https://avatars.githubusercontent.com/u/2090712?v=3","gravatar_id":"","url":"https://api.github.com/users/UltCombo","html_url":"https://github.com/UltCombo","followers_url":"https://api.github.com/users/UltCombo/followers","following_url":"https://api.github.com/users/UltCombo/following{/other_user}","gists_url":"https://api.github.com/users/UltCombo/gists{/gist_id}","starred_url":"https://api.github.com/users/UltCombo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/UltCombo/subscriptions","organizations_url":"https://api.github.com/users/UltCombo/orgs","repos_url":"https://api.github.com/users/UltCombo/repos","events_url":"https://api.github.com/users/UltCombo/events{/privacy}","received_events_url":"https://api.github.com/users/UltCombo/received_events","type":"User","site_admin":false},"body":"This is an initial proof of concept for codecombat/codecombat#2874.\r\n\r\nThis PR, together with codecombat/aether#159 adds support for built-in methods that accept generator functions as callbacks. As this is an early proof of concept, I've only added the `[].forEach` and `[].map` methods.\r\n\r\nWith this PR and the Aether PR merged, this code will finally work as expected:\r\n\r\n```js\r\nfunction double(value) {\r\n    return value * 2;\r\n}\r\n\r\nvar arr = [1, 2, 3];\r\n\r\nvar doubled = arr.map(function(value) {\r\n    return double(value);\r\n});\r\n\r\ndoubled.forEach(function(value) {\r\n    this.say(value); // 2, 4, 6\r\n}, this);\r\n```\r\n\r\n## PR overview\r\n\r\nI've created a side-project called [innerator](https://github.com/UltCombo/innerator#innerator), which provides the option to override built-in methods replacing them with re-implementations that understand generator functions as callbacks. I believe this is more clear in the [innerator docs](https://github.com/UltCombo/innerator#innerator):\r\n\r\n\r\n> ## innerator\r\n> JavaScript built-in functions rewritten to understand generators.\r\n>\r\n> The innerator functions closely follow the [ECMA-262's current work](https://tc39.github.io/ecma262/). The inneratored versions of the built-in functions support generator functions where only regular functions were supported, properly executing the generator and iterating over it.\r\n\r\nAs for how it actually works, well, it is all open source. In any case, I believe a quick overview is in order:\r\n\r\n- Innerator replaces the built-ins with a function that checks whether the callback passed in is a generator function or not. If it is, it calls the inneratored version of that built-in, otherwise it calls the original built-in function.\r\n  - Note that as Aether replaces the `constructor` property of all objects with a regular function that throws when called, it is very hard (impossible?) to detect generator functions in a conventional way. Therefore, I've added a `supportAether` boolean option to the `installGlobals` method. When this option is enabled, innerator will look for a `_isAetherGen` property that is set on the generator function by Aether in codecombat/aether#159. You can see how this is handled in the innerator side [here](https://github.com/UltCombo/innerator/blob/9818261d5926f6479f6770355232ada39dfbf492/src/index.js#L15-L39).\r\n- My generatorified built-ins closely follow [ECMA-262's current work](https://tc39.github.io/ecma262/), they just add `yield*` (iterator delegation) to the result of  `Call` operations. Check out one of the generatorified functions for details, e.g. [`Array.prototype.forEach`](https://github.com/UltCombo/innerator/blob/9818261d5926f6479f6770355232ada39dfbf492/src/lib/Array.prototype.forEach.js).\r\n- As for the development stack: it uses [Babel](http://babeljs.io/) and [Webpack](https://webpack.github.io/) for compilation and bundling, ESLint for linting, Mocha for unit testing. It is also using [Especially](https://github.com/domenic/especially) (in fact, a [branch](https://github.com/domenic/especially/pull/9) that I haven't merged in yet) in order to make the built-ins re-implementations easier to reason about—i.e. the code reads very closely to the spec. and allows one to maintain sanity using reusable and modular code.\r\n- Innerator is quite [well documented](https://github.com/UltCombo/innerator#innerator) and has [extensive tests](https://github.com/UltCombo/innerator/tree/master/src/test), so it should be pretty easy to use.\r\n\r\n---\r\n\r\nHere are a few things I already know that are missing:\r\n\r\n- [ ] Headless client—generatorified functions are not implemented for it yet.\r\n- [ ] Reduce innerator file size—if this seems like a viable approach, I'd be happy to try to drop all the Babel/Webpack stuff and only preserve regenerator. This should drastically reduce innerator's file size.\r\n- [ ] Merge Innerator into Aether—I guess it would make more sense for innerator to go with Aether than here, but I'm not sure how to do that yet.\r\n\r\nAnd yes, I'm aware that the CodeCombat team is working on a new interpreter that should fix most if not all of theses issues. It is up to you whether this is worth taking a look at.\r\n\r\n**Note:** this PR only addresses passing generatorified functions to *built-in methods*—this PR does not intend to cover passing generatorified functions to user defined functions, that would perhaps be a future PR. I should also note again that this is an early PoC that only covers `[].forEach` and `[].map`.","created_at":"2016-02-29T06:52:36Z","updated_at":"2016-02-29T06:52:36Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/codecombat/codecombat/pulls/3433/commits","review_comments_url":"https://api.github.com/repos/codecombat/codecombat/pulls/3433/comments","review_comment_url":"https://api.github.com/repos/codecombat/codecombat/pulls/comments{/number}","comments_url":"https://api.github.com/repos/codecombat/codecombat/issues/3433/comments","statuses_url":"https://api.github.com/repos/codecombat/codecombat/statuses/7e962e021a758bbd95d2d8fba45eda421f1f26a2","head":{"label":"UltCombo:built-ins-generatorified-callbacks","ref":"built-ins-generatorified-callbacks","sha":"7e962e021a758bbd95d2d8fba45eda421f1f26a2","user":{"login":"UltCombo","id":2090712,"avatar_url":"https://avatars.githubusercontent.com/u/2090712?v=3","gravatar_id":"","url":"https://api.github.com/users/UltCombo","html_url":"https://github.com/UltCombo","followers_url":"https://api.github.com/users/UltCombo/followers","following_url":"https://api.github.com/users/UltCombo/following{/other_user}","gists_url":"https://api.github.com/users/UltCombo/gists{/gist_id}","starred_url":"https://api.github.com/users/UltCombo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/UltCombo/subscriptions","organizations_url":"https://api.github.com/users/UltCombo/orgs","repos_url":"https://api.github.com/users/UltCombo/repos","events_url":"https://api.github.com/users/UltCombo/events{/privacy}","received_events_url":"https://api.github.com/users/UltCombo/received_events","type":"User","site_admin":false},"repo":{"id":38181767,"name":"codecombat","full_name":"UltCombo/codecombat","owner":{"login":"UltCombo","id":2090712,"avatar_url":"https://avatars.githubusercontent.com/u/2090712?v=3","gravatar_id":"","url":"https://api.github.com/users/UltCombo","html_url":"https://github.com/UltCombo","followers_url":"https://api.github.com/users/UltCombo/followers","following_url":"https://api.github.com/users/UltCombo/following{/other_user}","gists_url":"https://api.github.com/users/UltCombo/gists{/gist_id}","starred_url":"https://api.github.com/users/UltCombo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/UltCombo/subscriptions","organizations_url":"https://api.github.com/users/UltCombo/orgs","repos_url":"https://api.github.com/users/UltCombo/repos","events_url":"https://api.github.com/users/UltCombo/events{/privacy}","received_events_url":"https://api.github.com/users/UltCombo/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/UltCombo/codecombat","description":"Multiplayer programming game for learning how to code.","fork":true,"url":"https://api.github.com/repos/UltCombo/codecombat","forks_url":"https://api.github.com/repos/UltCombo/codecombat/forks","keys_url":"https://api.github.com/repos/UltCombo/codecombat/keys{/key_id}","collaborators_url":"https://api.github.com/repos/UltCombo/codecombat/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/UltCombo/codecombat/teams","hooks_url":"https://api.github.com/repos/UltCombo/codecombat/hooks","issue_events_url":"https://api.github.com/repos/UltCombo/codecombat/issues/events{/number}","events_url":"https://api.github.com/repos/UltCombo/codecombat/events","assignees_url":"https://api.github.com/repos/UltCombo/codecombat/assignees{/user}","branches_url":"https://api.github.com/repos/UltCombo/codecombat/branches{/branch}","tags_url":"https://api.github.com/repos/UltCombo/codecombat/tags","blobs_url":"https://api.github.com/repos/UltCombo/codecombat/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/UltCombo/codecombat/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/UltCombo/codecombat/git/refs{/sha}","trees_url":"https://api.github.com/repos/UltCombo/codecombat/git/trees{/sha}","statuses_url":"https://api.github.com/repos/UltCombo/codecombat/statuses/{sha}","languages_url":"https://api.github.com/repos/UltCombo/codecombat/languages","stargazers_url":"https://api.github.com/repos/UltCombo/codecombat/stargazers","contributors_url":"https://api.github.com/repos/UltCombo/codecombat/contributors","subscribers_url":"https://api.github.com/repos/UltCombo/codecombat/subscribers","subscription_url":"https://api.github.com/repos/UltCombo/codecombat/subscription","commits_url":"https://api.github.com/repos/UltCombo/codecombat/commits{/sha}","git_commits_url":"https://api.github.com/repos/UltCombo/codecombat/git/commits{/sha}","comments_url":"https://api.github.com/repos/UltCombo/codecombat/comments{/number}","issue_comment_url":"https://api.github.com/repos/UltCombo/codecombat/issues/comments{/number}","contents_url":"https://api.github.com/repos/UltCombo/codecombat/contents/{+path}","compare_url":"https://api.github.com/repos/UltCombo/codecombat/compare/{base}...{head}","merges_url":"https://api.github.com/repos/UltCombo/codecombat/merges","archive_url":"https://api.github.com/repos/UltCombo/codecombat/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/UltCombo/codecombat/downloads","issues_url":"https://api.github.com/repos/UltCombo/codecombat/issues{/number}","pulls_url":"https://api.github.com/repos/UltCombo/codecombat/pulls{/number}","milestones_url":"https://api.github.com/repos/UltCombo/codecombat/milestones{/number}","notifications_url":"https://api.github.com/repos/UltCombo/codecombat/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/UltCombo/codecombat/labels{/name}","releases_url":"https://api.github.com/repos/UltCombo/codecombat/releases{/id}","deployments_url":"https://api.github.com/repos/UltCombo/codecombat/deployments","created_at":"2015-06-28T01:19:14Z","updated_at":"2015-06-28T01:19:17Z","pushed_at":"2016-02-29T05:46:53Z","git_url":"git://github.com/UltCombo/codecombat.git","ssh_url":"git@github.com:UltCombo/codecombat.git","clone_url":"https://github.com/UltCombo/codecombat.git","svn_url":"https://github.com/UltCombo/codecombat","homepage":"http://codecombat.com","size":117544,"stargazers_count":0,"watchers_count":0,"language":"CoffeeScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"codecombat:master","ref":"master","sha":"d9a52c62f1bf910760259d16c4019d8b21c3228e","user":{"login":"codecombat","id":5795842,"avatar_url":"https://avatars.githubusercontent.com/u/5795842?v=3","gravatar_id":"","url":"https://api.github.com/users/codecombat","html_url":"https://github.com/codecombat","followers_url":"https://api.github.com/users/codecombat/followers","following_url":"https://api.github.com/users/codecombat/following{/other_user}","gists_url":"https://api.github.com/users/codecombat/gists{/gist_id}","starred_url":"https://api.github.com/users/codecombat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codecombat/subscriptions","organizations_url":"https://api.github.com/users/codecombat/orgs","repos_url":"https://api.github.com/users/codecombat/repos","events_url":"https://api.github.com/users/codecombat/events{/privacy}","received_events_url":"https://api.github.com/users/codecombat/received_events","type":"Organization","site_admin":false},"repo":{"id":15193430,"name":"codecombat","full_name":"codecombat/codecombat","owner":{"login":"codecombat","id":5795842,"avatar_url":"https://avatars.githubusercontent.com/u/5795842?v=3","gravatar_id":"","url":"https://api.github.com/users/codecombat","html_url":"https://github.com/codecombat","followers_url":"https://api.github.com/users/codecombat/followers","following_url":"https://api.github.com/users/codecombat/following{/other_user}","gists_url":"https://api.github.com/users/codecombat/gists{/gist_id}","starred_url":"https://api.github.com/users/codecombat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/codecombat/subscriptions","organizations_url":"https://api.github.com/users/codecombat/orgs","repos_url":"https://api.github.com/users/codecombat/repos","events_url":"https://api.github.com/users/codecombat/events{/privacy}","received_events_url":"https://api.github.com/users/codecombat/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/codecombat/codecombat","description":"Multiplayer programming game for learning how to code.","fork":false,"url":"https://api.github.com/repos/codecombat/codecombat","forks_url":"https://api.github.com/repos/codecombat/codecombat/forks","keys_url":"https://api.github.com/repos/codecombat/codecombat/keys{/key_id}","collaborators_url":"https://api.github.com/repos/codecombat/codecombat/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/codecombat/codecombat/teams","hooks_url":"https://api.github.com/repos/codecombat/codecombat/hooks","issue_events_url":"https://api.github.com/repos/codecombat/codecombat/issues/events{/number}","events_url":"https://api.github.com/repos/codecombat/codecombat/events","assignees_url":"https://api.github.com/repos/codecombat/codecombat/assignees{/user}","branches_url":"https://api.github.com/repos/codecombat/codecombat/branches{/branch}","tags_url":"https://api.github.com/repos/codecombat/codecombat/tags","blobs_url":"https://api.github.com/repos/codecombat/codecombat/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/codecombat/codecombat/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/codecombat/codecombat/git/refs{/sha}","trees_url":"https://api.github.com/repos/codecombat/codecombat/git/trees{/sha}","statuses_url":"https://api.github.com/repos/codecombat/codecombat/statuses/{sha}","languages_url":"https://api.github.com/repos/codecombat/codecombat/languages","stargazers_url":"https://api.github.com/repos/codecombat/codecombat/stargazers","contributors_url":"https://api.github.com/repos/codecombat/codecombat/contributors","subscribers_url":"https://api.github.com/repos/codecombat/codecombat/subscribers","subscription_url":"https://api.github.com/repos/codecombat/codecombat/subscription","commits_url":"https://api.github.com/repos/codecombat/codecombat/commits{/sha}","git_commits_url":"https://api.github.com/repos/codecombat/codecombat/git/commits{/sha}","comments_url":"https://api.github.com/repos/codecombat/codecombat/comments{/number}","issue_comment_url":"https://api.github.com/repos/codecombat/codecombat/issues/comments{/number}","contents_url":"https://api.github.com/repos/codecombat/codecombat/contents/{+path}","compare_url":"https://api.github.com/repos/codecombat/codecombat/compare/{base}...{head}","merges_url":"https://api.github.com/repos/codecombat/codecombat/merges","archive_url":"https://api.github.com/repos/codecombat/codecombat/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/codecombat/codecombat/downloads","issues_url":"https://api.github.com/repos/codecombat/codecombat/issues{/number}","pulls_url":"https://api.github.com/repos/codecombat/codecombat/pulls{/number}","milestones_url":"https://api.github.com/repos/codecombat/codecombat/milestones{/number}","notifications_url":"https://api.github.com/repos/codecombat/codecombat/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/codecombat/codecombat/labels{/name}","releases_url":"https://api.github.com/repos/codecombat/codecombat/releases{/id}","deployments_url":"https://api.github.com/repos/codecombat/codecombat/deployments","created_at":"2013-12-14T21:47:37Z","updated_at":"2016-02-29T01:47:04Z","pushed_at":"2016-02-29T01:18:24Z","git_url":"git://github.com/codecombat/codecombat.git","ssh_url":"git@github.com:codecombat/codecombat.git","clone_url":"https://github.com/codecombat/codecombat.git","svn_url":"https://github.com/codecombat/codecombat","homepage":"http://codecombat.com","size":121227,"stargazers_count":4857,"watchers_count":4857,"language":"CoffeeScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2289,"mirror_url":null,"open_issues_count":374,"forks":2289,"open_issues":374,"watchers":4857,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/codecombat/codecombat/pulls/3433"},"html":{"href":"https://github.com/codecombat/codecombat/pull/3433"},"issue":{"href":"https://api.github.com/repos/codecombat/codecombat/issues/3433"},"comments":{"href":"https://api.github.com/repos/codecombat/codecombat/issues/3433/comments"},"review_comments":{"href":"https://api.github.com/repos/codecombat/codecombat/pulls/3433/comments"},"review_comment":{"href":"https://api.github.com/repos/codecombat/codecombat/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/codecombat/codecombat/pulls/3433/commits"},"statuses":{"href":"https://api.github.com/repos/codecombat/codecombat/statuses/7e962e021a758bbd95d2d8fba45eda421f1f26a2"}},"merged":false,"mergeable":null,"mergeable_state":"unknown","merged_by":null,"comments":0,"review_comments":0,"commits":1,"additions":9,"deletions":3,"changed_files":3}}