1.0.11 • Published 10 years ago

eachkv v1.0.11

Weekly downloads
43
License
-
Repository
github
Last release
10 years ago

key/value iteration for javascript Objects

(ignores any Object.prototype.xxx = items)

Installing

npm install eachkv

Auto require syntax:

You can optionally auto require both functions in the local scope with one line:

eval(require('eachkv')());

This expands out to the equivalent of:

var $eachKVAsync$=require('eachkv').$eachKVAsync$;
var $eachKV$=require('eachkv').$eachKV$;

$eachKV$ (basic synchronous looping)

Generic Synchronous Sytnax:

eval(require('eachkv')());

$eachKV$(
    elements,
    function onKeyValue (key,value,endLoop){

    },
    function ondone(retval) {

    }
)

Whilst this is a synchronous function, it uses callbacks for 2 reasons.

Firstly, to facilitate returning a value from a loop, and exiting the loop early. why not just use a for (var x in array) loop? because $eachKV automatically decodes the arrayx value for you, and helpfully ignores any prototype extending functions that have been added to Object. (it still lets you iterate normal functions if that's what you want to do.)

Secondly, to get you into the habit of structuring your loops this way, so if you need to switch to an async model, it is very easy.

The return value

Most of the time you can ignore the return value, however, if you want to exit a loop early, remembering where you were, or something you were looping to find, you can pass it into endLoop(). this will cause that value to be returned to either the ondone() callback, or if you did not define one, the immediate caller. see the second example for one way to use this.

Salient points:

  • if no items were iterated, or endLoop() is never called, the return value is null.
  • if no iterms were iterated, or endLoop() is never called, ondone(null) is called at the end of the loop
  • inside iterator function, if the endLoop() callback was called, the ondone() callback is called with that value, and $eachKV$ returns undefined
  • otherwise, if the endLoop() callback was called, $eachKV$ returns whatever was passed into endLoop()

simple example using standard array no return values, you just want to loop.

eval(require('eachkv')());


var elements = ["one","small","step","for","a","man"];

$eachKV$(
    elements,
    function onKeyValue (n,word,endLoop){
        console.log("word #",n+1,"is",word);
    }
)

synchronous example using named array

eval(require('eachkv')());

var total = 0, elements = { fish : 20, chicken : 45, oats : 39 };

if ($eachKV$(

    elements,
    function onKeyValue (key,value,endLoop){
        if (value > 99) {
            endLoop(key);
        } else {
            total += value;
            console.log("Updating total for",key,"+ $"+value,"=$"+total);
        }
    },
    function ondone(retval) {
        if (retval) {
            console.log(retval,"is too high ($"+elements[retval],")");
        } else {
            console.log("The shopping cart total is $", total);
        }
    }
) ===undefined) {
    // we got a hit.
    console.log("shopping aborted due to something being too expensive");
}

$eachKVAsync$ (asynchronous looping)

Expanding on $eachKV$, $eachKVAsync$ adds a nextItem() callback and an info parameter.

nextItem() advances to the next item - if you don't call it, your loops stops, so remember to ensure it's called at least once for each iteration.

endLoop is the same as before, however the return value of $eachKVAsync$ is always null. your afterLastItem() callback needs to collect anything it needs out of info before proceeeding.

loopEndedEarly tells you that

info is ignoreed by the $eachKVAsync$ itself, but is passed around everywhere for you to use as a container for variables etc. you can equally leave it undefined or null, and this will work too. and you can replace it's value each time if really want to, to set up a new value for the next iteration. it's up to you.

Generic Asynchronous Sytnax:

eval(require('eachkv')());


$eachKVAsync$(
	  elements,
	  info,
	  function onItem(key, value, info, nextItem, endLoop) {
	  
	  		if (must_exit===true) {
	  		   endLoop(info);
	  		}

			nextItem(info)		
	  },
	  function afterLastItem(info, loopEndedEarly) {
	      if (!loopEndedEarly) {
	
	      }
	  }
)

Asynchronous example using indexed array

This just prints out the sizes of the files.

eval(require('eachkv')());

var info  = {
    total : 0,
    count : 0,
    folder :
    require("path").resolve(module.filename).split("/").
    reverse().slice(1).reverse().join("/")
};

require("fs").readdir(

    info.folder,

    function(err,files) {
        if (err) throw err;

        $eachKVAsync$(
            files,
            info,
            function onFile(i, filename, info, nextFile, endLoop) {
                if (filename.charAt(0) === '.') {
                    nextFile(info);
                } else {
                    
                    require("fs").stat(info.folder + "/" + filename,
                        function (err, stat) {
                            if (err) throw err;

                            console.log(filename, "is", stat.size, "bytes")
                            info.count++;
                            info.total += stat.size;
                            nextFile(info);
                        }
                    )
                }
            },
            function afterLastFile(info, loopEndedEarly) {
                if (!loopEndedEarly) {
                    console.log("total of",info.total,"bytes in",info.count,"files");
                }
            }
        )
    }
)

Bonus feature & example:

The automatic installer feature is reusable, and uses $eachKV$ to iterate the functions and build an "install script". you can have a look at that to see another way to use it.

if you are going to be using $eachKVAsync$ anyway, you can use it to provide the same easy install as follows:

module.exports = function (options) {
    return require('eachkv').installer(module,options);
}

Or if you want to exclude something for some reason:

//Pull in the installer & $eachKV$ tools…
eval(require('eachkv')({installer:true}));

module.exports = function (options) {
    var opt = options || {  };
    if (opt.exclude) {
        opt.exclude.push["notThisOne"]
    } else {
        opt.exclude = ["notThisOne"];
    }
    return installer(module,opt);
}

if your module only exports one function, which is the same name as the npm use this:

module.exports = function () {
    return require('eachkv').installer(module,{complete:true});
}

or to cherry pick a few functions to auto export, use this:

eval(require('eachkv')({installer:true}));

module.exports = function () {
    return installer(module,{include:["func1","func2"]});
}

full options syntax:

only install these functions

{
  include : ["a","b","c"]
}

don't install these functions

{
  exclude : ["a","z"]
}

rename these functions

{
  rename : {"myCoolFunction" : "mcf",
  "thisIstooLongANameForNormalUse" : "doit"}
}

keep it simple stupid

{
complete:true
}

if you npm is called gizmo, this will just generate

 if (!gizmo) {var gizmo=require("gizmo");}
1.0.11

10 years ago

1.0.10

10 years ago

1.0.9

10 years ago

1.0.8

10 years ago

1.0.7

10 years ago

1.0.6

10 years ago

1.0.5

10 years ago

1.0.4

10 years ago

1.0.3

10 years ago

1.0.2

10 years ago

1.0.1

10 years ago

1.0.0

10 years ago