Skip to content

Commit

Permalink
remove context binding related stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
Evan You committed Oct 17, 2013
1 parent 810c584 commit af342b7
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 134 deletions.
5 changes: 3 additions & 2 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module.exports = function( grunt ) {
},

jshint: {
build: {
dev: {
src: ['src/**/*.js'],
options: {
jshintrc: './.jshintrc'
Expand Down Expand Up @@ -90,8 +90,9 @@ module.exports = function( grunt ) {
grunt.loadNpmTasks( 'grunt-mocha' )
grunt.registerTask( 'test', ['component_build:test', 'mocha'] )
grunt.registerTask( 'default', [
'jshint',
'jshint:dev',
'component_build:build',
'jshint:test',
'test',
'uglify'
])
Expand Down
2 changes: 1 addition & 1 deletion examples/simple.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<script src="../dist/seed.js"></script>
</head>
<body>
<input type="checkbox" sd-checked="checked">
<input type="checkbox" sd-model="checked">
<span sd-text="hello.msg | uppercase" sd-class="red:checked"></span>
<h1 sd-if="checked">Now you see me</h1>
<script>
Expand Down
18 changes: 3 additions & 15 deletions src/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ function Compiler (vm, options) {
// because we want to have created all bindings before
// observing values / parsing dependencies.
var observables = compiler.observables = [],
computed = compiler.computed = [],
ctxBindings = compiler.ctxBindings = []
computed = compiler.computed = []

// prototypal inheritance of bindings
var parent = compiler.parentCompiler
Expand Down Expand Up @@ -100,10 +99,8 @@ function Compiler (vm, options) {
}
// extract dependencies for computed properties
if (computed.length) DepsParser.parse(computed)
// extract dependencies for computed properties with dynamic context
if (ctxBindings.length) compiler.bindContexts(ctxBindings)
// unset these no longer needed stuff
compiler.observables = compiler.computed = compiler.ctxBindings = compiler.arrays = null
compiler.observables = compiler.computed = compiler.arrays = null
}

var CompilerProto = Compiler.prototype
Expand Down Expand Up @@ -457,13 +454,7 @@ CompilerProto.define = function (key, binding) {
ob.emit('get', key)
}
return binding.isComputed
? value.get({
el: compiler.el,
vm: vm,
item: compiler.repeat
? vm[compiler.repeatPrefix]
: null
})
? value.get()
: value
},
set: function (newVal) {
Expand Down Expand Up @@ -493,9 +484,6 @@ CompilerProto.markComputed = function (binding) {
var value = binding.value,
vm = this.vm
binding.isComputed = true
// keep a copy of the raw getter
// for extracting contextual dependencies
binding.rawGet = value.get
// bind the accessors to the vm
value.get = value.get.bind(vm)
if (value.set) value.set = value.set.bind(vm)
Expand Down
75 changes: 3 additions & 72 deletions src/deps-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,9 @@ var Emitter = require('./emitter'),
utils = require('./utils'),
observer = new Emitter()

var dummyEl = document.createElement('div'),
ARGS_RE = /^function\s*?\((.+?)[\),]/,
SCOPE_RE_STR = '\\.vm\\.[\\.\\w][\\.\\w$]*',
noop = function () {}

/*
* Auto-extract the dependencies of a computed property
* by recording the getters triggered when evaluating it.
*
* However, the first pass will contain duplicate dependencies
* for computed properties. It is therefore necessary to do a
* second pass in injectDeps()
*/
function catchDeps (binding) {
utils.log('\n─ ' + binding.key)
Expand All @@ -25,67 +16,10 @@ function catchDeps (binding) {
binding.deps.push(dep)
dep.subs.push(binding)
})
parseContextDependency(binding)
binding.value.get({
vm: createDummyVM(binding),
el: dummyEl
})
binding.value.get()
observer.off('get')
}

/*
* We need to invoke each binding's getter for dependency parsing,
* but we don't know what sub-viewmodel properties the user might try
* to access in that getter. To avoid thowing an error or forcing
* the user to guard against an undefined argument, we staticly
* analyze the function to extract any possible nested properties
* the user expects the target viewmodel to possess. They are all assigned
* a noop function so they can be invoked with no real harm.
*/
function createDummyVM (binding) {
var viewmodel = {},
deps = binding.contextDeps
if (!deps) return viewmodel
var i = binding.contextDeps.length,
j, level, key, path
while (i--) {
level = viewmodel
path = deps[i].split('.')
j = 0
while (j < path.length) {
key = path[j]
if (!level[key]) level[key] = noop
level = level[key]
j++
}
}
return viewmodel
}

/*
* Extract context dependency paths
*/
function parseContextDependency (binding) {
var fn = binding.rawGet,
str = fn.toString(),
args = str.match(ARGS_RE)
if (!args) return null
var depsRE = new RegExp(args[1] + SCOPE_RE_STR, 'g'),
matches = str.match(depsRE),
base = args[1].length + 4
if (!matches) return null
var i = matches.length,
deps = [], dep
while (i--) {
dep = matches[i].slice(base)
if (deps.indexOf(dep) === -1) {
deps.push(dep)
}
}
binding.contextDeps = deps
binding.compiler.contextBindings.push(binding)
}

module.exports = {

/*
Expand All @@ -102,9 +36,6 @@ module.exports = {
bindings.forEach(catchDeps)
observer.isObserving = false
utils.log('\ndone.')
},

// for testing only
cdvm: createDummyVM,
pcd: parseContextDependency
}

}
76 changes: 32 additions & 44 deletions test/unit/specs/deps-parser.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,44 @@
/*
* NOTE
*
* this suite only tests two utility methods used in the
* Dependency Parser, but does not test the main .parse()
* method. .parse() is covered in integration tests because
* it has to work with multiple compilers.
*/

var DepsParser = require('seed/src/deps-parser')

describe('UNIT: Dependency Parser', function () {

describe('.parseContextDependency()', function () {

var binding = {
rawGet: function (ctx) {
return ctx.vm.a + ctx.vm.a + ctx.vm.b.c
},
compiler: {
contextBindings: []
}
}
DepsParser.pcd(binding)

it('should not contain duplicate entries', function () {
assert.strictEqual(binding.contextDeps.length, 2)
})
describe('.parse()', function () {

it('should extract correct context dependencies from a getter', function () {
assert.strictEqual(binding.contextDeps[0], 'b.c')
assert.strictEqual(binding.contextDeps[1], 'a')
})
// mock the bidnings...
var bindings = [],
ob = DepsParser.observer
for (var i = 0; i < 10; i++) {
mockBinding(i)
}

it('should add the binding to its compiler\'s contextBindings', function () {
assert.ok(binding.compiler.contextBindings.indexOf(binding) !== -1)
})
function mockBinding (i) {
var b = {
id: i,
depId: ~~(Math.random() * i),
deps: [],
subs: [],
value: {
get: function () {
if (i > 0) {
ob.emit('get', bindings[b.depId])
}
}
}
}
bindings.push(b)
}

})
DepsParser.parse(bindings)

describe('.createDummyVM()', function () {
it('should parse the deps correctly', function () {

bindings.forEach(function (b) {
if (b.id === 0) return
var dep = b.deps[0]
assert.strictEqual(dep.id, b.depId)
assert.ok(dep.subs.indexOf(b) > -1)
})

var createDummyVM = DepsParser.cdvm,
binding = {
contextDeps: ['a.b', 'a.b.c', 'b']
}

it('should create a dummy VM that has all context dep paths', function () {
var vm = createDummyVM(binding)
assert.ok('a' in vm)
assert.ok('b' in vm)
assert.ok('b' in vm.a)
assert.ok('c' in vm.a.b)
})

})
Expand Down

0 comments on commit af342b7

Please sign in to comment.