Skip to content

Gozala/callback-reduce

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

callback-reduce

Build Status

Reducers is a great abstraction for working with collections of values eventual or not. In fact it's great because API for working with data is same map/reduce regardless of weather it's sync or async.

var fold = require("reducers/fold")
var filter = require("reducers/filter")
var map = require("reducers/map")

// Sync
fold(filter(map(array, JSON.parse), isCached), accumulate)

// Async
fold(filter(map(stream, JSON.parse), isCached), accumulate)

Another cool concept about reducers is that allows you to work with non sequnce values with the same API. It just treats atomic vaules as sequences of themself.

var fold = require("reducers/fold")
function sum(sequence) {
  return fold(sequence, function(item, result) {
    return result + item
  }, 0)
}

fold(sum(15), console.log.bind(0, "=>"))            // => 15 undefined
fold(sum([ 15, 3, 7 ]), console.log.bind(0, "=>"))  // => 25 undefined

But there are bunch of async APIs around that are designed in terms of: do action provide a callback, where you'll handle either error or value.

var fs = require("fs")

function getPackageName(path, callback) {
  fs.readFile(path, function(error, buffer) {
    if (error) return callback(error)
    var json = JSON.parse(buffer.toString())
    callback(error, json.name)
  })
}

getPackageName("./package.json", console.log) // => null "callback-reduce"

Which is ok but not very composable and there is no simple to transform data. But with reducers we like the fact of unified API that works on the data structures regardless of their nature or timing. This libarray lets you get reducible callbacks for callback styled functions!

var fs = require("fs")
var map = require("reducers/map")
var callback = require("callback-reduce")
var fold = require("reducers/fold")

var content = callback(fs.readFile, "./package.json")
var json = map(map(content, String), JSON.parse)
var name = map(json, function($) { return $.name })

fold(name, console.log.bind(0, "=>"))     // => "callback-reduce" undefined

And of course it's lazy and compasable with rest of the API that reducers provide. For more complicated example see:

var print = require("reducers/debug/print")

var fs = require("fs")
var path = require("path")

var callback = require("callback-reduce")
var expand = require("reducers/expand")
var map = require("reducers/map")
var filter = require("reducers/filter")
var concat = require("reducers/concat")
var cache = require("cache-reduce/cache")


function lstree(root) {
  // Get sequence of directory entries, also we cache it as we read
  // from it several times.
  var entries = cache(callback(fs.readdir, root))
  // Resolve entries to the current path.
  var paths = map(entries, path.join.bind(path, root))
  // Expand sequence of paths, to associated stats. Unfortunately node does not
  // keeps path info in the stats so we need to hack this up. Otherwise it would
  // have being just: var stats = expand(paths, callback.bind(fs, fs.stats))
  var stats = expand(paths, function(path) {
    return map(callback(fs.stat, path), function(stats) {
      stats.toString = path.toString.bind(path)
      return stats
    })
  })
  // Filter & map file paths.
  var files = map(filter(stats, function($) { return $.isFile() }), String)
  // Filter & map directory paths.
  var dirs = map(filter(stats, function($) { return $.isDirectory() }), String)

  // Return concatination given path, file paths, and all the nested paths.
  return concat(root, files, expand(dirs, lstree))
}

print(lstree("./"))

passback

Converts a reducible into a callback

var passback = require("callback-reduce/passback")
var fs = require("fs")
var callback = require("callback-reduce")

var reducible = callback(fs.stat, ".")

passback(reducible, function (err, stat) {
  /* do stuff */
})

Also takes an optional packing function, to pack the arguments.

If you were to pass Array it would pack the entire content of the reducible into an array.

var passback = require("callback-reduce/passback")
var fs = require("fs")
var callback = require("callback-reduce")

var reducible = callback(fs.readdir, "./")

passback(reducible, Array, function (err, files) {
  /* do stuff */
})

Install

npm install callback-reduce

About

Callbacks made reducible

Resources

License

Stars

Watchers

Forks

Packages

No packages published