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

chainlang

v0.1.2

Published

Utility for easily creating chainable methods and complex fluent APIs in JavaScript

Downloads

2

Readme

Chainlang

Chainlang is a utility for easily creating chainable methods and complex fluent APIs (or fluent interfaces) in JavaScript.

Motivation

Fuent APIs make code easier to read and understand. Replacing a large options object parameter with a convenient fluent API can greatly simplify the use of many library functions. In an interactive environment like the nodejs repl, or the Firebug console, programmers can take advantage of auto-completion and exploratory programming to uncover the features of your fluent API without having to resort to the documentation.

Usage

Creating A Chainable API

Just pass any JavaScript object to chainlang.create to create a chainable api:

var adder = {
    add: function(val){ 
        this._subject += val; 
    },
    calc: function() { 
        return this._subject; 
    }
}

var to = chainlang.create(adder);

// Logs: 10
console.log(
    to(1).add(2).add(3).add(4).calc()
);

chainlang.create will return a function that starts your chain expression. The optional parameter to this function will be saved in this._subject and accessible by all of your methods. If no value is returned by a method in the chain, the chain object itself is implicitly returned so you may continue to chain other methods.

Using chainlang.append

chainlang.append is a simple function to help you build your language spec before passing it to chainlang.create. With chainlang.append, you can declare leaf nodes of an object graph and have the parent nodes filled in for you.

var spec = {};
chainlang.append(spec, 'some.nested.method', function(){});

// Logs: { some: { nested: { method: [Function] } } }
console.log(spec);

If you bind chainlang.append to some object, the first parameter may be omitted

var spec = {};
var define = chainlang.append.bind(spec);

define('another.nested.method', function(){});

// Logs: { another: { nested: { method: [Function] } } }
console.log(spec);

Sharing Data Between Links

Along with this._subject, all method calls have access to this._data. this._data is initially empty, and is simply provided as a convenient place to store information between links in a chained expression.

var spec = {};
var define = chainlang.append.bind(spec);

define('setData', function(val){ 
    this._data.field = val; 
});
define('logData', function(){ 
    console.log(this._data.field); 
});

var chain = chainlang.create(spec);

// Logs: 999
chain().setData(999).logData();

Keeping Your Privates Hidden

Sometimes it's desirable to hide some methods of your chainable api until it makes sense to use them. chainlang provides no built-in support for this, but it is recommended that you simply hide these nodes behind a field with a name like 'private'. That way, programmers using your api will not be tempted to use these methods in a context where it does not make sense to do so. Also, keeping them all behind a field like this, instand of simply prefixing them all with an '' will prevent the auto-completion results from being cluttered with fields that are supposed to be private in the first place. For example:

var delaySpec = {};
var define = chainlang.append.bind(delaySpec);

define('for', function(count){
    this._data.count = count;
    
    // exposing our private 'units' object now that we have a count
    return this._private.units;
});

define('_private.units.seconds.then', function(callback){
    setTimeout(callback, this._data.count * 1000);
});

define('_private.units.minutes.then', function(callback){
    setTimeout(callback, this._data.count * 1000 * 60)
});

var delay = chainlang.create(delaySpec);

// After 5 seconds, logs: '5 seconds elapsed'
delay().for(5).seconds.then(function(){
    console.log('5 seconds elapsed');
});

// After 5 minutes, logs: '5 minutes elapsed'
delay().for(5).minutes.then(function(){
    console.log('5 minutes elapsed');
});

In the previous example, it would not make sense to have an expression such as delay().minutes.then(...). The count needs to be declared before the units, so the units object is kept in private storage and exposed by returning it from the for(count) call.

More Information