From f8a54c928e79a2bd52f71e99c70be4390daad26f Mon Sep 17 00:00:00 2001 From: Rafael Rocha Date: Tue, 21 Jul 2015 17:08:01 -0300 Subject: [PATCH 1/3] first draft about kata proxies --- katas/es6/language/proxy/proxy.js | 112 ++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 katas/es6/language/proxy/proxy.js diff --git a/katas/es6/language/proxy/proxy.js b/katas/es6/language/proxy/proxy.js new file mode 100644 index 00000000..bb5b279d --- /dev/null +++ b/katas/es6/language/proxy/proxy.js @@ -0,0 +1,112 @@ +// 49: Proxy +// To do: make all tests pass, leave the assert lines unchanged! + + +// NOTES +//https://leanpub.com/exploring-es6/read +//http://www.ecma-international.org/ecma-262/6.0/ + + +// TODO Proxies as prototypes +// TODO Revocable + +describe('proxies bring intercession to JavaScript', function() { + + it('can intercept operation on objects such as get', function() { + let target = {}; + let handler = { + get(target, propKey, receiver) { + return 123; + } + }; + let proxy = new Proxy(target, handler); + + assert.equal(proxy.foo, 123); + }); + + + describe('traps (a term borrowed from the domain of operating systems) are the operations defined on the handler object', function() { + it('is called when the handler implements it', function() { + let target = { + foo: 987 + }; + + let handler = { + get(target, propKey, receiver) { + return 123; + } + }; + + let proxy = new Proxy(target, handler); + + assert.equal(proxy.foo, 123); + }); + + it('is not called when the handler does not implement it but target works as a fallback', function() { + let target = { + foo: 987 + }; + + let handler = { + has(target, propKey, receiver) { + return true; + } + }; + + let proxy = new Proxy(target, handler); + + assert.equal(proxy.foo, 987); + }); + }); + + describe('target object is the aimed object to be intercepted', function() { + it ('target property is not called when a trap intercepts its opertion', function() { + var counter = (function() { + var that = {}; + that.value = 0; + + that.increments = function() { + that.value = that.value + 1; + } + + return that; + })(); + + let handler = { + apply(target, propKey, receiver) { + return 999; + } + }; + + let proxyIncrement = new Proxy(counter.increments, handler); + + assert.equal(proxyIncrement(), 999); + assert.equal(counter.value, 0); + }); + + it ('must be done manually', function() { + var counter = (function() { + var that = {}; + that.value = 0; + + that.increments = function() { + that.value = that.value + 1; + } + + return that; + })(); + + let handler = { + apply(target, propKey, receiver) { + target(); + return 999; + } + }; + + let proxyIncrement = new Proxy(counter.increments, handler); + + assert.equal(proxyIncrement(), 999); + assert.equal(counter.value, 1); + }); + }); +}); \ No newline at end of file From 71afcd6f1ae48460ad1897c95a252def24c46441 Mon Sep 17 00:00:00 2001 From: Rafael Rocha Date: Mon, 27 Jul 2015 15:25:19 -0300 Subject: [PATCH 2/3] removing unecessary comments --- katas/es6/language/proxy/proxy.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/katas/es6/language/proxy/proxy.js b/katas/es6/language/proxy/proxy.js index bb5b279d..7474b80d 100644 --- a/katas/es6/language/proxy/proxy.js +++ b/katas/es6/language/proxy/proxy.js @@ -1,15 +1,6 @@ // 49: Proxy // To do: make all tests pass, leave the assert lines unchanged! - -// NOTES -//https://leanpub.com/exploring-es6/read -//http://www.ecma-international.org/ecma-262/6.0/ - - -// TODO Proxies as prototypes -// TODO Revocable - describe('proxies bring intercession to JavaScript', function() { it('can intercept operation on objects such as get', function() { From 408db02d2b208f0a297012bd9937acf4ec8e05ff Mon Sep 17 00:00:00 2001 From: Rafael Rocha Date: Mon, 3 Aug 2015 22:38:29 -0300 Subject: [PATCH 3/3] proxies katas splitted into basics, behaviour and api --- katas/es6/language/proxy/api.js | 53 +++++++++++++ katas/es6/language/proxy/basics.js | 46 ++++++++++++ katas/es6/language/proxy/behaviour.js | 91 +++++++++++++++++++++++ katas/es6/language/proxy/proxy.js | 103 -------------------------- 4 files changed, 190 insertions(+), 103 deletions(-) create mode 100644 katas/es6/language/proxy/api.js create mode 100644 katas/es6/language/proxy/basics.js create mode 100644 katas/es6/language/proxy/behaviour.js delete mode 100644 katas/es6/language/proxy/proxy.js diff --git a/katas/es6/language/proxy/api.js b/katas/es6/language/proxy/api.js new file mode 100644 index 00000000..defb1c5a --- /dev/null +++ b/katas/es6/language/proxy/api.js @@ -0,0 +1,53 @@ +// 49: Proxy - apis +// To do: make all tests pass, leave the assert lines unchanged! + +describe('handler can have different traps', function() { + + it('"apply" is a trap for a function call', function() { + var value = ""; + + let doSomething = function(arg) { + value = "Yeah! I'm safe!"; + }; + + let doSomethingProxy = new Proxy(doSomething, { + apply(target, thisArg, argumentsList) { + value = "Oh gosh, it's a trap!"; + } + }); + + doSomethingProxy(); + assert.equal(value, "Oh gosh, it's a trap!"); + }); + + it('"construct" is a trap for the "new" operator', function() { + var value = ""; + + let DoSomething = function(arg) { + value = "Yeah! I'm safe!"; + }; + + let DoSomethingProxy = new Proxy(DoSomething, { + construct(target, argumentsList) { + value = "Oh gosh, they got me!"; + return target; + } + }); + + var instance = new DoSomethingProxy(); + assert.equal(value, "Oh gosh, they got me!"); + }); + + it('"defineProperty" is a trap for Object.defineProperty()', function() {}); + it('"deleteProperty" is a trap for the "delete" operator', function() {}); + it('"enumerate" is a trap for for...in statements', function() {}); + it('"get" is a trap for getting a property value', function() {}); + it('"getOwnPropertyDescriptor" is a trap for Object.getOwnPropertyDescriptor()', function() {}); + it('"getPrototypeOf" is a trap for the [[GetPrototypeOf]] internal method', function() {}); + it('"has" is a trap for the in operator', function() {}); + it('"isExtensible" is a trap for Object.isExtensible()', function() {}); + it('"ownKeys" is a trap for Object.getOwnPropertyNames()', function() {}); + it('"preventExtensions" is a trap for Object.preventExtensions()', function() {}); + it('"set" is a trap for setting a property value', function() {}); + it('"setPrototypeOf" is a trap for Object.setPrototypeOf()', function() {}); +}); \ No newline at end of file diff --git a/katas/es6/language/proxy/basics.js b/katas/es6/language/proxy/basics.js new file mode 100644 index 00000000..b613f02f --- /dev/null +++ b/katas/es6/language/proxy/basics.js @@ -0,0 +1,46 @@ +// 49: Proxy - basics +// To do: make all tests pass, leave the assert lines unchanged! + +describe('proxies bring intercession to JavaScript', function() { + + it('is made of handler, traps and target', function() { + let target = {}; + let handler = { + // get is a trap + get(target, propKey, receiver) { + return 123; + } + }; + let proxy = new Proxy(target, handler); + + assert.equal(proxy.foo, 123); + }); + + it('can intercept operation on objects such as get and set', function() { + let target = {}; + let handler = { + get(target, propKey, receiver) { + if (propKey === 'foo') { + return 123; + } + return target[propKey]; + }, + set(target, propKey, value) { + if (propKey === 'age') { + if (!Number.isInteger(value)) { + throw new TypeError('The age is not an integer'); + } + } + + target[propKey] = value; + return true; + } + }; + + let proxy = new Proxy(target, handler); + + proxy.age = 26; + assert.equal(proxy.age, 26); + assert.equal(proxy.foo, 123); + }); +}); \ No newline at end of file diff --git a/katas/es6/language/proxy/behaviour.js b/katas/es6/language/proxy/behaviour.js new file mode 100644 index 00000000..de5afbca --- /dev/null +++ b/katas/es6/language/proxy/behaviour.js @@ -0,0 +1,91 @@ +// 49: Proxy - behaviour +// To do: make all tests pass, leave the assert lines unchanged! + +describe('handler has traps', function() { + + describe('traps are the operations defined on the handler object', function() { + it('is called when the handler implements it', function() { + let target = { + foo: 987 + }; + + let handler = { + get(target, propKey, receiver) { + return 123; + } + }; + + let proxy = new Proxy(target, handler); + + assert.equal(proxy.foo, 123); + }); + + it('is not called when the handler does not implement it but target works as a fallback', function() { + let target = { + foo: 987 + }; + + let handler = { + has(target, propKey, receiver) { + return true; + } + }; + + let proxy = new Proxy(target, handler); + + assert.equal(proxy.foo, 987); + }); + }); +}); + +describe('target object is the aimed object to be intercepted', function() { + + it ('target property is not called when a trap intercepts its opertion', function() { + var counter = (function() { + var that = {}; + that.value = 0; + + that.increments = function() { + that.value = that.value + 1; + } + + return that; + })(); + + let handler = { + apply(target, propKey, receiver) { + return 999; + } + }; + + let proxyIncrement = new Proxy(counter.increments, handler); + + assert.equal(proxyIncrement(), 999); + assert.equal(counter.value, 0); + }); + + it ('must be done manually', function() { + var counter = (function() { + var that = {}; + that.value = 0; + + that.increments = function() { + that.value = that.value + 1; + } + + return that; + })(); + + let handler = { + apply(target, propKey, receiver) { + target(); + return 999; + } + }; + + let proxyIncrement = new Proxy(counter.increments, handler); + + assert.equal(proxyIncrement(), 999); + assert.equal(counter.value, 1); + }); +}); \ No newline at end of file diff --git a/katas/es6/language/proxy/proxy.js b/katas/es6/language/proxy/proxy.js deleted file mode 100644 index 7474b80d..00000000 --- a/katas/es6/language/proxy/proxy.js +++ /dev/null @@ -1,103 +0,0 @@ -// 49: Proxy -// To do: make all tests pass, leave the assert lines unchanged! - -describe('proxies bring intercession to JavaScript', function() { - - it('can intercept operation on objects such as get', function() { - let target = {}; - let handler = { - get(target, propKey, receiver) { - return 123; - } - }; - let proxy = new Proxy(target, handler); - - assert.equal(proxy.foo, 123); - }); - - - describe('traps (a term borrowed from the domain of operating systems) are the operations defined on the handler object', function() { - it('is called when the handler implements it', function() { - let target = { - foo: 987 - }; - - let handler = { - get(target, propKey, receiver) { - return 123; - } - }; - - let proxy = new Proxy(target, handler); - - assert.equal(proxy.foo, 123); - }); - - it('is not called when the handler does not implement it but target works as a fallback', function() { - let target = { - foo: 987 - }; - - let handler = { - has(target, propKey, receiver) { - return true; - } - }; - - let proxy = new Proxy(target, handler); - - assert.equal(proxy.foo, 987); - }); - }); - - describe('target object is the aimed object to be intercepted', function() { - it ('target property is not called when a trap intercepts its opertion', function() { - var counter = (function() { - var that = {}; - that.value = 0; - - that.increments = function() { - that.value = that.value + 1; - } - - return that; - })(); - - let handler = { - apply(target, propKey, receiver) { - return 999; - } - }; - - let proxyIncrement = new Proxy(counter.increments, handler); - - assert.equal(proxyIncrement(), 999); - assert.equal(counter.value, 0); - }); - - it ('must be done manually', function() { - var counter = (function() { - var that = {}; - that.value = 0; - - that.increments = function() { - that.value = that.value + 1; - } - - return that; - })(); - - let handler = { - apply(target, propKey, receiver) { - target(); - return 999; - } - }; - - let proxyIncrement = new Proxy(counter.increments, handler); - - assert.equal(proxyIncrement(), 999); - assert.equal(counter.value, 1); - }); - }); -}); \ No newline at end of file