Skip to content

Commit

Permalink
v1.5 abstracts try/catch and adds a new internal event. Random keys a…
Browse files Browse the repository at this point in the history
…re shorter and guaranteed to be unique
  • Loading branch information
jgnewman committed Jan 12, 2012
1 parent be9aa7e commit 468a9ef
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 10 deletions.
49 changes: 46 additions & 3 deletions README.md
Expand Up @@ -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
Expand Down Expand Up @@ -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'

```

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion shotgun-min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 51 additions & 6 deletions shotgun.js
Expand Up @@ -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}
Expand Down Expand Up @@ -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;
Expand All @@ -88,14 +113,30 @@ 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 {
return false;
}
}

// 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) {
Expand All @@ -114,6 +155,10 @@ Internal events you can trap:
return eventsObj;
},

"try" : function (obj) {
return attempt(obj);
},

"version" : version

};
Expand All @@ -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;
Expand Down

0 comments on commit 468a9ef

Please sign in to comment.