Skip to content

Commit

Permalink
Restructure streams to be more static
Browse files Browse the repository at this point in the history
  • Loading branch information
wycats committed Sep 3, 2015
1 parent 8719022 commit 6963750
Show file tree
Hide file tree
Showing 28 changed files with 403 additions and 316 deletions.
2 changes: 1 addition & 1 deletion ember-cli-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function babelConfigFor(environment) {

if (isProduction) {
plugins.push(filterImports({
'ember-metal/debug': ['assert', 'debug', 'deprecate', 'info', 'runInDebug', 'warn']
'ember-metal/debug': ['assert', 'debug', 'deprecate', 'info', 'runInDebug', 'warn', 'debugSeal']
}));
}

Expand Down
4 changes: 4 additions & 0 deletions packages/ember-debug/lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ setDebugFunction('runInDebug', function runInDebug(func) {
func();
});

setDebugFunction('debugSeal', function debugSeal(obj) {
Object.seal(obj);
});

setDebugFunction('deprecate', _deprecate);
setDebugFunction('warn', _warn);
/**
Expand Down
4 changes: 2 additions & 2 deletions packages/ember-htmlbars/lib/hooks/bind-local.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@submodule ember-htmlbars
*/

import Stream from 'ember-metal/streams/stream';
import { wrap } from 'ember-metal/streams/stream';
import ProxyStream from 'ember-metal/streams/proxy-stream';

export default function bindLocal(env, scope, key, value) {
Expand All @@ -14,7 +14,7 @@ export default function bindLocal(env, scope, key, value) {
existing.setSource(value);
}
} else {
let newValue = Stream.wrap(value, ProxyStream, key);
let newValue = wrap(value, ProxyStream, key);
scope.bindLocal(key, newValue);
}
}
20 changes: 15 additions & 5 deletions packages/ember-htmlbars/lib/hooks/bind-self.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@submodule ember-htmlbars
*/

import _Ember from 'ember-metal';
import ProxyStream from 'ember-metal/streams/proxy-stream';

export default function bindSelf(env, scope, _self) {
Expand All @@ -12,12 +13,19 @@ export default function bindSelf(env, scope, _self) {
let { controller } = self;
self = self.self;

scope.bindLocal('controller', newStream(controller || self));
if (!!_Ember.ENV._LEGACY_CONTROLLER_SUPPORT) {
scope.bindLocal('controller', newStream(controller || self));
}
}

if (self && self.isView) {
scope.bindLocal('view', newStream(self, 'view'));
scope.bindLocal('controller', newStream(self, '').getKey('controller'));
if (!!_Ember.ENV._LEGACY_VIEW_SUPPORT) {
scope.bindLocal('view', newStream(self, 'view'));
}

if (!!_Ember.ENV._LEGACY_CONTROLLER_SUPPORT) {
scope.bindLocal('controller', newStream(self, '').getKey('controller'));
}

let selfStream = newStream(self, '');

Expand All @@ -33,8 +41,10 @@ export default function bindSelf(env, scope, _self) {
let selfStream = newStream(self, '');
scope.bindSelf(selfStream);

if (!scope.hasLocal('controller')) {
scope.bindLocal('controller', selfStream);
if (!!_Ember.ENV.LEGACY_CONTROLLER_SUPPORT) {
if (!scope.hasLocal('controller')) {
scope.bindLocal('controller', selfStream);
}
}
}

Expand Down
21 changes: 16 additions & 5 deletions packages/ember-htmlbars/lib/hooks/create-fresh-scope.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ProxyStream from 'ember-metal/streams/proxy-stream';
import EmptyObject from 'ember-metal/empty_object';

/*
Ember's implementation of HTMLBars creates an enriched scope.
Expand Down Expand Up @@ -50,13 +51,13 @@ import ProxyStream from 'ember-metal/streams/proxy-stream';

function Scope(parent) {
this._self = null;
this._blocks = {};
this._blocks = null;
this._component = null;
this._view = null;
this._attrs = null;
this._locals = {};
this._localPresent = {};
this.overrideController = false;
this._locals = null;
this._localPresent = null;
this.overrideController = null;
this.parent = parent;
}

Expand All @@ -81,14 +82,17 @@ proto.updateSelf = function(self, key) {
};

proto.getBlock = function(name) {
if (!this._blocks) { return this.parent.getBlock(name); }
return this._blocks[name] || this.parent.getBlock(name);
};

proto.hasBlock = function(name) {
if (!this._blocks) { return this.parent.hasBlock(name); }
return !!(this._blocks[name] || this.parent.hasBlock(name));
};

proto.bindBlock = function(name, block) {
if (!this._blocks) { this._blocks = new EmptyObject(); }
this._blocks[name] = block;
};

Expand Down Expand Up @@ -117,18 +121,25 @@ proto.bindAttrs = function(attrs) {
};

proto.hasLocal = function(name) {
if (!this._localPresent) { return this.parent.hasLocal(name); }
return this._localPresent[name] || this.parent.hasLocal(name);
};

proto.hasOwnLocal = function(name) {
return this._localPresent[name];
return this._localPresent && this._localPresent[name];
};

proto.getLocal = function(name) {
if (!this._localPresent) { return this.parent.getLocal(name); }
return this._localPresent[name] ? this._locals[name] : this.parent.getLocal(name);
};

proto.bindLocal = function(name, value) {
if (!this._localPresent) {
this._localPresent = new EmptyObject();
this._locals = new EmptyObject();
}

this._localPresent[name] = true;
this._locals[name] = value;
};
Expand Down
2 changes: 1 addition & 1 deletion packages/ember-htmlbars/lib/hooks/did-render-node.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export default function didRenderNode(morph, env) {
env.renderedNodes[morph.guid] = true;
env.renderedNodes.add(morph);
}
149 changes: 75 additions & 74 deletions packages/ember-htmlbars/lib/keywords/get.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
*/

import { assert } from 'ember-metal/debug';
import Stream from 'ember-metal/streams/stream';
import BasicStream from 'ember-metal/streams/stream';
import KeyStream from 'ember-metal/streams/key-stream';
import { isStream } from 'ember-metal/streams/utils';
import merge from 'ember-metal/merge';
import subscribe from 'ember-htmlbars/utils/subscribe';
import { get } from 'ember-metal/property_get';
import { set } from 'ember-metal/property_set';
Expand All @@ -22,17 +21,90 @@ function labelFor(source, key) {
return `(get ${sourceLabel} ${keyLabel})`;
}

let DynamicKeyStream = BasicStream.extend({
init(source, keySource) {
assert('DynamicKeyStream error: source must be a stream', isStream(source)); // TODO: This isn't necessary.

// used to get the original path for debugging and legacy purposes
var label = labelFor(source, keySource);

this.label = label;
this.path = label;
this.sourceDep = this.addMutableDependency(source);
this.keyDep = this.addMutableDependency(keySource);
this.observedObject = null;
this.observedKey = null;
},

key() {
const key = this.keyDep.getValue();
if (typeof key === 'string') {
assert('DynamicKeyStream error: key must not have a \'.\'', key.indexOf('.') === -1);
return key;
}
},

compute() {
var object = this.sourceDep.getValue();
var key = this.key();
if (object && key) {
return get(object, key);
}
},

setValue(value) {
var object = this.sourceDep.getValue();
var key = this.key();
if (object) {
set(object, key, value);
}
},

_super$revalidate: BasicStream.prototype.revalidate,

revalidate(value) {
this._super$revalidate(value);

var object = this.sourceDep.getValue();
var key = this.key();
if (object !== this.observedObject || key !== this.observedKey) {
this._clearObservedObject();

if (object && typeof object === 'object' && key) {
addObserver(object, key, this, this.notify);
this.observedObject = object;
this.observedKey = key;
}
}
},

_clearObservedObject() {
if (this.observedObject) {
removeObserver(this.observedObject, this.observedKey, this, this.notify);
this.observedObject = null;
this.observedKey = null;
}
}
});

const buildStream = function buildStream(params) {
const [objRef, pathRef] = params;

assert('The first argument to {{get}} must be a stream', isStream(objRef));
assert('{{get}} requires at least two arguments', params.length > 1);

const stream = new DynamicKeyStream(objRef, pathRef);
const stream = buildDynamicKeyStream(objRef, pathRef);

return stream;
};

function buildDynamicKeyStream(source, keySource) {
if (!isStream(keySource)) {
return new KeyStream(source, keySource);
} else {
return new DynamicKeyStream(source, keySource);
}
}

/**
Dynamically look up a property on an object. The second argument to `{{get}}`
Expand Down Expand Up @@ -97,75 +169,4 @@ var getKeyword = function getKeyword(morph, env, scope, params, hash, template,
return true;
};

var DynamicKeyStream = function DynamicKeyStream(source, keySource) {
if (!isStream(keySource)) {
return new KeyStream(source, keySource);
}
assert('DynamicKeyStream error: source must be a stream', isStream(source)); // TODO: This isn't necessary.

// used to get the original path for debugging and legacy purposes
var label = labelFor(source, keySource);

this.init(label);
this.path = label;
this.sourceDep = this.addMutableDependency(source);
this.keyDep = this.addMutableDependency(keySource);
this.observedObject = null;
this.observedKey = null;
};

DynamicKeyStream.prototype = Object.create(KeyStream.prototype);

merge(DynamicKeyStream.prototype, {
key() {
const key = this.keyDep.getValue();
if (typeof key === 'string') {
assert('DynamicKeyStream error: key must not have a \'.\'', key.indexOf('.') === -1);
return key;
}
},

compute() {
var object = this.sourceDep.getValue();
var key = this.key();
if (object && key) {
return get(object, key);
}
},

setValue(value) {
var object = this.sourceDep.getValue();
var key = this.key();
if (object) {
set(object, key, value);
}
},

_super$revalidate: Stream.prototype.revalidate,

revalidate(value) {
this._super$revalidate(value);

var object = this.sourceDep.getValue();
var key = this.key();
if (object !== this.observedObject || key !== this.observedKey) {
this._clearObservedObject();

if (object && typeof object === 'object' && key) {
addObserver(object, key, this, this.notify);
this.observedObject = object;
this.observedKey = key;
}
}
},

_clearObservedObject() {
if (this.observedObject) {
removeObserver(this.observedObject, this.observedKey, this, this.notify);
this.observedObject = null;
this.observedKey = null;
}
}
});

export default getKeyword;
Loading

0 comments on commit 6963750

Please sign in to comment.