Просмотр исходного кода

Collect dependencies on all types

Previously dependencies (get events) are only collected from
tip values - this prevents objects being collected as dependency.
The issue in #178 is that the user begins a value as non-object,
but has a binding somewhere that indicates the value can be an object
later. The observer converts the value to an object implicitly,
causing expressions not picking it up as dependency. This change
makes the observer emit get events regardless of type.

Also utils.set and get have been fixed to check for both null
and undefined.
Evan You 12 лет назад
Родитель
Сommit
f3af9599ce
5 измененных файлов с 44 добавлено и 36 удалено
  1. 9 1
      src/deps-parser.js
  2. 1 1
      src/observer.js
  3. 4 2
      src/utils.js
  4. 1 0
      test/unit/specs/deps-parser.js
  5. 29 32
      test/unit/specs/observer.js

+ 9 - 1
src/deps-parser.js

@@ -14,7 +14,15 @@ function catchDeps (binding) {
     binding.deps = []
     catcher.on('get', function (dep) {
         var has = got[dep.key]
-        if (has && has.compiler === dep.compiler) return
+        if (
+            // avoid duplicate bindings
+            (has && has.compiler === dep.compiler) ||
+            // avoid repeated items as dependency
+            // since all inside changes trigger array change too
+            (dep.compiler.repeat && dep.compiler.parent === binding.compiler)
+        ) {
+            return
+        }
         got[dep.key] = dep
         utils.log('  - ' + dep.key)
         binding.deps.push(dep)

+ 1 - 1
src/observer.js

@@ -287,7 +287,7 @@ function convertKey (obj, key) {
         get: function () {
             var value = values[key]
             // only emit get on tip values
-            if (pub.shouldGet && typeOf(value) !== OBJECT) {
+            if (pub.shouldGet) {
                 emitter.emit('get', key)
             }
             return value

+ 4 - 2
src/utils.js

@@ -13,12 +13,13 @@ var utils = module.exports = {
      *  get a value from an object keypath
      */
     get: function (obj, key) {
+        /* jshint eqeqeq: false */
         if (key.indexOf('.') < 0) {
             return obj[key]
         }
         var path = key.split('.'),
             d = -1, l = path.length
-        while (++d < l && obj !== undefined) {
+        while (++d < l && obj != null) {
             obj = obj[path[d]]
         }
         return obj
@@ -28,6 +29,7 @@ var utils = module.exports = {
      *  set a value to an object keypath
      */
     set: function (obj, key, val) {
+        /* jshint eqeqeq: false */
         if (key.indexOf('.') < 0) {
             obj[key] = val
             return
@@ -35,7 +37,7 @@ var utils = module.exports = {
         var path = key.split('.'),
             d = -1, l = path.length - 1
         while (++d < l) {
-            if (obj[path[d]] === undefined) {
+            if (obj[path[d]] == null) {
                 obj[path[d]] = {}
             }
             obj = obj[path[d]]

+ 1 - 0
test/unit/specs/deps-parser.js

@@ -17,6 +17,7 @@ describe('Dependency Parser', function () {
                 depId: ~~(Math.random() * i),
                 deps: [],
                 subs: [],
+                compiler: {},
                 value: {
                     $get: function () {
                         if (i > 0) {

+ 29 - 32
test/unit/specs/observer.js

@@ -42,16 +42,38 @@ describe('Observer', function () {
             path: 'test'
         }))
 
-        it('should emit get events on tip values', function () {
+        it('should emit get events', function () {
             Observer.shouldGet = true
-            getTestFactory({
-                obj: { a: 1, b: { c: 2 } },
-                expects: [
+
+            var ob = new Emitter(),
+                i  = 0,
+                obj = { a: 1, b: { c: 2 } },
+                gets = [
+                    'a',
+                    'b.c'
+                ],
+                expects = [
                     'test.a',
+                    'test.b',
                     'test.b.c'
-                ],
-                path: 'test'
-            })()
+                ]
+            Observer.observe(obj, 'test', ob)
+            ob.on('get', function (key) {
+                var expected = expects[i]
+                assert.strictEqual(key, expected)
+                i++
+            })
+            gets.forEach(function (key) {
+                var path = key.split('.'),
+                    j = 0,
+                    data = obj
+                while (j < path.length) {
+                    data = data[path[j]]
+                    j++
+                }
+            })
+            assert.strictEqual(i, expects.length)
+
             Observer.shouldGet = false
         })
 
@@ -505,29 +527,4 @@ describe('Observer', function () {
         }
     }
 
-    function getTestFactory (opts) {
-        return function () {
-            var ob = new Emitter(),
-                i  = 0,
-                obj = opts.obj,
-                expects = opts.expects
-            Observer.observe(obj, opts.path, ob)
-            ob.on('get', function (key) {
-                var expected = expects[i]
-                assert.strictEqual(key, expected)
-                i++
-            })
-            expects.forEach(function (key) {
-                var path = key.split('.'),
-                    j = 1,
-                    data = obj
-                while (j < path.length) {
-                    data = data[path[j]]
-                    j++
-                }
-            })
-            assert.strictEqual(i, expects.length)
-        }
-    }
-
 })