Permalink
Browse files

Implement first draft of coreduction.

  • Loading branch information...
0 parents commit dffc4372c9cf44acba56900e27eeb379ba0d9547 @Gozala committed Dec 5, 2012
Showing with 337 additions and 0 deletions.
  1. +5 −0 .travis.yml
  2. +5 −0 History.md
  3. +18 −0 License.md
  4. +9 −0 Readme.md
  5. +62 −0 coreduction.js
  6. +42 −0 package.json
  7. +191 −0 test/coreduction.js
  8. +5 −0 test/index.js
@@ -0,0 +1,5 @@
+language: node_js
+node_js:
+ - 0.4
+ - 0.5
+ - 0.6
@@ -0,0 +1,5 @@
+# Changes
+
+## 0.0.1 / 2012-12-04
+
+ - Initial release
@@ -0,0 +1,18 @@
+Copyright 2012 Irakli Gozalishvili. All rights reserved.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
@@ -0,0 +1,9 @@
+# coreduction
+
+[![Build Status](https://secure.travis-ci.org/Gozala/coreduction.png)](http://travis-ci.org/Gozala/coreduction)
+
+Library for correlative reductions
+
+## Install
+
+ npm install coreduction
@@ -0,0 +1,62 @@
+"use strict";
+
+var reducible = require("reducible/reducible")
+var reduced = require("reducible/reduced")
+var end = require("reducible/end")
+var isError = require("reducible/is-error")
+var isReduced = require("reducible/is-reduced")
+var reduce = require("reducible/reduce")
+
+// Special value indicating that no value has being aggregated.
+var nil = new String("Indication of no value")
+
+function coreduction(left, right) {
+ /**
+ Takes two reducibles and returns reducible of pairs, where each item from
+ either input is paired with a last item from the other. This of course means
+ that items from both left and right side may repeat many times. Result ends
+ once either of the inputs end.
+ **/
+ return reducible(function reduceCoupled(next, initial) {
+ var result
+ var state = initial
+ var leftValue = nil
+ var rightValue = nil
+
+ function reducer(isLeft) {
+ // create a reducer function for either left or right reducible.
+ return function coreduce(value) {
+ // If result is already set then either `left` or `right` reducible
+ // has finished or broke and stored `reduced` state returning which
+ // should signal source to stop reduction.
+ if (result) return result
+ // If `end` or error value is yield store result and pass value down
+ // the flow so that error / end can be handled.
+ if (value === end || isError(value)) {
+ result = reduced(state)
+ return next(value, state)
+ }
+
+ // Update last value for the associated reducible.
+ if (isLeft) leftValue = value
+ else rightValue = value
+
+ // If both reducibles yielded already values couple last ones
+ // and pass it down the flow.
+ if (leftValue !== nil && rightValue !== nil) {
+ state = next([leftValue, rightValue], state)
+
+ // If reduction is complete store result to stop the other reducible.
+ if (isReduced(state)) result = state
+
+ return state
+ }
+ }
+ }
+
+ reduce(left, reducer(true))
+ reduce(right, reducer(false))
+ })
+}
+
+module.exports = coreduction
@@ -0,0 +1,42 @@
+{
+ "name": "coreduction",
+ "id": "coreduction",
+ "version": "0.0.1",
+ "description": "Library for correlative reductions",
+ "keywords": [
+ "coreduction"
+ ],
+ "author": "Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)",
+ "homepage": "https://github.com/Gozala/coreduction",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/Gozala/coreduction.git",
+ "web": "https://github.com/Gozala/coreduction"
+ },
+ "bugs": {
+ "url": "http://github.com/Gozala/coreduction/issues/"
+ },
+ "devDependencies": {
+ "test": "~0.x.0",
+ "phantomify": "~0.x.0",
+ "repl-utils": "~2.0.1",
+ "reducers": "~2.0.0"
+ },
+ "main": "./coreduction.js",
+ "scripts": {
+ "repl": "node node_modules/repl-utils",
+ "test": "npm run test-node && npm run test-browser",
+ "test-browser": "node ./node_modules/phantomify/bin/cmd.js ./test/index.js",
+ "test-node": "node ./test/index.js",
+ "postinstall": "npm dedup"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/Gozala/coreduction/License.md"
+ }
+ ],
+ "dependencies": {
+ "reducible": "~1.0.1"
+ }
+}
@@ -0,0 +1,191 @@
+"use strict";
+
+var test = require("reducers/test/util/test")
+var event = require("reducers/test/util/event")
+
+var take = require("reducers/take")
+var concat = require("reducers/concat")
+var delay = require("reducers/delay")
+
+
+var end = require("reducible/end")
+
+var coreduction = require("../coreduction")
+
+exports["test ignore values before both yielded"] = test(function(assert) {
+ var e1 = event()
+ var e2 = event()
+ var e3 = event()
+
+ var actual = concat(coreduction(e1, e2), e3)
+
+ assert(actual, [
+ ["l3", "r1"],
+ ["l3", "r2"],
+ ["l4", "r2"],
+ ["l5", "r2"],
+ ["l5", "r3"]
+ ], "values paired once both strat yielding")
+
+ e1.send("l1")
+ e1.send("l2")
+ e1.send("l3")
+ e2.send("r1")
+ e2.send("r2")
+ e1.send("l4")
+ e1.send("l5")
+ e2.send("r3")
+ e2.send(end)
+
+ assert.ok(e2.isReduced, "right is reduced")
+ assert.ok(!e1.isReduced, "left is not reduced")
+
+ e1.send("l6")
+
+ assert.ok(e1.isReduced, "next yield stops left")
+
+ e3.send(end)
+})
+
+exports["test either end ends coreduction"] = test(function(assert) {
+ var e1 = event()
+ var e2 = event()
+ var e3 = event()
+
+ var actual = concat(coreduction(e1, e2), e3)
+
+ assert(actual, [
+ ["l3", "r1"],
+ ["l3", "r2"],
+ ["l4", "r2"],
+ ["l5", "r2"],
+ ["l5", "r3"]
+ ], "either end ends coreduction")
+
+ e1.send("l1")
+ e1.send("l2")
+ e1.send("l3")
+ e2.send("r1")
+ e2.send("r2")
+ e1.send("l4")
+ e1.send("l5")
+ e2.send("r3")
+ e1.send(end)
+
+ assert.ok(e1.isReduced, "left is reduced")
+ assert.ok(!e2.isReduced, "right is not reduced")
+
+ e2.send("r4")
+
+ assert.ok(e2.isReduced, "next yield stops right")
+
+ e3.send(end)
+})
+
+exports["test stop reduction before end"] = test(function(assert) {
+ var e1 = event()
+ var e2 = event()
+ var e3 = event()
+
+ var pairs = take(coreduction(e1, e2), 4)
+ var actual = concat(pairs, e3)
+
+ assert(actual, [
+ ["l3", "r1"],
+ ["l3", "r2"],
+ ["l4", "r2"],
+ ["l5", "r2"],
+ ], "either end ends coreduction")
+
+ e1.send("l1")
+ e1.send("l2")
+ e1.send("l3")
+ e2.send("r1")
+ e2.send("r2")
+ e1.send("l4")
+ e1.send("l5")
+ e2.send("r3")
+ e1.send("l6")
+ assert.ok(e1.isReduced, "left is reduced")
+ assert.ok(e2.isReduced, "right is reduced")
+
+ e3.send(end)
+})
+
+exports["test reducibles stop on left error"] = test(function(assert) {
+ var boom = Error("Boom!!")
+
+ var e1 = event()
+ var e2 = event()
+
+ var pairs = coreduction(e1, e2)
+ var actual = delay(pairs)
+
+ assert(actual, {
+ error: boom,
+ values: [
+ ["l3", "r1"],
+ ["l3", "r2"],
+ ["l4", "r2"],
+ ["l5", "r2"],
+ ["l5", "r3"]
+ ]
+ }, "error propagate to reducer and stops reducibles")
+
+ e1.send("l1")
+ e1.send("l2")
+ e1.send("l3")
+ e2.send("r1")
+ e2.send("r2")
+ e1.send("l4")
+ e1.send("l5")
+ e2.send("r3")
+ e1.send(boom)
+
+ assert.ok(e1.isReduced, "left is reduced")
+ assert.ok(!e2.isReduced, "right is not reduced")
+
+ e2.send("r4")
+ e1.send("l6")
+
+ assert.ok(e2.isReduced, "next yield stops right")
+})
+
+exports["test reducibles stop on right error"] = test(function(assert) {
+ var boom = Error("Boom!!")
+
+ var e1 = event()
+ var e2 = event()
+
+ var pairs = coreduction(e1, e2)
+ var actual = delay(pairs)
+
+ assert(actual, {
+ error: boom,
+ values: [
+ ["l3", "r1"],
+ ["l3", "r2"],
+ ["l4", "r2"],
+ ["l5", "r2"],
+ ["l5", "r3"]
+ ]
+ }, "error propagate to reducer and stops reducibles")
+
+ e1.send("l1")
+ e1.send("l2")
+ e1.send("l3")
+ e2.send("r1")
+ e2.send("r2")
+ e1.send("l4")
+ e1.send("l5")
+ e2.send("r3")
+ e2.send(boom)
+
+ assert.ok(e2.isReduced, "right is reduced")
+ assert.ok(!e1.isReduced, "left is not reduced")
+
+ e2.send("r4")
+ e1.send("l6")
+
+ assert.ok(e1.isReduced, "next yield stops left")
+})
@@ -0,0 +1,5 @@
+"use strict";
+
+exports["test coreduction"] = require("./coreduction")
+
+require("test").run(exports)

0 comments on commit dffc437

Please sign in to comment.