Permalink
Browse files

[core, drinker, tests] added waitFor method, improved drinker, fixed …

…test
  • Loading branch information...
1 parent d50bff7 commit 2f8f25247e58fddb8e6cddbbb14c509f31eaf211 @indutny committed Jun 18, 2011
Showing with 129 additions and 24 deletions.
  1. +77 −22 lib/bar/core.js
  2. +37 −1 lib/bar/drinker.js
  3. +14 −0 lib/bar/utils.js
  4. +1 −1 tests/bar-basic-test.js
View
@@ -21,16 +21,26 @@ function Bar(dir, options) {
* Drinkers in a Bar
*/
this.drinkers = {};
+ this.drinkersByName = {};
+
+ /**
+ * Wait list for drinkers
+ */
+ this.waitList = {};
/**
* Store options
*/
this.options = options = bar.utils.merge({
- drinker: {
- }
+ EventEmitter: require('eventemitter2').EventEmitter2
}, options);
/**
+ * Pool for all pints
+ */
+ this.pool = new options.EventEmitter();
+
+ /**
* Monitor file changes in directory
*/
watch.watchTree(dir, function(f, curr, prev) {
@@ -64,30 +74,42 @@ Bar.prototype.enter = function(drinkers) {
var that = this;
drinkers.forEach(function(file) {
- /**
- * Load each file
- */
- fs.readFile(file, function(err, content) {
- if (err) {
- that.log('Failed to load file %s', file, err);
- return;
- };
-
+ fs.stat(file, function(err, stat) {
+ if (!stat.isFile()) return;
/**
- * Convert content from Buffer to String
+ * Load each file
*/
- content = content.toString();
+ fs.readFile(file, function(err, content) {
+ if (err) {
+ that.log('Failed to load file %s', file, err);
+ return;
+ };
- /**
- * If that drinker was already here
- * Kick him out and let one come in
- */
- if (that.drinkers[file]) {
- that.drinkers[file].emit('kick');
- }
+ /**
+ * Convert content from Buffer to String
+ */
+ content = content.toString();
+
+ /**
+ * If that drinker was already here
+ * Kick him out and let one come in
+ */
+ that.leave(file);
+
+ var drinker = bar.drinker.create(file, content, that);
+ that.drinkers[drinker.name] = that.drinkers[file] = drinker;
+
+ /**
+ * Welcome drinker!
+ */
+ drinker.emit('enter.' + drinker.name);
- that.drinkers[file] = bar.drinker.create(file, content,
- that.options.drinker);
+ /**
+ * Notify waiters about new drinker
+ */
+ that.notifyWaiters(drinker.name);
+ that.notifyWaiters(file);
+ });
});
});
};
@@ -96,6 +118,39 @@ Bar.prototype.enter = function(drinkers) {
* Remove file
*/
Bar.prototype.leave = function(drinker) {
+ if (this.drinkers[drinker]) {
+ var name = this.drinkers[drinker].name;
+ this.drinkers[name].pint.emit('kicked.' + name);
+
+ /**
+ * Remove drinkers by name and filename from hashmap
+ */
+ this.drinkers[drinker] = this.drinkers[name] = null;
+ }
+};
+
+/**
+ * Wait for drinker to enter bar
+ */
+Bar.prototype.waitFor = function(name, callback) {
+ if (this.drinkers[name]) return process.nextTick(callback);
+
+ /**
+ * Add callback to waitList
+ */
+ var waitList = this.waitList[name] || (this.waitList[name] = []);
+ waitList.push(callback);
+};
+
+/**
+ * Notify waiters about new drinker
+ */
+Bar.prototype.notifyWaiters = function(name) {
+ if (!this.waitList[name]) return;
+ this.waitList[name].forEach(function(fn) {
+ fn();
+ });
+ this.waitList[name] = null;
};
/**
View
@@ -11,8 +11,44 @@ var bar = require('../bar');
/**
* Drinker @constructor
*/
-function Drinker(file, content, options) {
+function Drinker(file, content, bar) {
this.file = file;
+ this.pint = bar.pool;
+
+ var that = this;
+
+ vm.runInNewContext(content, utils.saturate({
+ /**
+ * Tunnel drinker's require to global
+ */
+ require: function() {
+ require.apply(null, arguments);
+ },
+
+ /**
+ * Introduce drinker to bar
+ */
+ name: function(name) {
+ if (that.name) {
+ bar.log('Can\'t change name drinker: %s', that.name);
+ return;
+ }
+ that.name = name;
+ },
+
+ /**
+ * Wait for drinker to enter bar
+ */
+ waitFor: function(name, callback) {
+ bar.waitFor(name, callback);
+ }
+ }, this.pint), file);
+
+ /**
+ * Give a unique initial name to drinker
+ * if he doesn't have one
+ */
+ this.name || (this.name = +new Date + ':' + ~~(Math.random() * 1e9));
};
drinker.Drinker = Drinker;
View
@@ -39,3 +39,17 @@ function merge(a, b) {
return c;
};
utils.merge = merge;
+
+/**
+ * Saturate object with binding saturator methods
+ */
+function saturate(obj, saturator) {
+ for (var i in saturator) {
+ if (typeof saturator[i] === 'function') {
+ obj[i] = saturator[i].bind(saturator);
+ }
+ };
+
+ return obj;
+};
+utils.saturate = saturate;
@@ -6,7 +6,7 @@ var bar = require('../lib/bar');
vows.describe('Bar').addBatch({
'Calling bar.create()': {
topic: function() {
- bar.create(__dirname + '/data');
+ return bar.create(__dirname + '/data');
},
'should create bar.Bar instance': function(I) {
assert.instanceOf(I, bar.Bar);

0 comments on commit 2f8f252

Please sign in to comment.