Skip to content

Commit

Permalink
adds .value for canjs/can-value#19
Browse files Browse the repository at this point in the history
  • Loading branch information
justinbmeyer committed Sep 20, 2018
1 parent 85e3a31 commit 8fae622
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 30 deletions.
8 changes: 4 additions & 4 deletions async/async.js
Expand Up @@ -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`
Expand Down Expand Up @@ -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') {
Expand Down
24 changes: 24 additions & 0 deletions can-simple-observable-test.js
Expand Up @@ -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");
Expand Down
20 changes: 14 additions & 6 deletions can-simple-observable.js
Expand Up @@ -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,
Expand All @@ -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);
}
Expand Down
1 change: 0 additions & 1 deletion resolver/resolver-test.js
Expand Up @@ -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");
Expand Down
28 changes: 14 additions & 14 deletions resolver/resolver.js
Expand Up @@ -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),
Expand Down Expand Up @@ -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"+
Expand Down Expand Up @@ -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
Expand All @@ -140,7 +140,7 @@ canReflect.assignMap(ResolverObservable.prototype, {
/* jshint laxcomma: false */
}
//!steal-remove-end

queues.batch.start();
queues.deriveQueue.enqueue(
this.update,
Expand All @@ -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
Expand All @@ -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() {
Expand All @@ -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);
Expand All @@ -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;
}
Expand Down
37 changes: 37 additions & 0 deletions settable/settable-test.js
Expand Up @@ -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);

Expand Down
19 changes: 14 additions & 5 deletions settable/settable.js
Expand Up @@ -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') {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -118,7 +118,7 @@ Object.assign(SettableObservable.prototype, {
}

if (this.bound === true) {
return this.value;
return this._value;
} else {
return this.observation.get();
}
Expand All @@ -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,
Expand Down
17 changes: 17 additions & 0 deletions setter/setter-test.js
Expand Up @@ -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);

Expand Down

0 comments on commit 8fae622

Please sign in to comment.