Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
feat: add decorator syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
btford committed Mar 29, 2014
1 parent 81d5f49 commit c6202a1
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 56 deletions.
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ someZone.fork({

### Augmenting A Zone's Hook

When you fork a zone, you'll often want to control how the parent zone's
hook gets called.

Prefixing a hook with `$` means that the hook will be passed the
parent zone's hook, and the hook will be expected to return the function to
be invoked rather than be the function itself.

```javascript
var someZone = zone.fork({
onZoneLeave: function () {
Expand All @@ -121,8 +128,36 @@ var someZone = zone.fork({
});

someZone.fork({
$onZoneLeave: function (parentOnLeave) {
// return the hook
return function onZoneLeave() {
parentOnLeave();
console.log('cya l8r');
};
}
}).run(function () {
// do stuff
});

// logs: goodbye
// cya l8r
```

#### `+` and `-` Sugar
Most of the time, you'll want to run a hook before or after the parent's implementation.
You can prefix a hook with `-` for running before, and `+` for running after.

The above can be written like this:

```javascript
var someZone = zone.fork({
onZoneLeave: function () {
this.parent.onZoneLeave();
console.log('goodbye');
}
});

someZone.fork({
'+onZoneLeave': function (parentOnLeave) {
console.log('cya l8r');
}
}).run(function () {
Expand All @@ -133,6 +168,8 @@ someZone.fork({
// cya l8r
```

This frees you from writing boilerplate to compose a new hook.

## API

Zone.js exports a single object: `window.zone`.
Expand Down Expand Up @@ -166,6 +203,10 @@ myZone.run(function () {

Below describes the behavior of each of these hooks.

### `zone.onZoneCreated`

Runs when a zone is forked.

### `zone.onZoneEnter`

Before a function invoked with `zone.run`, this hook runs.
Expand Down
21 changes: 21 additions & 0 deletions counting-zone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* See example/counting.html
*/
zone.countingZone = {
'-onZoneCreated': function () {
zone.countingZone.counter += 1;
},
'+onZoneLeave': function () {
zone.countingZone.counter -= 1;
if (zone.countingZone.counter === 0) {
this.onFlush();
}
},
reset: function () {
zone.countingZone.counter = 0;
},
counter: function () {
return zone.countingZone.counter;
},
onFlush: function () {}
};
67 changes: 20 additions & 47 deletions example/counting.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<title>Counting Pending Tasks</title>
<link rel="stylesheet" href="style.css">
<script src="../zone.js"></script>
<script src="../long-stack-trace-zone.js"></script>
<script src="../counting-zone.js"></script>
</head>
<body>

Expand All @@ -26,59 +26,32 @@ <h1>Counting Pending Tasks</h1>
/*
* Zone that counts pending async tasks
*/
var countingZone = (function () {
var count = 0,
start;
return {
_wrap: function (fn) {
return function () {
var ret = fn.apply(this, arguments);
count -= 1;
zone._print();
return ret;
};
},

_print: function () {
output.innerHTML = 'pending task count: ' + count +
(count === 0 ? (' DONE! ' + (Date.now() - start)/1000 + 's') : '');
},

reset: function () {
start = 0;
},

run: function () {
if (!start) {
start = Date.now();
}
return zone.run.apply(this, arguments);
},


onError: function (e) {
console.log(e.stack);
},

setTimeout: function () {
count += 1;
zone._print();
arguments[0] = zone._wrap(arguments[0]);
return zone._setTimeout.apply(this, arguments);
},

_setTimeout: zone.setTimeout
};
}());

var myCountingZone = zone.fork(zone.countingZone).fork({
'+onZoneCreated': function () {
zone.countingZone.start || (zone.countingZone.start = Date.now());
this.print();
},
'-onZoneLeave': function (delegate) {
this.print();
},
'+reset': function (delegate) {
zone.countingZone.start = 0;
},
print: function () {
counter = this.counter();
output.innerHTML = counter ?
'pending task count: ' + counter :
' DONE! ' + (Date.now() - zone.countingZone.start)/1000 + 's';
}
});

/*
* We want to profile just the actions that are a result of this button, so with
* a single line of code, we can run `main` in the countingZone
*/

b1.addEventListener('click', function () {
zone.fork(countingZone).run(main);
myCountingZone.run(main);
});


Expand Down
8 changes: 1 addition & 7 deletions test/zone.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,7 @@ describe('Zone.patch', function () {
expect(leaveSpy).toHaveBeenCalled();
});

it('should throw if onError is not defined', function () {
expect(function () {
zone.run(throwError);
}).toThrow();
});

it('should fire onZoneCreeated when a zone is forked', function () {
it('should fire onZoneCreated when a zone is forked', function () {
var createdSpy = jasmine.createSpy();
var counter = 0;
var myZone = zone.fork({
Expand Down
35 changes: 34 additions & 1 deletion zone.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,40 @@ function Zone(parentZone, data) {
zone.parent = parentZone;

Object.keys(data || {}).forEach(function(property) {
zone[property] = data[property];

var _property = property.substr(1);

// augment the new zone with a hook decorates the parent's hook
if (property[0] === '$') {
zone[_property] = data[property](parentZone[_property] || function () {});

// augment the new zone with a hook that runs after the parent's hook
} else if (property[0] === '+') {
if (parentZone[_property]) {
zone[_property] = function () {
var result = parentZone[_property].apply(this, arguments);
data[property].apply(this, arguments);
return result;
};
} else {
zone[_property] = data[property];
}

// augment the new zone with a hook that runs before the parent's hook
} else if (property[0] === '-') {
if (parentZone[_property]) {
zone[_property] = function () {
data[property].apply(this, arguments);
return parentZone[_property].apply(this, arguments);
};
} else {
zone[_property] = data[property];
}

// set the new zone's hook (replacing the parent zone's)
} else {
zone[property] = data[property];
}
});

return zone;
Expand Down

0 comments on commit c6202a1

Please sign in to comment.