From f675a7e01d292c7aa6f79e33ae697c5c23ef049b Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Wed, 16 Jan 2013 20:38:52 +0100 Subject: [PATCH] js: Make 'Mopidy()' work without 'new' --- js/src/mopidy.js | 4 ++++ js/test/mopidy-test.js | 9 +++++++++ mopidy/frontends/http/data/mopidy.js | 8 ++++++-- mopidy/frontends/http/data/mopidy.min.js | 6 +++--- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/js/src/mopidy.js b/js/src/mopidy.js index 3485b442..5a75a836 100644 --- a/js/src/mopidy.js +++ b/js/src/mopidy.js @@ -1,6 +1,10 @@ /*global bane:false, when:false*/ function Mopidy(settings) { + if (!(this instanceof Mopidy)) { + return new Mopidy(settings); + } + this._settings = this._configure(settings || {}); this._console = this._getConsole(); diff --git a/js/test/mopidy-test.js b/js/test/mopidy-test.js index 7dcc5972..8842ebf4 100644 --- a/js/test/mopidy-test.js +++ b/js/test/mopidy-test.js @@ -48,6 +48,15 @@ buster.testCase("Mopidy", { new Mopidy({webSocket: {}}); refute.called(this.webSocketConstructorStub); + }, + + "works without 'new' keyword": function () { + var mopidyConstructor = Mopidy; // To trick jshint into submission + + var mopidy = mopidyConstructor({webSocket: {}}); + + assert.isObject(mopidy); + assert(mopidy instanceof Mopidy); } }, diff --git a/mopidy/frontends/http/data/mopidy.js b/mopidy/frontends/http/data/mopidy.js index 5b022c0c..f41695e6 100644 --- a/mopidy/frontends/http/data/mopidy.js +++ b/mopidy/frontends/http/data/mopidy.js @@ -1,6 +1,6 @@ -/*! Mopidy.js - built 2012-12-04 +/*! Mopidy.js - built 2013-01-16 * http://www.mopidy.com/ - * Copyright (c) 2012 Stein Magnus Jodal and contributors + * Copyright (c) 2013 Stein Magnus Jodal and contributors * Licensed under the Apache License, Version 2.0 */ /** @@ -910,6 +910,10 @@ define(['module'], function () { /*global bane:false, when:false*/ function Mopidy(settings) { + if (!(this instanceof Mopidy)) { + return new Mopidy(settings); + } + this._settings = this._configure(settings || {}); this._console = this._getConsole(); diff --git a/mopidy/frontends/http/data/mopidy.min.js b/mopidy/frontends/http/data/mopidy.min.js index 797b47ec..e727cefd 100644 --- a/mopidy/frontends/http/data/mopidy.min.js +++ b/mopidy/frontends/http/data/mopidy.min.js @@ -1,5 +1,5 @@ -/*! Mopidy.js - built 2012-12-04 +/*! Mopidy.js - built 2013-01-16 * http://www.mopidy.com/ - * Copyright (c) 2012 Stein Magnus Jodal and contributors + * Copyright (c) 2013 Stein Magnus Jodal and contributors * Licensed under the Apache License, Version 2.0 */ -function Mopidy(e){this._settings=this._configure(e||{}),this._console=this._getConsole(),this._backoffDelay=this._settings.backoffDelayMin,this._pendingRequests={},this._webSocket=null,bane.createEventEmitter(this),this._delegateEvents(),this._settings.autoConnect&&this.connect()}(typeof define=="function"&&define.amd&&function(e){define(e)}||typeof module=="object"&&function(e){module.exports=e()}||function(e){this.bane=e()})(function(){"use strict";function t(e,t,n){var r,i=n.length;if(i>0){for(r=0;r>>0,o=Math.max(0,Math.min(t,v)),a=[],u=v-o+1,l=[],c=f();if(!o)c.resolve(a);else{d=c.progress,p=function(e){l.push(e),--u||(h=p=w,c.reject(l))},h=function(e){a.push(e),--o||(h=p=w,c.resolve(a))};for(m=0;m>>0,n=[],l=f();if(!s)l.resolve(n);else{u=l.reject,o=function(i,o){r(i,t).then(function(e){n[o]=e,--s||l.resolve(n)},u)};for(a=0;a2;return r(e,function(e){return t.resolve(i?n:e)},t.reject,t.progress)}function y(e,t){var n,r=0;while(n=e[r++])n(t)}function b(e,t){var n,r=t.length;while(r>e){n=t[--r];if(n!=null&&typeof n!="function")throw new Error("arg "+r+" must be a function")}}function w(){}function E(e){return e}var e,t,n;return r.defer=f,r.resolve=i,r.reject=s,r.join=d,r.all=p,r.some=c,r.any=h,r.map=v,r.reduce=m,r.chain=g,r.isPromise=l,o.prototype={always:function(e,t){return this.then(e,e,t)},otherwise:function(e){return this.then(n,e)}},t=[].slice,e=[].reduce||function(e){var t,n,r,i,s;s=0,t=Object(this),i=t.length>>>0,n=arguments;if(n.length<=1)for(;;){if(s in t){r=t[s++];break}if(++s>=i)throw new TypeError}else r=n[1];for(;sthis._settings.backoffDelayMax&&(this._backoffDelay=this._settings.backoffDelayMax)},Mopidy.prototype._resetBackoffDelay=function(){this._backoffDelay=this._settings.backoffDelayMin},Mopidy.prototype.close=function(){this.off("state:offline",this._reconnect),this._webSocket.close()},Mopidy.prototype._handleWebSocketError=function(e){this._console.warn("WebSocket error:",e.stack||e)},Mopidy.prototype._send=function(e){var t=when.defer();switch(this._webSocket.readyState){case WebSocket.CONNECTING:t.resolver.reject({message:"WebSocket is still connecting"});break;case WebSocket.CLOSING:t.resolver.reject({message:"WebSocket is closing"});break;case WebSocket.CLOSED:t.resolver.reject({message:"WebSocket is closed"});break;default:e.jsonrpc="2.0",e.id=this._nextRequestId(),this._pendingRequests[e.id]=t.resolver,this._webSocket.send(JSON.stringify(e)),this.emit("websocket:outgoingMessage",e)}return t.promise},Mopidy.prototype._nextRequestId=function(){var e=-1;return function(){return e+=1,e}}(),Mopidy.prototype._handleMessage=function(e){try{var t=JSON.parse(e.data);t.hasOwnProperty("id")?this._handleResponse(t):t.hasOwnProperty("event")?this._handleEvent(t):this._console.warn("Unknown message type received. Message was: "+e.data)}catch(n){if(!(n instanceof SyntaxError))throw n;this._console.warn("WebSocket message parsing failed. Message was: "+e.data)}},Mopidy.prototype._handleResponse=function(e){if(!this._pendingRequests.hasOwnProperty(e.id)){this._console.warn("Unexpected response received. Message was:",e);return}var t=this._pendingRequests[e.id];delete this._pendingRequests[e.id],e.hasOwnProperty("result")?t.resolve(e.result):e.hasOwnProperty("error")?(t.reject(e.error),this._console.warn("Server returned error:",e.error)):(t.reject({message:"Response without 'result' or 'error' received",data:{response:e}}),this._console.warn("Response without 'result' or 'error' received. Message was:",e))},Mopidy.prototype._handleEvent=function(e){var t=e.event,n=e;delete n.event,this.emit("event:"+this._snakeToCamel(t),n)},Mopidy.prototype._getApiSpec=function(){this._send({method:"core.describe"}).then(this._createApi.bind(this),this._handleWebSocketError).then(null,this._handleWebSocketError)},Mopidy.prototype._createApi=function(e){var t=function(e){return function(){var t=Array.prototype.slice.call(arguments);return this._send({method:e,params:t})}.bind(this)}.bind(this),n=function(e){var t=e.split(".");return t.length>=1&&t[0]==="core"&&(t=t.slice(1)),t},r=function(e){var t=this;return e.forEach(function(e){e=this._snakeToCamel(e),t[e]=t[e]||{},t=t[e]}.bind(this)),t}.bind(this),i=function(i){var s=n(i),o=this._snakeToCamel(s.slice(-1)[0]),u=r(s.slice(0,-1));u[o]=t(i),u[o].description=e[i].description,u[o].params=e[i].params}.bind(this);Object.keys(e).forEach(i),this.emit("state:online")},Mopidy.prototype._snakeToCamel=function(e){return e.replace(/(_[a-z])/g,function(e){return e.toUpperCase().replace("_","")})}; \ No newline at end of file +function Mopidy(e){if(!(this instanceof Mopidy))return new Mopidy(e);this._settings=this._configure(e||{}),this._console=this._getConsole(),this._backoffDelay=this._settings.backoffDelayMin,this._pendingRequests={},this._webSocket=null,bane.createEventEmitter(this),this._delegateEvents(),this._settings.autoConnect&&this.connect()}(typeof define=="function"&&define.amd&&function(e){define(e)}||typeof module=="object"&&function(e){module.exports=e()}||function(e){this.bane=e()})(function(){"use strict";function t(e,t,n){var r,i=n.length;if(i>0){for(r=0;r>>0,o=Math.max(0,Math.min(t,v)),a=[],u=v-o+1,l=[],c=f();if(!o)c.resolve(a);else{d=c.progress,p=function(e){l.push(e),--u||(h=p=w,c.reject(l))},h=function(e){a.push(e),--o||(h=p=w,c.resolve(a))};for(m=0;m>>0,n=[],l=f();if(!s)l.resolve(n);else{u=l.reject,o=function(i,o){r(i,t).then(function(e){n[o]=e,--s||l.resolve(n)},u)};for(a=0;a2;return r(e,function(e){return t.resolve(i?n:e)},t.reject,t.progress)}function y(e,t){var n,r=0;while(n=e[r++])n(t)}function b(e,t){var n,r=t.length;while(r>e){n=t[--r];if(n!=null&&typeof n!="function")throw new Error("arg "+r+" must be a function")}}function w(){}function E(e){return e}var e,t,n;return r.defer=f,r.resolve=i,r.reject=s,r.join=d,r.all=p,r.some=c,r.any=h,r.map=v,r.reduce=m,r.chain=g,r.isPromise=l,o.prototype={always:function(e,t){return this.then(e,e,t)},otherwise:function(e){return this.then(n,e)}},t=[].slice,e=[].reduce||function(e){var t,n,r,i,s;s=0,t=Object(this),i=t.length>>>0,n=arguments;if(n.length<=1)for(;;){if(s in t){r=t[s++];break}if(++s>=i)throw new TypeError}else r=n[1];for(;sthis._settings.backoffDelayMax&&(this._backoffDelay=this._settings.backoffDelayMax)},Mopidy.prototype._resetBackoffDelay=function(){this._backoffDelay=this._settings.backoffDelayMin},Mopidy.prototype.close=function(){this.off("state:offline",this._reconnect),this._webSocket.close()},Mopidy.prototype._handleWebSocketError=function(e){this._console.warn("WebSocket error:",e.stack||e)},Mopidy.prototype._send=function(e){var t=when.defer();switch(this._webSocket.readyState){case WebSocket.CONNECTING:t.resolver.reject({message:"WebSocket is still connecting"});break;case WebSocket.CLOSING:t.resolver.reject({message:"WebSocket is closing"});break;case WebSocket.CLOSED:t.resolver.reject({message:"WebSocket is closed"});break;default:e.jsonrpc="2.0",e.id=this._nextRequestId(),this._pendingRequests[e.id]=t.resolver,this._webSocket.send(JSON.stringify(e)),this.emit("websocket:outgoingMessage",e)}return t.promise},Mopidy.prototype._nextRequestId=function(){var e=-1;return function(){return e+=1,e}}(),Mopidy.prototype._handleMessage=function(e){try{var t=JSON.parse(e.data);t.hasOwnProperty("id")?this._handleResponse(t):t.hasOwnProperty("event")?this._handleEvent(t):this._console.warn("Unknown message type received. Message was: "+e.data)}catch(n){if(!(n instanceof SyntaxError))throw n;this._console.warn("WebSocket message parsing failed. Message was: "+e.data)}},Mopidy.prototype._handleResponse=function(e){if(!this._pendingRequests.hasOwnProperty(e.id)){this._console.warn("Unexpected response received. Message was:",e);return}var t=this._pendingRequests[e.id];delete this._pendingRequests[e.id],e.hasOwnProperty("result")?t.resolve(e.result):e.hasOwnProperty("error")?(t.reject(e.error),this._console.warn("Server returned error:",e.error)):(t.reject({message:"Response without 'result' or 'error' received",data:{response:e}}),this._console.warn("Response without 'result' or 'error' received. Message was:",e))},Mopidy.prototype._handleEvent=function(e){var t=e.event,n=e;delete n.event,this.emit("event:"+this._snakeToCamel(t),n)},Mopidy.prototype._getApiSpec=function(){this._send({method:"core.describe"}).then(this._createApi.bind(this),this._handleWebSocketError).then(null,this._handleWebSocketError)},Mopidy.prototype._createApi=function(e){var t=function(e){return function(){var t=Array.prototype.slice.call(arguments);return this._send({method:e,params:t})}.bind(this)}.bind(this),n=function(e){var t=e.split(".");return t.length>=1&&t[0]==="core"&&(t=t.slice(1)),t},r=function(e){var t=this;return e.forEach(function(e){e=this._snakeToCamel(e),t[e]=t[e]||{},t=t[e]}.bind(this)),t}.bind(this),i=function(i){var s=n(i),o=this._snakeToCamel(s.slice(-1)[0]),u=r(s.slice(0,-1));u[o]=t(i),u[o].description=e[i].description,u[o].params=e[i].params}.bind(this);Object.keys(e).forEach(i),this.emit("state:online")},Mopidy.prototype._snakeToCamel=function(e){return e.replace(/(_[a-z])/g,function(e){return e.toUpperCase().replace("_","")})}; \ No newline at end of file