https://github.com/Gozala/reducers
Raw File
Tip revision: 4e743321440a426d44c6ce03c05339e73c4517a5 authored by Irakli Gozalishvili on 24 October 2012, 19:47:47 UTC
Version 0.1.2
Tip revision: 4e74332
hub.js
/* vim:set ts=2 sw=2 sts=2 expandtab */
/*jshint asi: true undef: true es5: true node: true browser: true devel: true
         forin: true latedef: false globalstrict: true */
'use strict';

var accumulate = require("./accumulate")
var convert = require("./convert")
var accumulated = require("./accumulated")
var end = require("./end")

var input = "input@" + module.id
var consumers = "consumers@" + module.id

function open(hub) {
  var source = hub[input]
  var hubConsumers = hub[consumers]
  hub[input] = null         // mark hub as open
  accumulate(source, function distribute(value) {
    var activeConsumers = hubConsumers.slice(0)
    var count = activeConsumers.length, index = 0
    while (index < count) {
      var consumer = activeConsumers[index++]
      var state = consumer.next(value, consumer.state)
      if (state && state.is === accumulated) {
        var position = hubConsumers.indexOf(consumer)
        if (position >= 0) hubConsumers.splice(position, 1)
        consumer.next(end(), consumer.state)
      } else {
        consumer.state = state
      }
    }

    if (value && value.is === end) {
      hubConsumers.splice(0)
      hub[input] = source
    }
    if (!hubConsumers.length) {
      hub[input] = source       // mark hub as not open.
      return accumulated()      // will notify source consumption is complete.
    }
  })
}

function isHub(value) {
  return !value || (input in value && consumers in value)
}

function isOpen(hub) {
  return hub[input] === null
}

function hub(source) {
  /**
  Take a reducible `source`, such as a `signal` and return a reducible that can
  be consumed by many reducers.
  **/

  // If source is already a hub avoid just return.
  if (isHub(source)) return source
  var value = convert(source, hub.accumulate)
  value[input] = source
  value[consumers] = []
  return value
}
hub.isHub = isHub
hub.isOpen = isOpen
hub.accumulate = function accumulate(hub, next, initial) {
  hub[consumers].push({ next: next, state: initial })
  if (!isOpen(hub)) open(hub)
}
module.exports = hub
back to top