npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hooked

v0.1.3

Published

A simple javascript/node.js base type supporting before and after hooks over functions.

Downloads

25

Readme

hooked Build Status

A simple javascript/node.js base type supporting before and after hooks over functions.

or should I say, yet another...

You may have landed here while looking for the widely used hooks module. This is a clean-room implementation, similar in scope, that I put together as a base class used across many of my other modules. Of note are the options related to which methods are eligible for hooks.

##Features

  • Derived from EventEmitter; intended to be used as a base type.
  • Methods on derived types can be hooked with before and after hooks.
  • Control over which methods are eligible for each type of hook.
  • Hooked methods will raise error events upon error.
  • Hooked methods will raise canceled events upon cancelation.
  • Middleware pipelines are immutable at the time of execution (copy-on-write).

Types of Hooks

before

  • predicate hook - indicates whether the method pipeline should continue.
  • pipeline hook - observes and potentially transforms arguments before continuing the method pipeline.

after

  • pipeline hook - observes and potentially transforms the method's result before continuing the method pipeline.
  • observer hook - observes a method's result.

Predicate Hooks

A predicate hook determines whether a method pipeline continues to process before the target method. Any hook can act as a predicate by returning a defined falsy value. If a hook's return value is undefined it is not treated as a predicate.

Pipeline Hooks (otherwise known as middleware)

A pipeline hook is added to a method's processing pipeline, either before or after the method.

Pipeline hooks before a method must have the same signature as the hooked method.

Pipeline hooks after a method must have the signature function (err, res, next) { /*...*/ } where err, if truthy, is an error produced by the operation, res is an anticipated result, and next is the next method in the pipeline.

If any pipeline hook fails to call the next method that it is given, it has, in effect, silently canceled the operation.

Observer Hooks

Every hook is an observer of either the arguments before a target method, or the result after. However, if an after hook has an arity less than 3 it is assumed to be an observer. These hooks are called as synchronous participants in the method pipeline.

If an observer hook throws, the error is captured and communicated to the caller-supplied callback as an error.

Hookable Methods

Methods that take a callback as the last argument, and have an arity 1 or 2, are eligible for hooks. The two supported signatures are:

  • function(callback) { /*...*/ }
  • function(any, callback) { /*...*/ }

Installation

npm install hooked

Tests

Tests are written using vows & should.js (you may need to install them). If you've installed in a development environment you can use npm or node to run the tests.

npm test hooked

... or from the hooked directory...

node test

Use

hooked exports one type called Hooked. It is entended as a base type, and you'll have to create a type that inherits from it in order to start working with hooks.

Importing

var hooked = require('hooked');

Adding a before Hook

// assumes your object has a `perform` method...
my.before('perform', function(obj, next) {
	// do something interesting.
	next(null, obj);
});

Adding an after Hook

// assumes your object has a `perform` method...
my.after('perform', function(err, res, next) {
	// do something interesting.
	next(null, res);
});

Canceling (well-behaved example)

Well-behaved hooks should call next or return false. Returning false cancels the operation and emits a canceled event.

// assumes your object has a `perform` method
my.before('perform', function(obj, next) {
	// assumes there is a `shouldCancel` method in the current scope
	if (shouldCancel('perform', obj)) {
		// as a predicate, returning `false` cancels.
		return false;
	} else {
		next(null, obj);
	}
});

Enabling Events

Once a method has been hooked, unless it is configured for noevents, an event will be emitted. The event's name matches the method's name.

Events

  • error - emitted when a hook throws an error.
  • canceled - emitted when a before hook canceles an operation.
  • {method} - emitted when the target method completes, before after hooks.

Events can be enabled before hooks are present by using the enableMethodEvents method.

// enable an event for the assumed `perfrom` method
my.enableMethodEvents(["perform"]);

// hook up an event handler...
my.on('perform', function (res){ /* hrm, something just occurred */});

Making Methods Ineligible for Hooks

Methods that would normally be eligible for hooks based on their signature can be made ineligible by constructor option.

Ineligible for Any

Methods may be marked ineligible for any hook throught the unhooked option.

var util = require('util')
, Hooked = require('hooked').Hooked
;

function My() {
	// instruct the base class that `perform` will be ineligible for hooks...
	My.super_.call(this, { unhooked: ["perform"] });

	this.perform = function(any, callback) {
		/* ... elided ... */
		callback(null, 'ok');
	};
}
util.inherits(My, Hooked);

Ineligible before

Methods may be marked ineligible for before hooks throught the nonbefore option.

var util = require('util')
, Hooked = require('hooked').Hooked
;

function My() {
	// instruct the base class that `perform` will be ineligible for `before` hooks...
	My.super_.call(this, { nonbefore: ["perform"] });

	this.perform = function(any, callback) {
		/* ... elided ... */
		callback(null, 'ok');
	};
}
util.inherits(My, Hooked);

Ineligible after

Methods may be marked ineligible for after hooks throught the nonafter option.

var util = require('util')
, Hooked = require('hooked').Hooked
;

function My() {
	// instruct the base class that `perform` will be ineligible for `after` hooks...
	My.super_.call(this, { nonafter: ["perform"] });

	this.perform = function(any, callback) {
		/* ... elided ... */
		callback(null, 'ok');
	};
}
util.inherits(My, Hooked);

Method Events

By default, the base class will emit events for hooked methods.

The events can be suppressed through the noevents option.

var util = require('util')
, Hooked = require('hooked').Hooked
;

function My() {
	// instruct the base class not to emit a `perform` event...
	My.super_.call(this, { noevent: ["perform"] });

	this.perform = function(any, callback) {
		/* ... elided ... */
		callback(null, 'ok');
	};
}
util.inherits(My, Hooked);