Skip to content

Commit

Permalink
Update docs and rename project to can-observation
Browse files Browse the repository at this point in the history
This renames the project to can-observation. Part of #4
  • Loading branch information
matthewp committed Jun 21, 2016
1 parent f96ce27 commit 3c2d1cd
Show file tree
Hide file tree
Showing 13 changed files with 342 additions and 174 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -27,5 +27,5 @@ node_modules
# Users Environment Variables
.lock-wscript

docs/
doc/
dist/
209 changes: 151 additions & 58 deletions can-observe-info.js → can-observation.js
@@ -1,4 +1,4 @@
// # can/compute/get_value_and_bind
// # can-observation
//
// This module:
//
Expand All @@ -17,7 +17,7 @@ var canBatch = require('can-event/batch/');
var assign = require('can-util/js/assign/');
var namespace = require('can-util/namespace');

function ObservedInfo(func, context, compute){
function Observation(func, context, compute){
this.newObserved = {};
this.oldObserved = null;
this.func = func;
Expand All @@ -33,7 +33,7 @@ function ObservedInfo(func, context, compute){
this.setReady = this._setReady.bind(this);
}

// ### observedInfoStack
// ### observationStack
//
// This is the stack of all `observedInfo` objects that are the result of
// recursive `getValueAndBind` calls.
Expand All @@ -54,9 +54,9 @@ function ObservedInfo(func, context, compute){
// - `observed` is a map of `"cid|event"` to the observable and event.
// We use keys like `"cid|event"` to quickly identify if we have already observed this observable.
// - `names` is all the keys so we can quickly tell if two observedInfo objects are the same.
var observedInfoStack = [];
var observationStack = [];

assign(ObservedInfo.prototype,{
assign(Observation.prototype,{
getPrimaryDepth: function() {
return this.compute._primaryDepth || 0;
},
Expand Down Expand Up @@ -99,7 +99,7 @@ assign(ObservedInfo.prototype,{
if(ev.batchNum !== undefined) {
// Only need to register once per batchNum
if(ev.batchNum !== this.batchNum) {
ObservedInfo.registerUpdate(this);
Observation.registerUpdate(this);
this.batchNum = ev.batchNum;
}
} else {
Expand All @@ -125,7 +125,7 @@ assign(ObservedInfo.prototype,{
// ## getValueAndBind
// Calls `func` with "this" as `context` and binds to any observables that
// `func` reads. When any of those observables change, `onchanged` is called.
// `oldObservedInfo` is A map of observable / event pairs this function used to be listening to.
// `oldObservation` is A map of observable / event pairs this function used to be listening to.
// Returns the `newInfo` set of listeners and the value `func` returned.
getValueAndBind: function() {
this.bound = true;
Expand All @@ -137,9 +137,9 @@ assign(ObservedInfo.prototype,{
// Add this function call's observedInfo to the stack,
// runs the function, pops off the observedInfo, and returns it.

observedInfoStack.push(this);
observationStack.push(this);
this.value = this.func.call(this.context);
observedInfoStack.pop();
observationStack.pop();
this.updateBindings();
canBatch.afterPreviousEvents(this.setReady);
},
Expand Down Expand Up @@ -177,14 +177,28 @@ assign(ObservedInfo.prototype,{
}
});

/**
* @typedef {{}} observed observed
*
* @description
*
* An object representing an observation.
*
* ```js
* { "obj": map, "event": "prop1" }
* ```
*
* @option {Object} obj The observable object
* @option {String} event The event, or more likely property, that is being observed.
*/


var updateOrder = [],
curPrimaryDepth = Infinity,
maxPrimaryDepth = 0;

// could get a registerUpdate from a 5 while a 1 is going on because the 5 listens to the 1
ObservedInfo.registerUpdate = function(observeInfo, batchNum){
Observation.registerUpdate = function(observeInfo, batchNum){
var depth = observeInfo.getDepth()-1;
var primaryDepth = observeInfo.getPrimaryDepth();

Expand All @@ -204,7 +218,8 @@ ObservedInfo.registerUpdate = function(observeInfo, batchNum){
primary.current = Math.min(depth, primary.current);
primary.max = Math.max(depth, primary.max);
};
ObservedInfo.batchEnd = function(batchNum){

Observation.batchEnd = function(batchNum){
var cur;

while(true) {
Expand All @@ -230,12 +245,25 @@ ObservedInfo.batchEnd = function(batchNum){
}
};


// ## can.__observe
// Indicates that an observable is being read.
// Updates the top of the stack with the observable being read.
ObservedInfo.observe = function (obj, event) {
var top = observedInfoStack[observedInfoStack.length-1];
/**
* @function Observation.add observe
* @signature `Observation.add(obj, event)`
*
* Signals that an event should be observed. Adds the observable being read to
* the top of the stack.
*
* ```js
* Observation.add(obj, "prop1");
* ```
*
* @param {Object} obj An observable object which is being observed.
* @param {String} event The name of the event (or property) that is being observed.
* @body
*
* Signals that an object's property is being observed, so that any functions that are recording observations will see that this object is a dependency.
*/
Observation.add = function (obj, event) {
var top = observationStack[observationStack.length-1];
if (top && !top.ignore) {
var evStr = event + "",
name = obj._cid + '|' + evStr;
Expand All @@ -252,33 +280,28 @@ ObservedInfo.observe = function (obj, event) {
}
};


ObservedInfo.trap = function(){
if (observedInfoStack.length) {
var top = observedInfoStack[observedInfoStack.length-1];
var oldTraps = top.traps;
var traps = top.traps = [];
return function(){
top.traps = oldTraps;
return traps;
};
} else {
return function(){return [];};
}
};
ObservedInfo.trapsCount = function(){
if (observedInfoStack.length) {
var top = observedInfoStack[observedInfoStack.length-1];
return top.traps.length;
} else {
return 0;
}
};
// sets an array of observable notifications on the current top of the observe stack.

ObservedInfo.observes = function(observes){
// a bit more optimized so we don't have to repeat everything in can.__observe
var top = observedInfoStack[observedInfoStack.length-1];
/**
* @function Observation.addAll observes
* @signature `Observation.addAll(observes)`
*
* The same as `Observation.add` but takes an array of [observed] objects.
* This will most often by used in coordination with [Observation.trap]:
*
* ```js
* var untrap = Observation.trap();
*
* Observation.add(obj, "prop3");
*
* var traps = untrap();
* Oservation.addAll(traps);
* ```
*
* @param {Array<observed>} observes An array of [observed]s.
*/
Observation.addAll = function(observes){
// a bit more optimized so we don't have to repeat everything in
// Observation.add
var top = observationStack[observationStack.length-1];
if (top) {
if(top.traps) {
top.traps.push.apply(top.traps, observes);
Expand All @@ -296,19 +319,32 @@ ObservedInfo.observes = function(observes){
}
};

// ### can.__isRecordingObserves
// Returns if some function is in the process of recording observes.
ObservedInfo.isRecording = function(){
var len = observedInfoStack.length;
return len && (observedInfoStack[len-1].ignore === 0);
};

// ### can.__notObserve
// Protects a function from being observed.
ObservedInfo.notObserve = function(fn){
/**
* @function Observation.ignore notObserve
* @signature `Observation.ignore(fn)`
*
* Creates a function that, when called, will prevent observations from
* being applied.
*
* ```js
* var fn = Observation.ignore(function(){
* // This will be ignored
* Observation.add(obj, "prop1");
* });
*
* fn();
* Observation.trapCount(); // -> 0
* ```
*
* @param {Function} fn Any function that contains potential calls to
* [Observation.add].
*
* @return {Function} A function that is free of observation side-effects.
*/
Observation.ignore = function(fn){
return function(){
if (observedInfoStack.length) {
var top = observedInfoStack[observedInfoStack.length-1];
if (observationStack.length) {
var top = observationStack[observationStack.length-1];
top.ignore++;
var res = fn.apply(this, arguments);
top.ignore--;
Expand All @@ -319,6 +355,63 @@ ObservedInfo.notObserve = function(fn){
};
};

canBatch._onDispatchedEvents = ObservedInfo.batchEnd;

module.exports = namespace.ObservedInfo = ObservedInfo;
/**
* @function Observation.trap trap
* @signature `Observation.trap()`
*
* Trap all observations until the `untrap` function is called. The state of
* traps prior to `Observation.trap()` will be restored when `untrap()` is called.
*
* ```js
* var untrap = Observation.trap();
*
* Observation.add(obj, "prop1");
*
* var traps = untrap();
* console.log(traps[0].obj === obj); // -> true
* ```
*
* @return {Function} A function to untrap the current observations.
*/
Observation.trap = function(){
if (observationStack.length) {
var top = observationStack[observationStack.length-1];
var oldTraps = top.traps;
var traps = top.traps = [];
return function(){
top.traps = oldTraps;
return traps;
};
} else {
return function(){return [];};
}
};

Observation.trapsCount = function(){
if (observationStack.length) {
var top = observationStack[observationStack.length-1];
return top.traps.length;
} else {
return 0;
}
};
// sets an array of observable notifications on the current top of the observe stack.

/**
* @function Observation.isRecording isRecording
*
* @signature `Observation.isRecording()`
*
* Returns if some function is in the process of recording observes.
*
* @return {Boolean} True if a function is in the process of recording observes.
*/
Observation.isRecording = function(){
var len = observationStack.length;
return len && (observationStack[len-1].ignore === 0);
};

canBatch._onDispatchedEvents = Observation.batchEnd;

module.exports = namespace.Observation = Observation;
41 changes: 41 additions & 0 deletions can-observation_test.js
@@ -0,0 +1,41 @@
require("./reader/reader_test");

var Observation = require('can-observation');
var QUnit = require('steal-qunit');
var CID = require('can-util/js/cid/cid');

var assign = require("can-util/js/assign/assign");
var canEvent = require('can-event');

QUnit.module('can-observation');

QUnit.test('nested traps are reset onto parent traps', function() {
var obs1 = assign({}, canEvent);
CID(obs1);
var obs2 = assign({}, canEvent);
CID(obs2);

var oi = new Observation(function() {

var getObserves1 = Observation.trap();

Observation.add(obs1, "prop1");

var getObserves2 = Observation.trap();
Observation.add(obs2, "prop2");

var observes2 = getObserves2();

Observation.addAll(observes2);

var observes1 = getObserves1();

equal(observes1.length, 2, "two items");
equal(observes1[0].obj, obs1);
equal(observes1[1].obj, obs2);
}, null, function() {

});

oi.getValueAndBind();
});
5 changes: 0 additions & 5 deletions can-observe-info.md

This file was deleted.

0 comments on commit 3c2d1cd

Please sign in to comment.