diff --git a/vendor/gems/message_bus/assets/application.js b/vendor/gems/message_bus/assets/application.js index 6347f926cef..884cff24db0 100644 --- a/vendor/gems/message_bus/assets/application.js +++ b/vendor/gems/message_bus/assets/application.js @@ -9,12 +9,22 @@ window.App.start(); App.IndexRoute = Ember.Route.extend({ setupController: function(controller) { - controller.set('content', App.IndexModel.create()); + model = App.IndexModel.create(); + model.ensureSubscribed(); + controller.set('content', model); } }); -App.IndexView = Ember.View.extend({ - +App.IndexView = Ember.View.extend({}); + +App.Process = Ember.View.extend({ + uniqueId: function(){ + return this.get('hostname') + this.get('pid'); + }.property('hostname', 'pid'), + + hup: function(){ + $.post("/message-bus/_diagnostics/hup/" + this.get('hostname') + "/" + this.get('pid')); + } }); App.IndexModel = Ember.Object.extend({ @@ -22,8 +32,31 @@ App.IndexModel = Ember.Object.extend({ return this.get("discovering") ? "disabled" : null; }.property("discovering"), + ensureSubscribed: function() { + var processes; + var _this = this; + if(this.get("subscribed")) { return; } + + MessageBus.callbackInterval = 500; + MessageBus.subscribe("/_diagnostics/process-discovery", function(data){ + processes = _this.get('processes'); + processes.pushObject(App.Process.create(data)); + processes = processes.sort(function(a,b){ + return a.get('uniqueId') < b.get('uniqueId') ? -1 : 1; + }); + // somewhat odd ... + _this.set('processes', null); + _this.set('processes', processes); + }); + + this.set("subscribed", true); + }, + discover: function(){ var _this = this; + this.set('processes', Em.A()); + + this.ensureSubscribed(); this.set("discovering", true); Ember.run.later(function(){ @@ -31,11 +64,6 @@ App.IndexModel = Ember.Object.extend({ }, 1 * 1000); $.post("/message-bus/_diagnostics/discover"); - - MessageBus.subscribe("/process-discovery", function(data){ - console.log(data); - }); - } }); @@ -43,5 +71,9 @@ App.IndexModel = Ember.Object.extend({ App.IndexController = Ember.ObjectController.extend({ discover: function(){ this.get("content").discover(); + }, + + hup: function(process) { + process.hup(); } }); diff --git a/vendor/gems/message_bus/assets/ember.js b/vendor/gems/message_bus/assets/ember.js index f16bfd4bcb9..e566b10f98b 100644 --- a/vendor/gems/message_bus/assets/ember.js +++ b/vendor/gems/message_bus/assets/ember.js @@ -1,3 +1,159 @@ +// Version: v1.0.0-rc.1 +// Last commit: 8b061b4 (2013-02-15 12:10:22 -0800) + + +(function() { +/*global __fail__*/ + +/** +Ember Debug + +@module ember +@submodule ember-debug +*/ + +/** +@class Ember +*/ + +if ('undefined' === typeof Ember) { + Ember = {}; + + if ('undefined' !== typeof window) { + window.Em = window.Ember = Em = Ember; + } +} + +Ember.ENV = 'undefined' === typeof ENV ? {} : ENV; + +if (!('MANDATORY_SETTER' in Ember.ENV)) { + Ember.ENV.MANDATORY_SETTER = true; // default to true for debug dist +} + +/** + Define an assertion that will throw an exception if the condition is not + met. Ember build tools will remove any calls to `Ember.assert()` when + doing a production build. Example: + + ```javascript + // Test for truthiness + Ember.assert('Must pass a valid object', obj); + // Fail unconditionally + Ember.assert('This code path should never be run') + ``` + + @method assert + @param {String} desc A description of the assertion. This will become + the text of the Error thrown if the assertion fails. + @param {Boolean} test Must be truthy for the assertion to pass. If + falsy, an exception will be thrown. +*/ +Ember.assert = function(desc, test) { + if (!test) throw new Error("assertion failed: "+desc); +}; + + +/** + Display a warning with the provided message. Ember build tools will + remove any calls to `Ember.warn()` when doing a production build. + + @method warn + @param {String} message A warning to display. + @param {Boolean} test An optional boolean. If falsy, the warning + will be displayed. +*/ +Ember.warn = function(message, test) { + if (!test) { + Ember.Logger.warn("WARNING: "+message); + if ('trace' in Ember.Logger) Ember.Logger.trace(); + } +}; + +/** + Display a debug notice. Ember build tools will remove any calls to + `Ember.debug()` when doing a production build. + + ```javascript + Ember.debug("I'm a debug notice!"); + ``` + + @method debug + @param {String} message A debug message to display. +*/ +Ember.debug = function(message) { + Ember.Logger.debug("DEBUG: "+message); +}; + +/** + Display a deprecation warning with the provided message and a stack trace + (Chrome and Firefox only). Ember build tools will remove any calls to + `Ember.deprecate()` when doing a production build. + + @method deprecate + @param {String} message A description of the deprecation. + @param {Boolean} test An optional boolean. If falsy, the deprecation + will be displayed. +*/ +Ember.deprecate = function(message, test) { + if (Ember && Ember.TESTING_DEPRECATION) { return; } + + if (arguments.length === 1) { test = false; } + if (test) { return; } + + if (Ember && Ember.ENV.RAISE_ON_DEPRECATION) { throw new Error(message); } + + var error; + + // When using new Error, we can't do the arguments check for Chrome. Alternatives are welcome + try { __fail__.fail(); } catch (e) { error = e; } + + if (Ember.LOG_STACKTRACE_ON_DEPRECATION && error.stack) { + var stack, stackStr = ''; + if (error['arguments']) { + // Chrome + stack = error.stack.replace(/^\s+at\s+/gm, ''). + replace(/^([^\(]+?)([\n$])/gm, '{anonymous}($1)$2'). + replace(/^Object.\s*\(([^\)]+)\)/gm, '{anonymous}($1)').split('\n'); + stack.shift(); + } else { + // Firefox + stack = error.stack.replace(/(?:\n@:0)?\s+$/m, ''). + replace(/^\(/gm, '{anonymous}(').split('\n'); + } + + stackStr = "\n " + stack.slice(2).join("\n "); + message = message + stackStr; + } + + Ember.Logger.warn("DEPRECATION: "+message); +}; + + + +/** + Display a deprecation warning with the provided message and a stack trace + (Chrome and Firefox only) when the wrapped method is called. + + Ember build tools will not remove calls to `Ember.deprecateFunc()`, though + no warnings will be shown in production. + + @method deprecateFunc + @param {String} message A description of the deprecation. + @param {Function} func The function to be deprecated. +*/ +Ember.deprecateFunc = function(message, func) { + return function() { + Ember.deprecate(message); + return func.apply(this, arguments); + }; +}; + +})(); + +// Version: v1.0.0-rc.1 +// Last commit: 8b061b4 (2013-02-15 12:10:22 -0800) + + (function() { var define, requireModule; @@ -55,7 +211,7 @@ var define, requireModule; @class Ember @static - @version 1.0.0-pre.4 + @version 1.0.0-rc.1 */ if ('undefined' === typeof Ember) { @@ -82,10 +238,10 @@ Ember.toString = function() { return "Ember"; }; /** @property VERSION @type String - @default '1.0.0-pre.4' + @default '1.0.0-rc.1' @final */ -Ember.VERSION = '1.0.0-pre.4'; +Ember.VERSION = '1.0.0-rc.1'; /** Standard environmental variables. You can define these in a global `ENV` @@ -1699,10 +1855,11 @@ get = function get(obj, keyName) { } if (!obj || keyName.indexOf('.') !== -1) { - + Ember.assert("Cannot call get with '"+ keyName +"' on an undefined object.", obj !== undefined); return getPath(obj, keyName); } + Ember.assert("You need to provide an object and key to `get`.", !!obj && keyName); var meta = obj[META_KEY], desc = meta && meta.descs[keyName], ret; if (desc) { @@ -1748,7 +1905,7 @@ get = function get(obj, keyName) { */ set = function set(obj, keyName, value, tolerant) { if (typeof obj === 'string') { - + Ember.assert("Path '" + obj + "' must be global if no obj is given.", IS_GLOBAL.test(obj)); value = keyName; keyName = obj; obj = null; @@ -1758,7 +1915,8 @@ set = function set(obj, keyName, value, tolerant) { return setPath(obj, keyName, value, tolerant); } - + Ember.assert("You need to provide an object and key to `set`.", !!obj && keyName !== undefined); + Ember.assert('calling set on destroyed object', !obj.isDestroyed); var meta = obj[META_KEY], desc = meta && meta.descs[keyName], isUnknown, currentValue; @@ -1992,7 +2150,7 @@ var Descriptor = Ember.Descriptor = function() {}; // var MANDATORY_SETTER_FUNCTION = Ember.MANDATORY_SETTER_FUNCTION = function(value) { - + Ember.assert("You must use Ember.set() to access this property (of " + this + ")", false); }; var DEFAULT_GETTER_FUNCTION = Ember.DEFAULT_GETTER_FUNCTION = function(name) { @@ -2495,6 +2653,7 @@ function flushPendingChains() { forEach.call(queue, function(q) { q[0].add(q[1]); }); + Ember.warn('Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos', pendingQueue.length === 0); } function isProto(pvalue) { @@ -3026,6 +3185,7 @@ Ember.destroy = function (obj) { @module ember-metal */ +Ember.warn("The CP_DEFAULT_CACHEABLE flag has been removed and computed properties are always cached by default. Use `volatile` if you don't want caching.", Ember.ENV.CP_DEFAULT_CACHEABLE !== false); var get = Ember.get, @@ -3255,7 +3415,7 @@ ComputedPropertyPrototype.meta = function(meta) { ComputedPropertyPrototype.willWatch = function(obj, keyName) { // watch already creates meta for this instance var meta = obj[META_KEY]; - + Ember.assert('watch should have setup meta to be writable', meta.source === obj); if (!(keyName in meta.cache)) { addDependentKeys(this, obj, keyName, meta); } @@ -3263,7 +3423,7 @@ ComputedPropertyPrototype.willWatch = function(obj, keyName) { ComputedPropertyPrototype.didUnwatch = function(obj, keyName) { var meta = obj[META_KEY]; - + Ember.assert('unwatch should have setup meta to be writable', meta.source === obj); if (!(keyName in meta.cache)) { // unwatch already creates meta for this instance removeDependentKeys(this, obj, keyName, meta); @@ -3599,7 +3759,7 @@ function actionsDiff(obj, eventName, otherActions) { @param {Function|String} method A function or the name of a function to be called on `target` */ function addListener(obj, eventName, target, method, once) { - + Ember.assert("You must pass at least an object and event name to Ember.addListener", !!obj && !!eventName); if (!method && 'function' === typeof target) { method = target; @@ -3631,7 +3791,7 @@ function addListener(obj, eventName, target, method, once) { @param {Function|String} method A function or the name of a function to be called on `target` */ function removeListener(obj, eventName, target, method) { - + Ember.assert("You must pass at least an object and event name to Ember.removeListener", !!obj && !!eventName); if (!method && 'function' === typeof target) { method = target; @@ -4132,7 +4292,7 @@ Ember.run.begin = function() { @return {void} */ Ember.run.end = function() { - + Ember.assert('must have a current run loop', run.currentRunLoop); function tryable() { run.currentRunLoop.end(); } function finalizer() { run.currentRunLoop = run.currentRunLoop.prev(); } @@ -4234,7 +4394,7 @@ Ember.run.cancelTimers = function () { */ Ember.run.autorun = function() { if (!run.currentRunLoop) { - + Ember.assert("You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in an Ember.run", !Ember.testing); run.begin(); @@ -4628,7 +4788,7 @@ Binding.prototype = { @return {Ember.Binding} `this` */ connect: function(obj) { - + Ember.assert('Must pass a valid object to Ember.Binding.connect()', !!obj); var fromPath = this._from, toPath = this._to; Ember.trySet(obj, toPath, getWithGlobals(obj, fromPath)); @@ -4653,7 +4813,7 @@ Binding.prototype = { @return {Ember.Binding} `this` */ disconnect: function(obj) { - + Ember.assert('Must pass a valid object to Ember.Binding.disconnect()', !!obj); var twoWay = !this._oneWay; @@ -5119,7 +5279,7 @@ function mergeMixins(mixins, m, descs, values, base) { for(var i=0, l=mixins.length; i=0) return copies[loc]; + Ember.assert('Cannot clone an Ember.Object that does not implement Ember.Copyable', !(obj instanceof Ember.Object) || (Ember.Copyable && Ember.Copyable.detect(obj))); // IMPORTANT: this specific test will detect a native array only. Any other // object will need to implement Copyable. @@ -9372,7 +9567,7 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ { @return {Object} The property value or undefined. */ getPath: function(path) { - + Ember.deprecate("getPath is deprecated since get now supports paths"); return this.get(path); }, @@ -9384,7 +9579,7 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ { @return {Ember.Observable} */ setPath: function(path, value) { - + Ember.deprecate("setPath is deprecated since set now supports paths"); return this.set(path, value); }, @@ -9628,7 +9823,7 @@ Ember.Evented = Ember.Mixin.create({ event. ```javascript - person.on('didEat', food) { + person.on('didEat', function(food) { console.log('person ate some ' + food); }); @@ -9649,7 +9844,7 @@ Ember.Evented = Ember.Mixin.create({ }, fire: function(name) { - + Ember.deprecate("Ember.Evented#fire() has been deprecated in favor of trigger() for compatibility with jQuery. It will be removed in 1.0. Please update your code to call trigger() instead."); this.trigger.apply(this, arguments); }, @@ -9842,7 +10037,8 @@ function makeCtor() { var desc = m.descs[keyName]; - + Ember.assert("Ember.Object.create no longer supports defining computed properties.", !(value instanceof Ember.ComputedProperty)); + Ember.assert("Ember.Object.create no longer supports defining methods that call _super.", !(typeof value === 'function' && value.toString().indexOf('._super') !== -1)); if (concatenatedProperties && indexOf(concatenatedProperties, keyName) >= 0) { var baseValue = this[keyName]; @@ -10192,6 +10388,7 @@ var ClassMixin = Mixin.create({ metaForProperty: function(key) { var desc = meta(this.proto(), false).descs[key]; + Ember.assert("metaForProperty() could not find a computed property with key '"+key+"'.", !!desc && desc instanceof Ember.ComputedProperty); return desc._meta || {}; }, @@ -10774,16 +10971,28 @@ var Namespace = Ember.Namespace = Ember.Object.extend({ Namespace.reopenClass({ NAMESPACES: [Ember], + NAMESPACES_BY_ID: {}, PROCESSED: false, - processAll: processAllNamespaces + processAll: processAllNamespaces, + byName: function(name) { + if (!Ember.BOOTED) { + processAllNamespaces(); + } + + return NAMESPACES_BY_ID[name]; + } }); +var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID; + var hasOwnProp = ({}).hasOwnProperty, guidFor = Ember.guidFor; function processNamespace(paths, root, seen) { var idx = paths.length; + NAMESPACES_BY_ID[paths.join('.')] = root; + // Loop over all of the keys in the namespace, looking for classes for(var key in root) { if (!hasOwnProp.call(root, key)) { continue; } @@ -10842,7 +11051,7 @@ function findNamespaces() { } if (isNamespace) { - + Ember.deprecate("Namespaces should not begin with lowercase.", /^[A-Z]/.test(prop)); obj[NAME_KEY] = prop; } } @@ -10883,12 +11092,15 @@ function classToString() { } function processAllNamespaces() { - if (!Namespace.PROCESSED) { + var unprocessedNamespaces = !Namespace.PROCESSED, + unprocessedMixins = Ember.anyUnprocessedMixins; + + if (unprocessedNamespaces) { findNamespaces(); Namespace.PROCESSED = true; } - if (Ember.anyUnprocessedMixins) { + if (unprocessedNamespaces || unprocessedMixins) { var namespaces = Namespace.NAMESPACES, namespace; for (var i=0, l=namespaces.length; i= 0 && idx < length) { + var controllerClass = this.lookupItemController(object); + if (controllerClass) { + return this.controllerAt(idx, object, controllerClass); + } } + + // When `controllerClass` is falsy, we have not opted in to using item + // controllers, so return the object directly. + + // When the index is out of range, we want to return the "out of range" + // value, whatever that might be. Rather than make assumptions + // (e.g. guessing `null` or `undefined`) we defer this to `arrangedContent`. + return object; }, arrangedContentDidChange: function() { @@ -12259,6 +12478,7 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin, init: function() { this._super(); + if (!this.get('content')) { this.set('content', Ember.A()); } this._resetSubContainers(); }, @@ -12352,7 +12572,7 @@ Ember Runtime */ var jQuery = Ember.imports.jQuery; - +Ember.assert("Ember Views require jQuery 1.8 or 1.9", jQuery && (jQuery().jquery.match(/^1\.(8|9)(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY)); /** Alias for jQuery @@ -12492,7 +12712,7 @@ var setInnerHTML = function(element, html) { if (canSetInnerHTML(tagName)) { setInnerHTMLWithoutFix(element, html); } else { - + Ember.assert("Can't set innerHTML on "+element.tagName+" in this browser", element.outerHTML); var startTag = element.outerHTML.match(new RegExp("<"+tagName+"([^>]*)>", 'i'))[0], endTag = ''; @@ -12632,17 +12852,19 @@ Ember._RenderBuffer.prototype = elementAttributes: null, /** - The value for this attribute. Values cannot be set via attr after - jQuery 1.9, they need to be set with val() instead. + A hash keyed on the name of the properties and whose value will be + applied to that property. For example, if you wanted to apply a + `checked=true` property to an element, you would set the + elementProperties hash to `{'checked':true}`. - You should not maintain this value yourself, rather, you should use - the `val()` method of `Ember.RenderBuffer`. + You should not maintain this hash yourself, rather, you should use + the `prop()` method of `Ember.RenderBuffer`. - @property elementValue - @type String - @default null + @property elementProperties + @type Hash + @default {} */ - elementValue: null, + elementProperties: null, /** The tagname of the element an instance of `Ember.RenderBuffer` represents. @@ -12752,26 +12974,6 @@ Ember._RenderBuffer.prototype = return this; }, - /** - Adds an value which will be rendered to the element. - - @method val - @param {String} value The value to set - @chainable - @return {Ember.RenderBuffer|String} this or the current value - */ - val: function(value) { - var elementValue = this.elementValue; - - if (arguments.length === 0) { - return elementValue; - } else { - this.elementValue = value; - } - - return this; - }, - /** Remove an attribute from the list of attributes to render. @@ -12786,6 +12988,41 @@ Ember._RenderBuffer.prototype = return this; }, + /** + Adds an property which will be rendered to the element. + + @method prop + @param {String} name The name of the property + @param {String} value The value to add to the property + @chainable + @return {Ember.RenderBuffer|String} this or the current property value + */ + prop: function(name, value) { + var properties = this.elementProperties = (this.elementProperties || {}); + + if (arguments.length === 1) { + return properties[name]; + } else { + properties[name] = value; + } + + return this; + }, + + /** + Remove an property from the list of properties to render. + + @method removeProp + @param {String} name The name of the property + @chainable + */ + removeProp: function(name) { + var properties = this.elementProperties; + if (properties) { delete properties[name]; } + + return this; + }, + /** Adds a style to the style attribute which will be rendered to the element. @@ -12819,9 +13056,9 @@ Ember._RenderBuffer.prototype = id = this.elementId, classes = this.classes, attrs = this.elementAttributes, - value = this.elementValue, + props = this.elementProperties, style = this.elementStyle, - prop; + attr, prop; buffer.push('<' + tagName); @@ -12849,19 +13086,30 @@ Ember._RenderBuffer.prototype = } if (attrs) { - for (prop in attrs) { - if (attrs.hasOwnProperty(prop)) { - buffer.push(' ' + prop + '="' + this._escapeAttribute(attrs[prop]) + '"'); + for (attr in attrs) { + if (attrs.hasOwnProperty(attr)) { + buffer.push(' ' + attr + '="' + this._escapeAttribute(attrs[attr]) + '"'); } } this.elementAttributes = null; } - if (value) { - buffer.push(' value="' + this._escapeAttribute(value) + '"'); + if (props) { + for (prop in props) { + if (props.hasOwnProperty(prop)) { + var value = props[prop]; + if (value || typeof(value) === 'number') { + if (value === true) { + buffer.push(' ' + prop + '="' + prop + '"'); + } else { + buffer.push(' ' + prop + '="' + this._escapeAttribute(props[prop]) + '"'); + } + } + } + } - this.elementValue = null; + this.elementProperties = null; } buffer.push('>'); @@ -12883,9 +13131,9 @@ Ember._RenderBuffer.prototype = id = this.elementId, classes = this.classes, attrs = this.elementAttributes, - value = this.elementValue, + props = this.elementProperties, style = this.elementStyle, - styleBuffer = '', prop; + styleBuffer = '', attr, prop; if (id) { $element.attr('id', id); @@ -12909,19 +13157,23 @@ Ember._RenderBuffer.prototype = } if (attrs) { - for (prop in attrs) { - if (attrs.hasOwnProperty(prop)) { - $element.attr(prop, attrs[prop]); + for (attr in attrs) { + if (attrs.hasOwnProperty(attr)) { + $element.attr(attr, attrs[attr]); } } this.elementAttributes = null; } - if (value) { - $element.val(value); + if (props) { + for (prop in props) { + if (props.hasOwnProperty(prop)) { + $element.prop(prop, props[prop]); + } + } - this.elementValue = null; + this.elementProperties = null; } return element; @@ -13077,11 +13329,13 @@ Ember.EventDispatcher = Ember.Object.extend( var rootElement = Ember.$(get(this, 'rootElement')); - - + Ember.assert(fmt('You cannot use the same root element (%@) multiple times in an Ember.Application', [rootElement.selector || rootElement[0].tagName]), !rootElement.is('.ember-application')); + Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length); + Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length); rootElement.addClass('ember-application'); + Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application')); for (event in events) { if (events.hasOwnProperty(event)) { @@ -13290,7 +13544,7 @@ var childViewsProperty = Ember.computed(function() { ret.replace = function (idx, removedCount, addedViews) { if (view instanceof Ember.ContainerView) { - + Ember.deprecate("Manipulating a Ember.ContainerView through its childViews property is deprecated. Please use the ContainerView instance itself as an Ember.MutableArray."); return view.replace(idx, removedCount, addedViews); } throw new Error("childViews is immutable"); @@ -13299,6 +13553,7 @@ var childViewsProperty = Ember.computed(function() { return ret; }); +Ember.warn("The VIEW_PRESERVES_CONTEXT flag has been removed and the functionality can no longer be disabled.", Ember.ENV.VIEW_PRESERVES_CONTEXT !== false); /** Global hash of shared templates. This will automatically be populated @@ -13322,7 +13577,7 @@ Ember.CoreView = Ember.Object.extend(Ember.Evented, { // Register the view for event handling. This hash is used by // Ember.EventDispatcher to dispatch incoming events. if (!this.isVirtual) { - + Ember.assert("Attempted to register a view with an id already in use: "+this.elementId, !Ember.View.views[this.elementId]); Ember.View.views[this.elementId] = this; } @@ -14091,6 +14346,7 @@ Ember.View = Ember.CoreView.extend( var templateName = get(this, 'templateName'), template = this.templateForName(templateName, 'template'); + Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template); return template || get(this, 'defaultTemplate'); }).property('templateName'), @@ -14133,6 +14389,7 @@ Ember.View = Ember.CoreView.extend( var layoutName = get(this, 'layoutName'), layout = this.templateForName(layoutName, 'layout'); + Ember.assert("You specified the layoutName " + layoutName + " for " + this + ", but it did not exist.", !layoutName || layout); return layout || get(this, 'defaultLayout'); }).property('layoutName'), @@ -14140,6 +14397,7 @@ Ember.View = Ember.CoreView.extend( templateForName: function(name, type) { if (!name) { return; } + Ember.assert("templateNames are not allowed to contain periods: "+name, name.indexOf('.') === -1); var container = get(this, 'container'); @@ -14266,7 +14524,7 @@ Ember.View = Ember.CoreView.extend( @deprecated */ nearestInstanceOf: function(klass) { - + Ember.deprecate("nearestInstanceOf is deprecated and will be removed from future releases. Use nearestOfType."); var view = get(this, 'parentView'); while (view) { @@ -14400,6 +14658,7 @@ Ember.View = Ember.CoreView.extend( // is the view's controller by default. A hash of data is also passed that provides // the template with access to the view and render buffer. + Ember.assert('template must be a function. Did you mean to call Ember.Handlebars.compile("...") or specify templateName instead?', typeof template === 'function'); // The template should write directly to the render buffer instead // of returning a string. output = template(context, { data: data }); @@ -14671,7 +14930,7 @@ Ember.View = Ember.CoreView.extend( // Schedule the DOM element to be created and appended to the given // element after bindings have synchronized. this._insertElementLater(function() { - + Ember.assert("You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.", !Ember.$(target).is('.ember-view') && !Ember.$(target).parents().is('.ember-view')); this.$().appendTo(target); }); @@ -14692,7 +14951,7 @@ Ember.View = Ember.CoreView.extend( @return {Ember.View} received */ replaceIn: function(target) { - + Ember.assert("You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.", !Ember.$(target).is('.ember-view') && !Ember.$(target).parents().is('.ember-view')); this._insertElementLater(function() { Ember.$(target).empty(); @@ -15144,8 +15403,10 @@ Ember.View = Ember.CoreView.extend( // setup child views. be sure to clone the child views array first this._childViews = this._childViews.slice(); + Ember.assert("Only arrays are allowed for 'classNameBindings'", Ember.typeOf(this.classNameBindings) === 'array'); this.classNameBindings = Ember.A(this.classNameBindings.slice()); + Ember.assert("Only arrays are allowed for 'classNames'", Ember.typeOf(this.classNames) === 'array'); this.classNames = Ember.A(this.classNames.slice()); var viewController = get(this, 'viewController'); @@ -15296,7 +15557,7 @@ Ember.View = Ember.CoreView.extend( // consumers of the view API if (view.viewName) { set(get(this, 'concreteView'), view.viewName, view); } } else { - + Ember.assert('You must pass instance or subclass of View', view.isView); if (attrs) { view.setProperties(attrs); @@ -15604,56 +15865,20 @@ Ember.View.views = {}; Ember.View.childViewsProperty = childViewsProperty; Ember.View.applyAttributeBindings = function(elem, name, value) { - if (name === 'value') { - Ember.View.applyValueBinding(elem, value); - } else { - Ember.View.applyAttributeBinding(elem, name, value); - } -}; - -Ember.View.applyAttributeBinding = function(elem, name, value) { var type = Ember.typeOf(value); - var currentValue = elem.attr(name); // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js - if ( - ( - ( type === 'string' ) || - ( type === 'number' && !isNaN(value) ) || - ( type === 'boolean' && value ) - ) && ( - value !== currentValue - ) - ) { - elem.attr(name, value); - } else if (!value) { - elem.removeAttr(name); - } -}; - -Ember.View.applyValueBinding = function(elem, value) { - var type = Ember.typeOf(value); - var currentValue = elem.val(); - - // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js - if ( - ( - ( type === 'string' ) || - ( type === 'number' && !isNaN(value) ) || - ( type === 'boolean' && value ) - ) && ( - value !== currentValue - ) - ) { - if (elem.caretPosition) { - var caretPosition = elem.caretPosition(); - elem.val(value); - elem.setCaretPosition(caretPosition); - } else { - elem.val(value); + if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) { + if (value !== elem.attr(name)) { + elem.attr(name, value); + } + } else if (name === 'value' || type === 'boolean') { + if (value !== elem.prop(name)) { + // value and booleans should always be properties + elem.prop(name, value); } } else if (!value) { - elem.val(''); + elem.removeAttr(name); } }; @@ -15802,7 +16027,7 @@ Ember.merge(inBuffer, { }, empty: function() { - + Ember.assert("Emptying a view in the inBuffer state is not allowed and should not happen under normal circumstances. Most likely there is a bug in your application. This may be due to excessive property change notifications."); }, renderToBufferIfNeeded: function (view) { @@ -16617,7 +16842,7 @@ Ember.CollectionView = Ember.ContainerView.extend( var content = get(this, 'content'); if (content) { - + Ember.assert(fmt("an Ember.CollectionView's content must implement Ember.Array. You passed %@", [content]), Ember.Array.detect(content)); content.addArrayObserver(this); } @@ -16685,6 +16910,7 @@ Ember.CollectionView = Ember.ContainerView.extend( itemViewClass = get(itemViewClass); } + Ember.assert(fmt("itemViewClass must be a subclass of Ember.View, not %@", [itemViewClass]), Ember.View.detect(itemViewClass)); len = content ? get(content, 'length') : 0; if (len) { @@ -17245,7 +17471,7 @@ var objectCreate = Object.create || function(parent) { }; var Handlebars = this.Handlebars || Ember.imports.Handlebars; - +Ember.assert("Ember Handlebars requires Handlebars 1.0.0-rc.3 or greater", Handlebars && Handlebars.VERSION.match(/^1\.0\.[0-9](\.rc\.[23456789]+)?/)); /** Prepares the Handlebars templating library for use inside Ember's view @@ -17659,7 +17885,7 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) { Ember.Handlebars.registerBoundHelper = function(name, fn) { var dependentKeys = slice.call(arguments, 2); - Ember.Handlebars.registerHelper(name, function() { + function helper() { var properties = slice.call(arguments, 0, -1), numProperties = properties.length, options = arguments[arguments.length - 1], @@ -17698,6 +17924,7 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) { return evaluateMultiPropertyBoundHelper(currentContext, fn, normalizedProperties, options); } + Ember.assert("Dependent keys can only be used with single-property helpers.", properties.length === 1); normalized = normalizedProperties[0]; @@ -17720,7 +17947,10 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) { for (var i=0, l=dependentKeys.length; i= 1.0.0-rc.3']; helpers = helpers || Ember.Handlebars.helpers; data = data || {}; var buffer = '', stack1, hashTypes, escapeExpression=this.escapeExpression, self=this; function program1(depth0,data) { - var buffer = '', stack1, hashTypes; + var buffer = '', hashTypes; data.buffer.push(""); - return buffer;} + data.buffer.push(escapeExpression(helpers._triageMustache.call(depth0, "view.prompt", {hash:{},contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data}))); + data.buffer.push(""); + return buffer; + } function program3(depth0,data) { - var stack1, hashTypes; - stack1 = {}; - hashTypes = {}; - hashTypes['contentBinding'] = "STRING"; - stack1['contentBinding'] = "this"; - stack1 = helpers.view.call(depth0, "Ember.SelectOption", {hash:stack1,contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data}); - data.buffer.push(escapeExpression(stack1));} + var hashTypes; + hashTypes = {'contentBinding': "STRING"}; + data.buffer.push(escapeExpression(helpers.view.call(depth0, "Ember.SelectOption", {hash:{ + 'contentBinding': ("this") + },contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data}))); + } - stack1 = {}; hashTypes = {}; - stack1 = helpers['if'].call(depth0, "view.prompt", {hash:stack1,inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data}); + stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data}); if(stack1 || stack1 === 0) { data.buffer.push(stack1); } - stack1 = {}; hashTypes = {}; - stack1 = helpers.each.call(depth0, "view.content", {hash:stack1,inverse:self.noop,fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data}); + stack1 = helpers.each.call(depth0, "view.content", {hash:{},inverse:self.noop,fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data}); if(stack1 || stack1 === 0) { data.buffer.push(stack1); } return buffer; + }), attributeBindings: ['multiple', 'disabled', 'tabindex'], @@ -22413,7 +22648,7 @@ DSL.prototype = { }, route: function(name, options) { - + Ember.assert("You must use `this.resource` to nest", typeof options !== 'function'); options = options || {}; @@ -22536,6 +22771,10 @@ Ember.Router = Ember.Object.extend({ setupLocation(this); }, + url: Ember.computed(function() { + return get(this, 'location').getURL(); + }), + startRouting: function() { this.router = this.router || this.constructor.map(Ember.K); @@ -22549,16 +22788,17 @@ Ember.Router = Ember.Object.extend({ container.register('view', 'default', DefaultView); container.register('view', 'toplevel', Ember.View.extend()); - this.handleURL(location.getURL()); location.onUpdateURL(function(url) { self.handleURL(url); }); + + this.handleURL(location.getURL()); }, didTransition: function(infos) { // Don't do any further action here if we redirected for (var i=0, l=infos.length; i= 2); var container, router, controller, view, context; if (arguments.length === 2) { @@ -23482,6 +23786,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { container = options.data.keywords.controller.container; router = container.lookup('router:main'); + Ember.assert("This view is already rendered", !router || !router._lookupActiveView(name)); view = container.lookup('view:' + name) || container.lookup('view:default'); @@ -23575,12 +23880,14 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { target = target.root; } - if (target.send) { - return target.send.apply(target, args(options.parameters, actionName)); - } else { - - return target[actionName].apply(target, args(options.parameters)); - } + Ember.run(function() { + if (target.send) { + target.send.apply(target, args(options.parameters, actionName)); + } else { + Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function'); + target[actionName].apply(target, args(options.parameters)); + } + }); } }; @@ -23760,7 +24067,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { @method action @for Ember.Handlebars.helpers @param {String} actionName - @param {Object...} contexts + @param {Object} [context]* @param {Hash} options */ EmberHandlebars.registerHelper('action', function(actionName) { @@ -23807,61 +24114,80 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { (function() { -var get = Ember.get, set = Ember.set; +/** +@module ember +@submodule ember-routing +*/ -Ember.Handlebars.registerHelper('control', function(path, modelPath, options) { - if (arguments.length === 2) { - options = modelPath; - modelPath = undefined; - } +if (Ember.ENV.EXPERIMENTAL_CONTROL_HELPER) { + var get = Ember.get, set = Ember.set; - var model; + /** + The control helper is currently under development and is considered experimental. + To enable it, set `ENV.EXPERIMENTAL_CONTROL_HELPER = true` before requiring Ember. - if (modelPath) { - model = Ember.Handlebars.get(this, modelPath, options); - } + @method control + @for Ember.Handlebars.helpers + @param {String} path + @param {String} modelPath + @param {Hash} options + @return {String} HTML string + */ + Ember.Handlebars.registerHelper('control', function(path, modelPath, options) { + if (arguments.length === 2) { + options = modelPath; + modelPath = undefined; + } - var controller = options.data.keywords.controller, - view = options.data.keywords.view, - children = get(controller, '_childContainers'), - controlID = options.hash.controlID, - container, subContainer; + var model; - if (children.hasOwnProperty(controlID)) { - subContainer = children[controlID]; - } else { - container = get(controller, 'container'), - subContainer = container.child(); - children[controlID] = subContainer; - } + if (modelPath) { + model = Ember.Handlebars.get(this, modelPath, options); + } - var normalizedPath = path.replace(/\//g, '.'); + var controller = options.data.keywords.controller, + view = options.data.keywords.view, + children = get(controller, '_childContainers'), + controlID = options.hash.controlID, + container, subContainer; - var childView = subContainer.lookup('view:' + normalizedPath) || subContainer.lookup('view:default'), - childController = subContainer.lookup('controller:' + normalizedPath), - childTemplate = subContainer.lookup('template:' + path); + if (children.hasOwnProperty(controlID)) { + subContainer = children[controlID]; + } else { + container = get(controller, 'container'), + subContainer = container.child(); + children[controlID] = subContainer; + } + var normalizedPath = path.replace(/\//g, '.'); + var childView = subContainer.lookup('view:' + normalizedPath) || subContainer.lookup('view:default'), + childController = subContainer.lookup('controller:' + normalizedPath), + childTemplate = subContainer.lookup('template:' + path); - set(childController, 'target', controller); - set(childController, 'model', model); + Ember.assert("Could not find controller for path: " + normalizedPath, childController); + Ember.assert("Could not find view for path: " + normalizedPath, childView); - options.hash.template = childTemplate; - options.hash.controller = childController; - - function observer() { - var model = Ember.Handlebars.get(this, modelPath, options); + set(childController, 'target', controller); set(childController, 'model', model); - childView.rerender(); - } - Ember.addObserver(this, modelPath, observer); - childView.one('willDestroyElement', this, function() { - Ember.removeObserver(this, modelPath, observer); + options.hash.template = childTemplate; + options.hash.controller = childController; + + function observer() { + var model = Ember.Handlebars.get(this, modelPath, options); + set(childController, 'model', model); + childView.rerender(); + } + + Ember.addObserver(this, modelPath, observer); + childView.one('willDestroyElement', this, function() { + Ember.removeObserver(this, modelPath, observer); + }); + + Ember.Handlebars.helpers.view.call(this, childView, options); }); - - Ember.Handlebars.helpers.view.call(this, childView, options); -}); +} })(); @@ -23883,24 +24209,26 @@ var get = Ember.get, set = Ember.set; Ember.ControllerMixin.reopen({ transitionToRoute: function() { - var target = get(this, 'target'); - - return target.transitionTo.apply(target, arguments); + // target may be either another controller or a router + var target = get(this, 'target'), + method = target.transitionToRoute || target.transitionTo; + return method.apply(target, arguments); }, - // TODO: Deprecate this, see https://github.com/emberjs/ember.js/issues/1785 transitionTo: function() { + Ember.deprecate("transitionTo is deprecated. Please use transitionToRoute."); return this.transitionToRoute.apply(this, arguments); }, replaceRoute: function() { - var target = get(this, 'target'); - - return target.replaceWith.apply(target, arguments); + // target may be either another controller or a router + var target = get(this, 'target'), + method = target.replaceRoute || target.replaceWith; + return method.apply(target, arguments); }, - // TODO: Deprecate this, see https://github.com/emberjs/ember.js/issues/1785 replaceWith: function() { + Ember.deprecate("replaceWith is deprecated. Please use replaceRoute."); return this.replaceRoute.apply(this, arguments); } }); @@ -23991,10 +24319,10 @@ var get = Ember.get, set = Ember.set; Ember.Location = { create: function(options) { var implementation = options && options.implementation; - + Ember.assert("Ember.Location.create: you must specify a 'implementation' option", !!implementation); var implementationClass = this.implementations[implementation]; - + Ember.assert("Ember.Location.create: " + implementation + " is not a valid implementation", !!implementationClass); return implementationClass.create.apply(implementationClass, arguments); }, @@ -24040,7 +24368,12 @@ Ember.NoneLocation = Ember.Object.extend({ }, onUpdateURL: function(callback) { - // We are not wired up to the browser, so we'll never trigger the callback. + this.updateCallback = callback; + }, + + handleURL: function(url) { + set(this, 'path', url); + this.updateCallback(url); }, formatURL: function(url) { @@ -24121,12 +24454,14 @@ Ember.HashLocation = Ember.Object.extend({ var guid = Ember.guidFor(this); Ember.$(window).bind('hashchange.ember-location-'+guid, function() { - var path = location.hash.substr(1); - if (get(self, 'lastSetURL') === path) { return; } + Ember.run(function() { + var path = location.hash.substr(1); + if (get(self, 'lastSetURL') === path) { return; } - set(self, 'lastSetURL', null); + set(self, 'lastSetURL', null); - callback(location.hash.substr(1)); + callback(location.hash.substr(1)); + }); }); }, @@ -24586,7 +24921,14 @@ var get = Ember.get, set = Ember.set, ### Routing In addition to creating your application's router, `Ember.Application` is - also responsible for telling the router when to start routing. + also responsible for telling the router when to start routing. Transitions + between routes can be logged with the LOG_TRANSITIONS flag: + + ```javascript + window.App = Ember.Application.create({ + LOG_TRANSITIONS: true + }); + ``` By default, the router will begin trying to translate the current URL into application state once the browser emits the `DOMContentReady` event. If you @@ -24595,14 +24937,7 @@ var get = Ember.get, set = Ember.set, If there is any setup required before routing begins, you can implement a `ready()` method on your app that will be invoked immediately before routing - begins: - - ```javascript - window.App = Ember.Application.create({ - ready: function() { - this.set('router.enableLogging', true); - } - }); + begins. To begin routing, you must have at a minimum a top-level controller and view. You define these as `App.ApplicationController` and `App.ApplicationView`, @@ -24620,8 +24955,7 @@ var get = Ember.get, set = Ember.set, @namespace Ember @extends Ember.Namespace */ -var Application = Ember.Application = Ember.Namespace.extend( -/** @scope Ember.Application.prototype */{ +var Application = Ember.Application = Ember.Namespace.extend({ /** The root DOM element of the Application. This can be specified as an @@ -24701,10 +25035,11 @@ var Application = Ember.Application = Ember.Namespace.extend( this.deferUntilDOMReady(); this.scheduleInitialize(); - - - - + Ember.debug('-------------------------------'); + Ember.debug('Ember.VERSION : ' + Ember.VERSION); + Ember.debug('Handlebars.VERSION : ' + Ember.Handlebars.VERSION); + Ember.debug('jQuery.VERSION : ' + Ember.$().jquery); + Ember.debug('-------------------------------'); }, /** @@ -24820,7 +25155,7 @@ var Application = Ember.Application = Ember.Namespace.extend( @method deferReadiness */ deferReadiness: function() { - + Ember.assert("You cannot defer readiness since the `ready()` hook has already been called.", this._readinessDeferrals > 0); this._readinessDeferrals++; }, @@ -24896,8 +25231,8 @@ var Application = Ember.Application = Ember.Namespace.extend( @method initialize */ initialize: function() { - - + Ember.assert("Application initialize may only be called once", !this.isInitialized); + Ember.assert("Cannot initialize a destroyed application", !this.isDestroyed); this.isInitialized = true; // At this point, the App.Router must already be assigned @@ -24914,6 +25249,15 @@ var Application = Ember.Application = Ember.Namespace.extend( return this; }, + reset: function() { + get(this, '__container__').destroy(); + this.buildContainer(); + + this.isInitialized = false; + this.initialize(); + this.startRouting(); + }, + /** @private @method runInitializers @@ -25001,6 +25345,12 @@ var Application = Ember.Application = Ember.Namespace.extend( router.startRouting(); }, + handleURL: function(url) { + var router = this.__container__.lookup('router:main'); + + router.handleURL(url); + }, + /** Called when the Application has become ready. The call will be delayed until the DOM has become ready. @@ -25015,7 +25365,7 @@ var Application = Ember.Application = Ember.Namespace.extend( var eventDispatcher = get(this, 'eventDispatcher'); if (eventDispatcher) { eventDispatcher.destroy(); } - this.__container__.destroy(); + get(this, '__container__').destroy(); }, initializer: function(options) { @@ -25029,8 +25379,9 @@ Ember.Application.reopenClass({ initializer: function(initializer) { var initializers = get(this, 'initializers'); - - + Ember.assert("The initializer '" + initializer.name + "' has already been registered", !initializers.findProperty('name', initializers.name)); + Ember.assert("An injection cannot be registered with both a before and an after", !(initializer.before && initializer.after)); + Ember.assert("An injection cannot be registered without an injection function", Ember.canInvoke(initializer, 'initialize')); initializers.push(initializer); }, @@ -25063,7 +25414,7 @@ Ember.Application.reopenClass({ */ buildContainer: function(namespace) { var container = new Ember.Container(); - Ember.Container.defaultContainer = container; + Ember.Container.defaultContainer = Ember.Container.defaultContainer || container; container.set = Ember.set; container.resolver = resolverFor(namespace); @@ -25176,7 +25527,7 @@ function verifyDependencies(controller) { if (!container.has(dependency)) { satisfied = false; - + Ember.assert(controller + " needs " + dependency + " but it does not exist", false); } } @@ -25192,12 +25543,12 @@ Ember.ControllerMixin.reopen({ // Structure asserts to still do verification but not string concat in production if(!verifyDependencies(this)) { - + Ember.assert("Missing dependencies", false); } }, controllerFor: function(controllerName) { - + Ember.deprecate("Controller#controllerFor is depcrecated, please use Controller#needs instead"); var container = get(this, 'container'); return container.lookup('controller:' + controllerName); }, @@ -26145,7 +26496,7 @@ Ember.StateManager = Ember.State.extend({ if (initialState) { this.transitionTo(initialState); - + Ember.assert('Failed to transition to initial state "' + initialState + '"', !!get(this, 'currentState')); } }, @@ -26209,7 +26560,7 @@ Ember.StateManager = Ember.State.extend({ send: function(event) { var contexts = [].slice.call(arguments, 1); - + Ember.assert('Cannot send event "' + event + '" while currentState is ' + get(this, 'currentState'), get(this, 'currentState')); return sendEvent.call(this, event, contexts, false); }, unhandledEvent: function(manager, event) { @@ -26367,7 +26718,7 @@ Ember.StateManager = Ember.State.extend({ if (!resolveState) { enterStates = this.getStatesInPath(this, path); if (!enterStates) { - + Ember.assert('Could not find state for path: "'+path+'"'); return; } } @@ -26421,6 +26772,7 @@ Ember.StateManager = Ember.State.extend({ enterStates = transitions.enterStates, transitionEvent = get(this, 'transitionEvent'); + Ember.assert("More contexts provided than states", offset >= 0); arrayForEach.call(enterStates, function(state, idx) { state.trigger(transitionEvent, this, contexts[idx-offset]); @@ -26472,9 +26824,16 @@ Ember States })(); +// Version: v1.0.0-rc.1 +// Last commit: 8b061b4 (2013-02-15 12:10:22 -0800) -if (typeof location !== 'undefined' && (location.hostname === 'localhost' || location.hostname === '127.0.0.1')) { - console.warn("You are running a production build of Ember on localhost and won't receive detailed error messages. "+ - "If you want full error messages please use the non-minified build provided on the Ember website."); -} +(function() { +/** +Ember + +@module ember +*/ + +})(); + diff --git a/vendor/gems/message_bus/assets/handlebars-1.0.rc.2.js b/vendor/gems/message_bus/assets/handlebars.js similarity index 84% rename from vendor/gems/message_bus/assets/handlebars-1.0.rc.2.js rename to vendor/gems/message_bus/assets/handlebars.js index aeea9260568..9c653ee7209 100644 --- a/vendor/gems/message_bus/assets/handlebars-1.0.rc.2.js +++ b/vendor/gems/message_bus/assets/handlebars.js @@ -1,3 +1,27 @@ +/* + +Copyright (C) 2011 by Yehuda Katz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + // lib/handlebars/base.js /*jshint eqnull:true*/ @@ -5,7 +29,13 @@ this.Handlebars = {}; (function(Handlebars) { -Handlebars.VERSION = "1.0.rc.2"; +Handlebars.VERSION = "1.0.0-rc.3"; +Handlebars.COMPILER_REVISION = 2; + +Handlebars.REVISION_CHANGES = { + 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it + 2: '>= 1.0.0-rc.3' +}; Handlebars.helpers = {}; Handlebars.partials = {}; @@ -618,9 +648,13 @@ return new Parser; // lib/handlebars/compiler/base.js Handlebars.Parser = handlebars; -Handlebars.parse = function(string) { +Handlebars.parse = function(input) { + + // Just return if an already-compile AST was passed in. + if(input.constructor === Handlebars.AST.ProgramNode) { return input; } + Handlebars.Parser.yy = Handlebars.AST; - return Handlebars.Parser.parse(string); + return Handlebars.Parser.parse(input); }; Handlebars.print = function(ast) { @@ -702,8 +736,11 @@ Handlebars.print = function(ast) { for(var i=0,l=parts.length; i 0) { throw new Handlebars.Exception("Invalid path: " + this.original); } + else if (part === "..") { depth++; } + else { this.isScoped = true; } + } else { dig.push(part); } } @@ -853,6 +890,26 @@ Handlebars.JavaScriptCompiler = function() {}; return out.join("\n"); }, + equals: function(other) { + var len = this.opcodes.length; + if (other.opcodes.length !== len) { + return false; + } + + for (var i = 0; i < len; i++) { + var opcode = this.opcodes[i], + otherOpcode = other.opcodes[i]; + if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) { + return false; + } + for (var j = 0; j < opcode.args.length; j++) { + if (opcode.args[j] !== otherOpcode.args[j]) { + return false; + } + } + } + return true; + }, guid: 0, @@ -944,7 +1001,7 @@ Handlebars.JavaScriptCompiler = function() {}; // evaluate it by executing `blockHelperMissing` this.opcode('pushProgram', program); this.opcode('pushProgram', inverse); - this.opcode('pushHash'); + this.opcode('emptyHash'); this.opcode('blockValue'); } else { this.ambiguousMustache(mustache, program, inverse); @@ -953,7 +1010,7 @@ Handlebars.JavaScriptCompiler = function() {}; // evaluate it by executing `blockHelperMissing` this.opcode('pushProgram', program); this.opcode('pushProgram', inverse); - this.opcode('pushHash'); + this.opcode('emptyHash'); this.opcode('ambiguousBlockValue'); } @@ -977,6 +1034,7 @@ Handlebars.JavaScriptCompiler = function() {}; this.opcode('assignToHash', pair[0]); } + this.opcode('popHash'); }, partial: function(partial) { @@ -1017,17 +1075,19 @@ Handlebars.JavaScriptCompiler = function() {}; }, ambiguousMustache: function(mustache, program, inverse) { - var id = mustache.id, name = id.parts[0]; + var id = mustache.id, + name = id.parts[0], + isBlock = program != null || inverse != null; this.opcode('getContext', id.depth); this.opcode('pushProgram', program); this.opcode('pushProgram', inverse); - this.opcode('invokeAmbiguous', name); + this.opcode('invokeAmbiguous', name, isBlock); }, - simpleMustache: function(mustache, program, inverse) { + simpleMustache: function(mustache) { var id = mustache.id; if (id.type === 'DATA') { @@ -1158,7 +1218,7 @@ Handlebars.JavaScriptCompiler = function() {}; if(mustache.hash) { this.hash(mustache.hash); } else { - this.opcode('pushHash'); + this.opcode('emptyHash'); } return params; @@ -1175,7 +1235,7 @@ Handlebars.JavaScriptCompiler = function() {}; if(mustache.hash) { this.hash(mustache.hash); } else { - this.opcode('pushHash'); + this.opcode('emptyHash'); } return params; @@ -1189,7 +1249,7 @@ Handlebars.JavaScriptCompiler = function() {}; JavaScriptCompiler.prototype = { // PUBLIC API: You can override these methods in a subclass to provide // alternative compiled forms for name lookup and buffering semantics - nameLookup: function(parent, name, type) { + nameLookup: function(parent, name /* , type*/) { if (/^[0-9]+$/.test(name)) { return parent + "[" + name + "]"; } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { @@ -1204,7 +1264,11 @@ Handlebars.JavaScriptCompiler = function() {}; if (this.environment.isSimple) { return "return " + string + ";"; } else { - return "buffer += " + string + ";"; + return { + appendToBuffer: true, + content: string, + toString: function() { return "buffer += " + string + ";"; } + }; } }, @@ -1225,6 +1289,7 @@ Handlebars.JavaScriptCompiler = function() {}; this.isChild = !!context; this.context = context || { programs: [], + environments: [], aliases: { } }; @@ -1234,6 +1299,7 @@ Handlebars.JavaScriptCompiler = function() {}; this.stackVars = []; this.registers = { list: [] }; this.compileStack = []; + this.inlineStack = []; this.compileChildren(environment, options); @@ -1255,11 +1321,11 @@ Handlebars.JavaScriptCompiler = function() {}; }, nextOpcode: function() { - var opcodes = this.environment.opcodes, opcode = opcodes[this.i + 1]; + var opcodes = this.environment.opcodes; return opcodes[this.i + 1]; }, - eat: function(opcode) { + eat: function() { this.i = this.i + 1; }, @@ -1297,7 +1363,6 @@ Handlebars.JavaScriptCompiler = function() {}; // Generate minimizer alias mappings if (!this.isChild) { - var aliases = []; for (var alias in this.context.aliases) { this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias]; } @@ -1322,16 +1387,48 @@ Handlebars.JavaScriptCompiler = function() {}; params.push("depth" + this.environment.depths.list[i]); } + // Perform a second pass over the output to merge content when possible + var source = this.mergeSource(); + + if (!this.isChild) { + var revision = Handlebars.COMPILER_REVISION, + versions = Handlebars.REVISION_CHANGES[revision]; + source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source; + } + if (asObject) { - params.push(this.source.join("\n ")); + params.push(source); return Function.apply(this, params); } else { - var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + this.source.join("\n ") + '}'; + var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}'; Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n"); return functionSource; } }, + mergeSource: function() { + // WARN: We are not handling the case where buffer is still populated as the source should + // not have buffer append operations as their final action. + var source = '', + buffer; + for (var i = 0, len = this.source.length; i < len; i++) { + var line = this.source[i]; + if (line.appendToBuffer) { + if (buffer) { + buffer = buffer + '\n + ' + line.content; + } else { + buffer = line.content; + } + } else { + if (buffer) { + source += 'buffer += ' + buffer + ';\n '; + buffer = undefined; + } + source += line + '\n '; + } + } + return source; + }, // [blockValue] // @@ -1369,6 +1466,9 @@ Handlebars.JavaScriptCompiler = function() {}; var current = this.topStack(); params.splice(1, 0, current); + // Use the options value generated from the invocation + params[params.length-1] = 'options'; + this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }"); }, @@ -1392,6 +1492,9 @@ Handlebars.JavaScriptCompiler = function() {}; // If `value` is truthy, or 0, it is coerced into a string and appended // Otherwise, the empty string is appended append: function() { + // Force anything that is inlined onto the stack so we don't have duplication + // when we examine local + this.flushInline(); var local = this.popStack(); this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }"); if (this.environment.isSimple) { @@ -1406,15 +1509,9 @@ Handlebars.JavaScriptCompiler = function() {}; // // Escape `value` and append it to the buffer appendEscaped: function() { - var opcode = this.nextOpcode(), extra = ""; this.context.aliases.escapeExpression = 'this.escapeExpression'; - if(opcode && opcode.opcode === 'appendContent') { - extra = " + " + this.quotedString(opcode.args[0]); - this.eat(opcode); - } - - this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")" + extra)); + this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")")); }, // [getContext] @@ -1438,7 +1535,7 @@ Handlebars.JavaScriptCompiler = function() {}; // Looks up the value of `name` on the current context and pushes // it onto the stack. lookupOnContext: function(name) { - this.pushStack(this.nameLookup('depth' + this.lastContext, name, 'context')); + this.push(this.nameLookup('depth' + this.lastContext, name, 'context')); }, // [pushContext] @@ -1486,7 +1583,7 @@ Handlebars.JavaScriptCompiler = function() {}; // // Push the result of looking up `id` on the current data lookupData: function(id) { - this.pushStack(this.nameLookup('data', id, 'data')); + this.push(this.nameLookup('data', id, 'data')); }, // [pushStringParam] @@ -1509,13 +1606,25 @@ Handlebars.JavaScriptCompiler = function() {}; } }, - pushHash: function() { - this.push('{}'); + emptyHash: function() { + this.pushStackLiteral('{}'); if (this.options.stringParams) { this.register('hashTypes', '{}'); } }, + pushHash: function() { + this.hash = {values: [], types: []}; + }, + popHash: function() { + var hash = this.hash; + this.hash = undefined; + + if (this.options.stringParams) { + this.register('hashTypes', '{' + hash.types.join(',') + '}'); + } + this.push('{\n ' + hash.values.join(',\n ') + '\n }'); + }, // [pushString] // @@ -1534,7 +1643,8 @@ Handlebars.JavaScriptCompiler = function() {}; // // Push an expression onto the stack push: function(expr) { - this.pushStack(expr); + this.inlineStack.push(expr); + return expr; }, // [pushLiteral] @@ -1577,12 +1687,14 @@ Handlebars.JavaScriptCompiler = function() {}; invokeHelper: function(paramSize, name) { this.context.aliases.helperMissing = 'helpers.helperMissing'; - var helper = this.lastHelper = this.setupHelper(paramSize, name); - this.register('foundHelper', helper.name); + var helper = this.lastHelper = this.setupHelper(paramSize, name, true); - this.pushStack("foundHelper ? foundHelper.call(" + - helper.callParams + ") " + ": helperMissing.call(" + - helper.helperMissingParams + ")"); + this.push(helper.name); + this.replaceStack(function(name) { + return name + ' ? ' + name + '.call(' + + helper.callParams + ") " + ": helperMissing.call(" + + helper.helperMissingParams + ")"; + }); }, // [invokeKnownHelper] @@ -1594,7 +1706,7 @@ Handlebars.JavaScriptCompiler = function() {}; // so a `helperMissing` fallback is not required. invokeKnownHelper: function(paramSize, name) { var helper = this.setupHelper(paramSize, name); - this.pushStack(helper.name + ".call(" + helper.callParams + ")"); + this.push(helper.name + ".call(" + helper.callParams + ")"); }, // [invokeAmbiguous] @@ -1609,19 +1721,18 @@ Handlebars.JavaScriptCompiler = function() {}; // This operation emits more code than the other options, // and can be avoided by passing the `knownHelpers` and // `knownHelpersOnly` flags at compile-time. - invokeAmbiguous: function(name) { + invokeAmbiguous: function(name, helperCall) { this.context.aliases.functionType = '"function"'; - this.pushStackLiteral('{}'); - var helper = this.setupHelper(0, name); + this.pushStackLiteral('{}'); // Hash value + var helper = this.setupHelper(0, name, helperCall); var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); - this.register('foundHelper', helperName); var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context'); var nextStack = this.nextStack(); - this.source.push('if (foundHelper) { ' + nextStack + ' = foundHelper.call(' + helper.callParams + '); }'); + this.source.push('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }'); this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }'); }, @@ -1640,7 +1751,7 @@ Handlebars.JavaScriptCompiler = function() {}; } this.context.aliases.self = "this"; - this.pushStack("self.invokePartial(" + params.join(", ") + ")"); + this.push("self.invokePartial(" + params.join(", ") + ")"); }, // [assignToHash] @@ -1651,17 +1762,19 @@ Handlebars.JavaScriptCompiler = function() {}; // Pops a value and hash off the stack, assigns `hash[key] = value` // and pushes the hash back onto the stack. assignToHash: function(key) { - var value = this.popStack(); + var value = this.popStack(), + type; if (this.options.stringParams) { - var type = this.popStack(); + type = this.popStack(); this.popStack(); - this.source.push("hashTypes['" + key + "'] = " + type + ";"); } - var hash = this.topStack(); - - this.source.push(hash + "['" + key + "'] = " + value + ";"); + var hash = this.hash; + if (type) { + hash.types.push("'" + key + "': " + type); + } + hash.values.push("'" + key + "': (" + value + ")"); }, // HELPERS @@ -1675,11 +1788,27 @@ Handlebars.JavaScriptCompiler = function() {}; child = children[i]; compiler = new this.compiler(); - this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children - var index = this.context.programs.length; - child.index = index; - child.name = 'program' + index; - this.context.programs[index] = compiler.compile(child, options, this.context); + var index = this.matchExistingProgram(child); + + if (index == null) { + this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children + index = this.context.programs.length; + child.index = index; + child.name = 'program' + index; + this.context.programs[index] = compiler.compile(child, options, this.context); + this.context.environments[index] = child; + } else { + child.index = index; + child.name = 'program' + index; + } + } + }, + matchExistingProgram: function(child) { + for (var i = 0, len = this.context.environments.length; i < len; i++) { + var environment = this.context.environments[i]; + if (environment && environment.equals(child)) { + return i; + } } }, @@ -1723,57 +1852,111 @@ Handlebars.JavaScriptCompiler = function() {}; }, pushStackLiteral: function(item) { - this.compileStack.push(new Literal(item)); - return item; + return this.push(new Literal(item)); }, pushStack: function(item) { + this.flushInline(); + var stack = this.incrStack(); - this.source.push(stack + " = " + item + ";"); + if (item) { + this.source.push(stack + " = " + item + ";"); + } this.compileStack.push(stack); return stack; }, replaceStack: function(callback) { - var stack = this.topStack(), - item = callback.call(this, stack); + var prefix = '', + inline = this.isInline(), + stack; - // Prevent modification of the context depth variable. Through replaceStack - if (/^depth/.test(stack)) { - stack = this.nextStack(); + // If we are currently inline then we want to merge the inline statement into the + // replacement statement via ',' + if (inline) { + var top = this.popStack(true); + + if (top instanceof Literal) { + // Literals do not need to be inlined + stack = top.value; + } else { + // Get or create the current stack name for use by the inline + var name = this.stackSlot ? this.topStackName() : this.incrStack(); + + prefix = '(' + this.push(name) + ' = ' + top + '),'; + stack = this.topStack(); + } + } else { + stack = this.topStack(); } - this.source.push(stack + " = " + item + ";"); + var item = callback.call(this, stack); + + if (inline) { + if (this.inlineStack.length || this.compileStack.length) { + this.popStack(); + } + this.push('(' + prefix + item + ')'); + } else { + // Prevent modification of the context depth variable. Through replaceStack + if (!/^stack/.test(stack)) { + stack = this.nextStack(); + } + + this.source.push(stack + " = (" + prefix + item + ");"); + } return stack; }, - nextStack: function(skipCompileStack) { - var name = this.incrStack(); - this.compileStack.push(name); - return name; + nextStack: function() { + return this.pushStack(); }, incrStack: function() { this.stackSlot++; if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } + return this.topStackName(); + }, + topStackName: function() { return "stack" + this.stackSlot; }, + flushInline: function() { + var inlineStack = this.inlineStack; + if (inlineStack.length) { + this.inlineStack = []; + for (var i = 0, len = inlineStack.length; i < len; i++) { + var entry = inlineStack[i]; + if (entry instanceof Literal) { + this.compileStack.push(entry); + } else { + this.pushStack(entry); + } + } + } + }, + isInline: function() { + return this.inlineStack.length; + }, - popStack: function() { - var item = this.compileStack.pop(); + popStack: function(wrapped) { + var inline = this.isInline(), + item = (inline ? this.inlineStack : this.compileStack).pop(); - if (item instanceof Literal) { + if (!wrapped && (item instanceof Literal)) { return item.value; } else { - this.stackSlot--; + if (!inline) { + this.stackSlot--; + } return item; } }, - topStack: function() { - var item = this.compileStack[this.compileStack.length - 1]; + topStack: function(wrapped) { + var stack = (this.isInline() ? this.inlineStack : this.compileStack), + item = stack[stack.length - 1]; - if (item instanceof Literal) { + if (!wrapped && (item instanceof Literal)) { return item.value; } else { return item; @@ -1788,22 +1971,22 @@ Handlebars.JavaScriptCompiler = function() {}; .replace(/\r/g, '\\r') + '"'; }, - setupHelper: function(paramSize, name) { + setupHelper: function(paramSize, name, missingParams) { var params = []; - this.setupParams(paramSize, params); + this.setupParams(paramSize, params, missingParams); var foundHelper = this.nameLookup('helpers', name, 'helper'); return { params: params, name: foundHelper, callParams: ["depth0"].concat(params).join(", "), - helperMissingParams: ["depth0", this.quotedString(name)].concat(params).join(", ") + helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ") }; }, // the params and contexts arguments are passed in arrays // to fill in - setupParams: function(paramSize, params) { + setupParams: function(paramSize, params, useRegister) { var options = [], contexts = [], types = [], param, inverse, program; options.push("hash:" + this.popStack()); @@ -1848,7 +2031,13 @@ Handlebars.JavaScriptCompiler = function() {}; options.push("data:data"); } - params.push("{" + options.join(",") + "}"); + options = "{" + options.join(",") + "}"; + if (useRegister) { + this.register('options', options); + params.push('options'); + } else { + params.push(options); + } return params.join(", "); } }; @@ -1886,23 +2075,23 @@ Handlebars.JavaScriptCompiler = function() {}; })(Handlebars.Compiler, Handlebars.JavaScriptCompiler); -Handlebars.precompile = function(string, options) { - if (typeof string !== 'string') { - throw new Handlebars.Exception("You must pass a string to Handlebars.compile. You passed " + string); +Handlebars.precompile = function(input, options) { + if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { + throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input); } options = options || {}; if (!('data' in options)) { options.data = true; } - var ast = Handlebars.parse(string); + var ast = Handlebars.parse(input); var environment = new Handlebars.Compiler().compile(ast, options); return new Handlebars.JavaScriptCompiler().compile(environment, options); }; -Handlebars.compile = function(string, options) { - if (typeof string !== 'string') { - throw new Handlebars.Exception("You must pass a string to Handlebars.compile. You passed " + string); +Handlebars.compile = function(input, options) { + if (!input || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) { + throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input); } options = options || {}; @@ -1911,7 +2100,7 @@ Handlebars.compile = function(string, options) { } var compiled; function compile() { - var ast = Handlebars.parse(string); + var ast = Handlebars.parse(input); var environment = new Handlebars.Compiler().compile(ast, options); var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true); return Handlebars.template(templateSpec); @@ -1946,12 +2135,32 @@ Handlebars.VM = { } }, programWithDepth: Handlebars.VM.programWithDepth, - noop: Handlebars.VM.noop + noop: Handlebars.VM.noop, + compilerInfo: null }; return function(context, options) { options = options || {}; - return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data); + var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data); + + var compilerInfo = container.compilerInfo || [], + compilerRevision = compilerInfo[0] || 1, + currentRevision = Handlebars.COMPILER_REVISION; + + if (compilerRevision !== currentRevision) { + if (compilerRevision < currentRevision) { + var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision], + compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision]; + throw "Template was precompiled with an older version of Handlebars than the current runtime. "+ + "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."; + } else { + // Use the embedded version info since the runtime doesn't know about this revision yet + throw "Template was precompiled with a newer version of Handlebars than the current runtime. "+ + "Please update your runtime to a newer version ("+compilerInfo[1]+")."; + } + } + + return result; }; }, @@ -1990,4 +2199,3 @@ Handlebars.VM = { Handlebars.template = Handlebars.VM.template; ; - diff --git a/vendor/gems/message_bus/assets/index.handlebars b/vendor/gems/message_bus/assets/index.handlebars index 340249ec6e1..6c2b053d38d 100644 --- a/vendor/gems/message_bus/assets/index.handlebars +++ b/vendor/gems/message_bus/assets/index.handlebars @@ -1 +1,25 @@ + + + + + + + + + + + + + + {{#each processes}} + + + + + + + + {{/each}} + +
pidfull_pathhostnameuptime
{{pid}}{{full_path}}{{hostname}}{{uptime}} secs
diff --git a/vendor/gems/message_bus/assets/message-bus.js b/vendor/gems/message_bus/assets/message-bus.js index bec7c2344ef..1a19d1577f1 100644 --- a/vendor/gems/message_bus/assets/message-bus.js +++ b/vendor/gems/message_bus/assets/message-bus.js @@ -39,7 +39,7 @@ window.MessageBus = (function() { callback.last_id = message.message_id; callback.func(message.data); } - if (message["channel"] === "/__status") { + if (message.channel === "/__status") { if (message.data[callback.channel] !== void 0) { callback.last_id = message.data[callback.channel]; } @@ -60,7 +60,7 @@ window.MessageBus = (function() { start: function(opts) { var poll, _this = this; - if (opts == null) { + if (opts === null) { opts = {}; } poll = function() { diff --git a/vendor/gems/message_bus/lib/message_bus.rb b/vendor/gems/message_bus/lib/message_bus.rb index 1948e74c778..3d144892a2a 100644 --- a/vendor/gems/message_bus/lib/message_bus.rb +++ b/vendor/gems/message_bus/lib/message_bus.rb @@ -9,6 +9,7 @@ require "message_bus/reliable_pub_sub" require "message_bus/client" require "message_bus/connection_manager" require "message_bus/message_handler" +require "message_bus/diagnostics" require "message_bus/rack/middleware" require "message_bus/rack/diagnostics" @@ -126,9 +127,7 @@ module MessageBus::Implementation end def enable_diagnostics - subscribe('/discover') do |msg| - MessageBus.publish '/process-discovery', Process.pid, user_id: msg.data[:user_id] - end + MessageBus::Diagnostics.enable end def publish(channel, data, opts = nil) diff --git a/vendor/gems/message_bus/lib/message_bus/diagnostics.rb b/vendor/gems/message_bus/lib/message_bus/diagnostics.rb new file mode 100644 index 00000000000..8d8d34f8d86 --- /dev/null +++ b/vendor/gems/message_bus/lib/message_bus/diagnostics.rb @@ -0,0 +1,44 @@ +class MessageBus::Diagnostics + def self.full_process_path + begin + info = `ps -eo "%p|$|%a" | grep '^\\s*#{Process.pid}'` + info.strip.split('|$|')[1] + rescue + # skip it ... not linux or something weird + end + end + + def self.hostname + begin + `hostname`.strip + rescue + # skip it + end + end + + def self.enable + full_path = full_process_path + start_time = Time.now.to_f + hostname = self.hostname + + # it may make sense to add a channel per machine/host to streamline + # process to process comms + MessageBus.subscribe('/_diagnostics/hup') do |msg| + if Process.pid == msg.data["pid"] && hostname == msg.data["hostname"] + $shutdown = true + sleep 4 + Process.kill("HUP", $$) + end + end + + MessageBus.subscribe('/_diagnostics/discover') do |msg| + MessageBus.publish '/_diagnostics/process-discovery', { + pid: Process.pid, + process_name: $0, + full_path: full_path, + uptime: (Time.now.to_f - start_time).to_i, + hostname: hostname + }, user_ids: [msg.data["user_id"]] + end + end +end diff --git a/vendor/gems/message_bus/lib/message_bus/rack/diagnostics.rb b/vendor/gems/message_bus/lib/message_bus/rack/diagnostics.rb index a286a4d5ebc..85f7fbeebaa 100644 --- a/vendor/gems/message_bus/lib/message_bus/rack/diagnostics.rb +++ b/vendor/gems/message_bus/lib/message_bus/rack/diagnostics.rb @@ -38,7 +38,7 @@ class MessageBus::Rack::Diagnostics
#{js_asset "jquery-1.8.2.js"} - #{js_asset "handlebars-1.0.rc.2.js"} + #{js_asset "handlebars.js"} #{js_asset "ember.js"} #{js_asset "message-bus.js"} #{js_asset "application.handlebars"} @@ -72,7 +72,14 @@ HTML return index unless route if route == '/discover' - MessageBus.publish('/discover', {user_id: MessageBus.user_id_lookup.call(env)}) + user_id = MessageBus.user_id_lookup.call(env) + MessageBus.publish('/_diagnostics/discover', user_id: user_id) + return [200, {}, ['ok']] + end + + if route =~ /^\/hup\// + hostname, pid = route.split('/hup/')[1].split('/') + MessageBus.publish('/_diagnostics/hup', {hostname: hostname, pid: pid.to_i}) return [200, {}, ['ok']] end diff --git a/vendor/gems/message_bus/lib/message_bus/rack/middleware.rb b/vendor/gems/message_bus/lib/message_bus/rack/middleware.rb index f240266a4f0..121d8144a3e 100644 --- a/vendor/gems/message_bus/lib/message_bus/rack/middleware.rb +++ b/vendor/gems/message_bus/lib/message_bus/rack/middleware.rb @@ -9,6 +9,8 @@ class MessageBus::Rack::Middleware def self.start_listener unless @started_listener MessageBus.subscribe do |msg| + p msg.channel + p msg.message_id EM.next_tick do @@connection_manager.notify_clients(msg) if @@connection_manager end