From 8fae622156a1dcd09f1a3eca4c2193d78d607167 Mon Sep 17 00:00:00 2001 From: Justin Meyer Date: Thu, 20 Sep 2018 11:44:51 -0500 Subject: [PATCH] adds .value for https://github.com/canjs/can-value/issues/19 --- async/async.js | 8 ++++---- can-simple-observable-test.js | 24 +++++++++++++++++++++++ can-simple-observable.js | 20 +++++++++++++------ resolver/resolver-test.js | 1 - resolver/resolver.js | 28 +++++++++++++------------- settable/settable-test.js | 37 +++++++++++++++++++++++++++++++++++ settable/settable.js | 19 +++++++++++++----- setter/setter-test.js | 17 ++++++++++++++++ 8 files changed, 124 insertions(+), 30 deletions(-) diff --git a/async/async.js b/async/async.js index 20ff7b8..eb79146 100644 --- a/async/async.js +++ b/async/async.js @@ -34,7 +34,7 @@ function AsyncObservable(fn, context, initialValue) { // otherwise, if `resolve` was called synchronously in the getter, // resolve with the value passed to `resolve` else if (this.resolveCalled) { - this.resolve(this.value); + this.resolve(this._value); } // if bound, the handlers will be called by `resolve` @@ -80,14 +80,14 @@ var peek = ObservationRecorder.ignore(canReflect.getValue.bind(canReflect)); AsyncObservable.prototype.activate = function() { canReflect.onValue(this.observation, this.handler, "notify"); if (!this.resolveCalled) { - this.value = peek(this.observation); + this._value = peek(this.observation); } }; AsyncObservable.prototype.resolve = function resolve(newVal) { this.resolveCalled = true; - var old = this.value; - this.value = newVal; + var old = this._value; + this._value = newVal; //!steal-remove-start if (process.env.NODE_ENV !== 'production') { diff --git a/can-simple-observable-test.js b/can-simple-observable-test.js index 6f3db89..b567ccc 100644 --- a/can-simple-observable-test.js +++ b/can-simple-observable-test.js @@ -34,6 +34,30 @@ QUnit.test('basics', function(){ QUnit.equal(canReflect.getValue(obs), 'four', 'getValue after offValue'); }); +QUnit.test('basics with .value', function(){ + expect(5); + var obs = new SimpleObservable('one'); + + QUnit.equal(obs.value, 'one', 'getValue'); + + obs.value = 'two'; + ObservationRecorder.start(); + QUnit.equal(obs.value, 'two', 'setValue'); + var dependencies = ObservationRecorder.stop(); + QUnit.ok(dependencies.valueDependencies.has(obs), "was recorded"); + + var handler = function(newValue) { + QUnit.equal(newValue, 'three', 'onValue'); + }; + canReflect.onValue(obs, handler); + obs.value = 'three'; + + canReflect.offValue(obs, handler); + obs.value = 'four'; + + QUnit.equal(obs.value, 'four', 'getValue after offValue'); +}); + skipProduction("log observable changes", function(assert) { var done = assert.async(); var obs = new SimpleObservable("one"); diff --git a/can-simple-observable.js b/can-simple-observable.js index 3dbfc56..bd66c44 100644 --- a/can-simple-observable.js +++ b/can-simple-observable.js @@ -45,25 +45,33 @@ var dispatchSymbol = canSymbol.for("can.dispatch"); * ``` */ function SimpleObservable(initialValue) { - this.value = initialValue; + this._value = initialValue; } // mix in the value-like object event bindings valueEventBindings(SimpleObservable.prototype); -Object.assign(SimpleObservable.prototype, { +canReflect.assignMap(SimpleObservable.prototype, { log: log, get: function(){ ObservationRecorder.add(this); - return this.value; + return this._value; }, set: function(value){ - var old = this.value; - this.value = value; + var old = this._value; + this._value = value; this[dispatchSymbol](value, old); } }); +Object.defineProperty(SimpleObservable.prototype,"value",{ + set: function(value){ + return this.set(value); + }, + get: function(){ + return this.get(); + } +}); var simpleObservableProto = { "can.getValue": SimpleObservable.prototype.get, @@ -77,7 +85,7 @@ var simpleObservableProto = { //!steal-remove-start if (process.env.NODE_ENV !== 'production') { simpleObservableProto["can.getName"] = function() { - var value = this.value; + var value = this._value; if (typeof value !== 'object' || value === null) { value = JSON.stringify(value); } diff --git a/resolver/resolver-test.js b/resolver/resolver-test.js index 2d5be51..ad5eb41 100644 --- a/resolver/resolver-test.js +++ b/resolver/resolver-test.js @@ -80,7 +80,6 @@ QUnit.test('basics listenTo', 14, function(assert){ assert.equal(obs.get(), 6, "got unbound value"); listenHandlers = obs.binder[ canSymbol.for("can.meta") ].listenHandlers; QUnit.equal(listenHandlers.size(), 1, "1 handlers after bind"); - queues.log("flush"); number.set(2); assert.equal(obs.get(), 5, "got updated value"); diff --git a/resolver/resolver.js b/resolver/resolver.js index a407185..0f2f399 100644 --- a/resolver/resolver.js +++ b/resolver/resolver.js @@ -14,7 +14,7 @@ function ResolverObservable(resolver, context) { // we don't want reads leaking out. We should be binding to all of this ourselves. this.resolver = ObservationRecorder.ignore(resolver); this.context = context; - this.valueOptions = { + this._valueOptions = { resolve: this.resolve.bind(this), listenTo: this.listenTo.bind(this), stopListening: this.stopListening.bind(this), @@ -43,7 +43,7 @@ function ResolverObservable(resolver, context) { value: canReflect.getName(this) + ".update" }); - canReflect.assignSymbols(this.valueOptions.lastSet, { + canReflect.assignSymbols(this._valueOptions.lastSet, { "can.getName": function() { return ( canReflect.getName(this.constructor) +"::lastSet"+ @@ -118,16 +118,16 @@ canReflect.assignMap(ResolverObservable.prototype, { return this; }, resolve: function(newVal) { - this.value = newVal; + this._value = newVal; // if we are setting up the initial binding and we get a resolved value // do not emit events for it. if(this.isBinding) { - this.lastValue = this.value; + this.lastValue = this._value; return newVal; } - if(this.value !== this.lastValue) { + if(this._value !== this.lastValue) { var enqueueMeta = {}; //!steal-remove-start @@ -140,7 +140,7 @@ canReflect.assignMap(ResolverObservable.prototype, { /* jshint laxcomma: false */ } //!steal-remove-end - + queues.batch.start(); queues.deriveQueue.enqueue( this.update, @@ -154,14 +154,14 @@ canReflect.assignMap(ResolverObservable.prototype, { }, update: function(){ - if(this.lastValue !== this.value) { + if(this.lastValue !== this._value) { var old = this.lastValue; - this.lastValue = this.value; + this.lastValue = this._value; //!steal-remove-start if (process.env.NODE_ENV !== 'production') { if (typeof this._log === "function") { - this._log(old, this.value); + this._log(old, this._value); } } //!steal-remove-end @@ -170,13 +170,13 @@ canReflect.assignMap(ResolverObservable.prototype, { queues.enqueueByQueue( this.handlers.getNode([]), this, - [this.value, old] + [this._value, old] ); } }, activate: function() { this.isBinding = true; - this.teardown = this.resolver.call(this.context, this.valueOptions); + this.teardown = this.resolver.call(this.context, this._valueOptions); this.isBinding = false; }, onUnbound: function() { @@ -188,7 +188,7 @@ canReflect.assignMap(ResolverObservable.prototype, { } }, set: function(value) { - this.valueOptions.lastSet.set(value); + this._valueOptions.lastSet.set(value); /*if (newVal !== this.lastSetValue.get()) { this.lastSetValue.set(newVal); @@ -203,11 +203,11 @@ canReflect.assignMap(ResolverObservable.prototype, { } if (this.bound === true) { - return this.value; + return this._value; } else { var handler = function(){}; this.on(handler); - var val = this.value; + var val = this._value; this.off(handler); return val; } diff --git a/settable/settable-test.js b/settable/settable-test.js index dcbaa63..3d39cd4 100644 --- a/settable/settable-test.js +++ b/settable/settable-test.js @@ -49,6 +49,43 @@ QUnit.test('basics', function(){ }); +QUnit.test('basics with .value', function(){ + + var value = new SimpleObservable(2); + + + var obs = new SettableObservable(function(lastSet){ + return lastSet * value.value; + }, null, 1); + + // Unbound and unobserved behavior + QUnit.equal(obs.value, 2, 'getValue unbound'); + + + + var changes = 0; + var handler = function(newValue) { + changes++; + if(changes === 1) { + QUnit.equal(newValue, 4, 'set observable'); + obs.value = (3); + } else if(changes === 2){ + QUnit.equal(newValue, 6, 'set observable in handler'); + value.value = (3); + } else { + QUnit.equal(newValue, 9, 'set source'); + } + }; + canReflect.onValue(obs, handler); + obs.value = 2; + + QUnit.equal( obs.value, 9, "after bound"); + canReflect.offValue(obs, handler); + obs.value = 5; + QUnit.equal( obs.value, 15, "after unbound"); + +}); + QUnit.test("get and set Priority", function(){ var value = new SimpleObservable(2); diff --git a/settable/settable.js b/settable/settable.js index dd4d51b..b16df35 100644 --- a/settable/settable.js +++ b/settable/settable.js @@ -50,14 +50,14 @@ function SettableObservable(fn, context, initialValue) { valueEventBindings(SettableObservable.prototype); -Object.assign(SettableObservable.prototype, { +canReflect.assignMap(SettableObservable.prototype, { // call `obs.log()` to log observable changes to the browser console // The observable has to be bound for `.log` to be called log: log, constructor: SettableObservable, handler: function(newVal) { - var old = this.value; - this.value = newVal; + var old = this._value; + this._value = newVal; //!steal-remove-start if (process.env.NODE_ENV !== 'production') { @@ -87,7 +87,7 @@ Object.assign(SettableObservable.prototype, { }, activate: function(){ canReflect.onValue(this.observation, this.handler, "notify"); - this.value = peek(this.observation); + this._value = peek(this.observation); }, onUnbound: function() { this.bound = false; @@ -118,7 +118,7 @@ Object.assign(SettableObservable.prototype, { } if (this.bound === true) { - return this.value; + return this._value; } else { return this.observation.get(); } @@ -131,6 +131,15 @@ Object.assign(SettableObservable.prototype, { } }); +Object.defineProperty(SettableObservable.prototype,"value",{ + set: function(value){ + return this.set(value); + }, + get: function(){ + return this.get(); + } +}); + canReflect.assignSymbols(SettableObservable.prototype, { "can.getValue": SettableObservable.prototype.get, "can.setValue": SettableObservable.prototype.set, diff --git a/setter/setter-test.js b/setter/setter-test.js index 03f8170..83712ec 100644 --- a/setter/setter-test.js +++ b/setter/setter-test.js @@ -22,6 +22,23 @@ QUnit.test('basics', function(assert){ assert.equal(canReflect.getValue(obs), 3, 'getValue unbound'); }); +QUnit.test('basics with .value', function(assert){ + var value = new SimpleObservable(2); + + var obs = new SetterObservable(function(){ + return value.value; + }, function(newVal){ + value.value = (newVal); + }); + + // Unbound and unobserved behavior + assert.equal(obs.value, 2, 'getValue unbound'); + + obs.value = 3; + assert.equal(value.value, 3, 'value set'); + assert.equal(obs.value, 3, 'getValue unbound'); +}); + QUnit.test("get and set Priority", function(assert){ var value = new SimpleObservable(2);