Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

v1.5 abstracts try/catch and adds a new internal event. Random keys a…

…re shorter and guaranteed to be unique
  • Loading branch information...
commit 468a9ef25df4078cc461e130712e7baaae9bb82f 1 parent be9aa7e
@jgnewman authored
Showing with 100 additions and 10 deletions.
  1. +46 −3 README.md
  2. +3 −1 shotgun-min.js
  3. +51 −6 shotgun.js
View
49 README.md
@@ -35,8 +35,8 @@ the name of the event your function will subscribe to. The **action** property
invoked when the event is fired. But the real secret to Shotgun.js is the **key** property.
With the **key** property you can uniquely name each of your individual subscriptions. If you do not pass a **key**
-property to **SHOTGUN.listen**, a random 64 character key will be generated for you. **SHOTGUN.listen** returns your
-subscription key so that you will have it available for use in the future.
+property to **SHOTGUN.listen**, a random 24 character key will be generated for you. **SHOTGUN.listen** returns your
+subscription key so that you will have it available for use in the future. All random keys are guaranteed to be unique.
You can subscribe as many functions to an event name as you want but you can not subscribe more than one function using
the same key. If you try to give two subscriptions the same **key**, the first subscription will disappear, being
@@ -71,7 +71,7 @@ var eventKey3 = SHOTGUN.listen({
}
});
-// returns something like => '.o:/u@D{#NLtr:PsKCIei_c.4c{9lP@Rv=c|N_NQeI6S*J9JcT?8#Evn*9t:UMBA'
+// returns something like => 'rJkB3oeekYLdQDvgG4LaRB9Y'
```
@@ -136,6 +136,41 @@ SHOTGUN.remove({"event" : "myCustomEvent"});
```
+## Better Error Handling
+
+As of v1.5 Shotgun makes it so you never have to write another ugly try/catch block ever again. Take a look at the
+following code:
+
+```javascript
+
+function parseJSON(obj) {
+ SHOTGUN.try({
+ "event" : "parseJSON",
+ "action" : function () {
+ JSON.parse(obj);
+ }
+ });
+}
+
+SHOTGUN.listen({
+ "event" : "parseJSON".
+ "action" : function (err) {
+ doSomethingWith(err);
+ }
+});
+
+parseJSON('asdfasdfasdfadefasdf');
+// Error caught. Launches doSomethingWith(err);
+
+
+```
+
+In the above code we define a function that calls **SHOTGUN.try** rather than setting up a traditional try block.
+**SHOTGUN.try** runs a try under the hood and publishes the error to an events channel for you within the catch block
+if an error occurs. This way, you can catch the error with **SHOTGUN.listen** and completely decouple your error
+handling from your normal work flow. In fact, you can even catch multiple errors with a single **.listen** and,
+if you wanted to, recursively call your try block again using the events channel.
+
## Internal Events
You might be interested to know that Shotgun publishes events for you to trap whenever you make a subscription or
@@ -171,6 +206,14 @@ SHOTGUN.listen({
}
});
+// tryError -> Fired any time SHOTGUN.try publishes an error
+SHOTGUN.listen({
+ "event" : "tryError",
+ "action" : function (err) {
+ // err === the error object
+ }
+});
+
```
## Keeping Track
View
4 shotgun-min.js
@@ -3,4 +3,6 @@ Name: shotgun.js
Author: John Newman
License: MIT
*/
-(function(a){"use strict";var b={},v='1.0',x;function c(){var i,g='',h='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz_`~!?.,<>@#$%^*()[]{}|+=-/&:;';for(i=0;i<64;i+=1){g+=h[Math.floor(Math.random()*h.length)];}return g;}function d(m){var i,g,h,j,k=b[m.event];if(k&&k[m.key]){if(typeof m.key==='string'){m.key=[m.key];}h=m.key.length;for(i=0;i<h;i+=1){g=k[m.key[i]];j=g.action;if(j){j.apply(null,m.args);}}}else if(k&&!k[m.key]){for(i in k){if(Object.prototype.hasOwnProperty.call(k,i)){k[i].action.apply(null,m.args);}}}}function e(h){var g=h.key||c();b[h.event]=b[h.event]||{};b[h.event][g]={"action":h.action};d({"event":"newListener","args":[h]});return g;}function f(h){if(!h.key){if(b[h.event]){delete b[h.event];d({"event":"rmEvent","args":[h.event]});return true;}else{return false;}}if(b[h.event][h.key]){delete b[h.event][h.key];d({"event":"rmListener","args":[h.event,h.key]});return true;}else{return false;}}x={"fire":function(g){return d(g);},"listen":function(g){return e(g);},"remove":function(g){return f(g);},"events":function(){return b;},"version":v};if(a.define&&typeof a.define==='function'&&a.define.amd){a.define('shotgun',[],sg);}else if(a.module&&a.module.exports){a.module.exports=sg;}else{a['SHOTGUN']=a['SG']=sg;}}(this));
+(function(a){"use strict";var b={},c={},d='1.5',e;function f(){var i,m='',n='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz';for(i=0;i<24;i+=1){m+=n[Math.floor(Math.random()*n.length)];}if(!c[m]){c[m]=true;return m;}else{return f();}}function g(q){var i,m,n,o,p=b[q.event];if(p&&p[q.key]){if(typeof q.key==='string'){q.key=[q.key];}n=q.key.length;for(i=0;i<n;i+=1){m=p[q.key[i]];o=m.action;if(o){o.apply(null,q.args);}}}else if(p&&!p[q.key]){for(i in p){if(Object.prototype.hasOwnProperty.call(p,i)){p[i].action.apply(null,q.args);}}}}function h(n){var m=n.key||f();b[n.event]=b[n.event]||{};b[n.event][m]={"action":n.action};g({"event":"newListener","args":[n]});return m;}function j(m){var i;if(!m.key){if(b[m.event]){for(i in b[m.event]){if(Object.prototype.hasOwnProperty.call(b[m.event],i)){delete c[i];}}delete b[m.event];g({"event":"rmEvent","args":[m.event]});return true;}else{return false;}}if(b[m.event][m.key]){delete b[m.event][m.key];delete c[m.key];g({"event":"rmListener","args":[m.event,m.key]});return true;}else{return false;}}function k(n){var m=n.key||null;
+try{n.action();}catch(p){g({"event":n.event,"key":m,"args":[p]});if(n.event!=='tryError'){g({"event":"tryError","key":m,"args":[p]});}}}e={"fire":function(m){return g(m);},"listen":function(m){return h(m);},"remove":function(m){return j(m);},"events":function(){return b;},
+"try":function(m){return k(m);},"version":d};if(a.define&&typeof a.define==='function'&&a.define.amd){a.define('SHOTGUN',[],e);}else if(a.module&&a.module.exports){a.module.exports=e;}else{a['SHOTGUN']=a['SG']=e;}}(this));
View
57 shotgun.js
@@ -4,30 +4,47 @@ Name: shotgun.js
Author: John Newman
Date: 12/22/2011
License: MIT
-Version: 1.0
+Version: 1.5
Description: Smarter than your average pubsub library. Small and fast.
Contains trappable internal events and gives you lots of control over your subscriptions.
+As of v1.5:
+ Contains an event-based abstraction of the try/catch block. You can now
+ decouple your error handling from your work flow, set multiple tries to a single catch,
+ and even indirectly call your try recursively through an events channel.
+
+ Unique keys are now shorter and SHOTGUN will run a test to make sure generated keys are actually unique.
+
+ Contains a new trappable event: tryError
+
Internal events you can trap:
newListener -> Fired any time a new subscription is made. Gives you an object containing the event, key, and action.
rmEvent -> Fired any time you remove an entire group of actions by event name. Gives you the name of the event removed.
rmListener -> Fired any time you unsubscribe a single action by key. Gives you the name of the event and the name of the key.
+ tryError -> Fired any time SHOTGUN.try() publishes an error.
*/
+// ! We're almost there. Figure out a way to put catches underneath tries?
+
(function (context) {
"use strict";
- var eventsObj = {}, version = '1.0', sg;
+ var eventsObj = {}, keysUsed = {}, version = '1.5', sg;
// Function for generating random strings
function genUnique() {
- var i, newStr = '', chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz_`~!?.,<>@#$%^*()[]{}|+=-/&:;';
- for (i = 0; i < 64; i += 1) {
+ var i, newStr = '', chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz';
+ for (i = 0; i < 24; i += 1) {
newStr += chars[Math.floor(Math.random() * chars.length)];
}
- return newStr;
+ if (!keysUsed[newStr]) {
+ keysUsed[newStr] = true;
+ return newStr;
+ } else {
+ return genUnique();
+ }
}
// General publish function {event, key, args}
@@ -78,8 +95,16 @@ Internal events you can trap:
// General unsubscribe function {event, key}
function unsubscribe(obj) {
+ var i;
if (!obj.key) {
if (eventsObj[obj.event]) {
+ // Free up all previously used keys in the event
+ for (i in eventsObj[obj.event]) {
+ if (Object.prototype.hasOwnProperty.call(eventsObj[obj.event], i)) {
+ delete keysUsed[i];
+ }
+ }
+ // Delete the event
delete eventsObj[obj.event];
publish({"event" : "rmEvent", "args" : [obj.event]});
return true;
@@ -88,7 +113,10 @@ Internal events you can trap:
}
}
if (eventsObj[obj.event][obj.key]) {
+ // Delete the event
delete eventsObj[obj.event][obj.key];
+ // Free up the used key
+ delete keysUsed[obj.key];
publish({"event" : "rmListener", "args" : [obj.event, obj.key]});
return true;
} else {
@@ -96,6 +124,19 @@ Internal events you can trap:
}
}
+ // Try/catch abstraction function {event, key, action}
+ function attempt(obj) {
+ var key = obj.key || null;
+ try {
+ obj.action();
+ } catch (err) {
+ publish({"event" : obj.event, "key" : key, "args" : [err]});
+ if (obj.event !== 'tryError') {
+ publish({"event" : "tryError", "key" : key, "args" : [err]});
+ }
+ }
+ }
+
sg = {
"fire" : function (obj) {
@@ -114,6 +155,10 @@ Internal events you can trap:
return eventsObj;
},
+ "try" : function (obj) {
+ return attempt(obj);
+ },
+
"version" : version
};
@@ -122,7 +167,7 @@ Internal events you can trap:
// AMD
if (context.define && typeof context.define === 'function' && context.define.amd) {
- context.define('shotgun', [], sg);
+ context.define('SHOTGUN', [], sg);
//node
} else if (context.module && context.module.exports) {
context.module.exports = sg;
Please sign in to comment.
Something went wrong with that request. Please try again.