fairmont-reactive
Advanced tools
Comparing version 1.0.0-beta-21 to 1.0.0-beta-22
@@ -9,6 +9,10 @@ // Generated by CoffeeScript 1.9.3 | ||
include(module.exports, require("./reducer")); | ||
include(module.exports, require("./reactor")); | ||
include(module.exports, require("./reactive")); | ||
include(module.exports, require("./adapters")); | ||
include(module.exports, require("./filters")); | ||
include(module.exports, require("./reducers")); | ||
}).call(this); |
// Generated by CoffeeScript 1.9.3 | ||
(function() { | ||
var Method, W, async, asyncIterator, binary, compact, compose, curry, either, events, filter, has, identity, isAsyncIterable, isAsyncIterator, isAsyncIteratorFunction, isDefined, isFunction, isGenerator, isIterable, isIterator, isIteratorFunction, isPromise, isSource, iterator, iteratorFunction, lines, map, negate, partition, project, property, pull, query, ref, ref1, reject, repeat, select, split, stream, take, takeN, where, | ||
slice = [].slice; | ||
var Method, async, curry, identity, isDefined, isFunction, isGenerator, isIterable, isIterator, isIteratorFunction, isPromise, iterator, iteratorFunction, ref, ref1; | ||
W = require("when"); | ||
ref = require("fairmont-core"), identity = ref.identity, curry = ref.curry; | ||
ref = require("fairmont-core"), identity = ref.identity, curry = ref.curry, compose = ref.compose, binary = ref.binary, negate = ref.negate; | ||
either = curry(function(f, g) { | ||
return function() { | ||
return (f.apply(null, arguments)) || (g.apply(null, arguments)); | ||
}; | ||
}); | ||
Method = require("fairmont-multimethods").Method; | ||
ref1 = require("fairmont-helpers"), property = ref1.property, query = ref1.query, has = ref1.has, isFunction = ref1.isFunction, isGenerator = ref1.isGenerator, isDefined = ref1.isDefined, isPromise = ref1.isPromise, async = ref1.async; | ||
ref1 = require("fairmont-helpers"), isFunction = ref1.isFunction, isGenerator = ref1.isGenerator, isDefined = ref1.isDefined, isPromise = ref1.isPromise, async = ref1.async; | ||
@@ -24,6 +15,2 @@ isIterable = function(x) { | ||
isAsyncIterable = function(x) { | ||
return (x != null ? x[Symbol.asyncIterator] : void 0) != null; | ||
}; | ||
isIterator = function(x) { | ||
@@ -33,6 +20,2 @@ return ((x != null ? x.next : void 0) != null) && isIterable(x); | ||
isAsyncIterator = function(x) { | ||
return ((x != null ? x.next : void 0) != null) && isAsyncIterable(x); | ||
}; | ||
iterator = Method.create(); | ||
@@ -52,6 +35,2 @@ | ||
Method.define(iterator, isAsyncIterable, function(i) { | ||
return i[Symbol.asyncIterator](); | ||
}); | ||
Method.define(iterator, isGenerator, function(g) { | ||
@@ -61,12 +40,2 @@ return g(); | ||
asyncIterator = Method.create(); | ||
Method.define(asyncIterator, isFunction, function(f) { | ||
f.next = f; | ||
f[Symbol.asyncIterator] = function() { | ||
return this["this"]; | ||
}; | ||
return f; | ||
}); | ||
isIteratorFunction = function(f) { | ||
@@ -76,13 +45,9 @@ return (isFunction(f)) && (isIterator(f)); | ||
isAsyncIteratorFunction = function(f) { | ||
return (isFunction(f)) && (isAsyncIterator(f)); | ||
}; | ||
iteratorFunction = Method.create(); | ||
Method.define(iteratorFunction, either(isIterable, isAsyncIterable), function(x) { | ||
Method.define(iteratorFunction, isIterable, function(x) { | ||
return iteratorFunction(iterator(x)); | ||
}); | ||
Method.define(iteratorFunction, either(isIterator, isAsyncIterator), function(i) { | ||
Method.define(iteratorFunction, isIterator, function(i) { | ||
return iterator((function() { | ||
@@ -97,461 +62,12 @@ return i.next(); | ||
Method.define(iteratorFunction, either(isIteratorFunction, isAsyncIteratorFunction), identity); | ||
Method.define(iteratorFunction, isIteratorFunction, identity); | ||
Method.define(iteratorFunction, isPromise, function(p) { | ||
var _p; | ||
_p = p.then(function(x) { | ||
return iteratorFunction(x); | ||
}); | ||
return asyncIterator(function() { | ||
return _p.then(function(i) { | ||
return i(); | ||
}); | ||
}); | ||
}); | ||
pull = Method.create(); | ||
Method.define(pull, isDefined, function(x) { | ||
return pull(iteratorFunction(x)); | ||
}); | ||
Method.define(pull, isIteratorFunction, function(i) { | ||
return iterator(function() { | ||
var done, ref2, value; | ||
ref2 = i(), done = ref2.done, value = ref2.value; | ||
if (done) { | ||
return W({ | ||
done: done | ||
}); | ||
} else { | ||
return value.then(function(value) { | ||
return { | ||
done: done, | ||
value: value | ||
}; | ||
}); | ||
} | ||
}); | ||
}); | ||
Method.define(pull, isAsyncIteratorFunction, function(i) { | ||
return asyncIterator(function() { | ||
return i().then(function(arg) { | ||
var done, value; | ||
done = arg.done, value = arg.value; | ||
if (done) { | ||
return W({ | ||
done: done | ||
}); | ||
} else { | ||
return value.then(function(value) { | ||
return { | ||
done: done, | ||
value: value | ||
}; | ||
}); | ||
} | ||
}); | ||
}); | ||
}); | ||
repeat = function(x) { | ||
return iterator(function() { | ||
return { | ||
done: false, | ||
value: x | ||
}; | ||
}); | ||
}; | ||
map = Method.create(); | ||
Method.define(map, Function, isDefined, function(f, x) { | ||
return map(f, iteratorFunction(x)); | ||
}); | ||
Method.define(map, Function, isIteratorFunction, function(f, i) { | ||
return iterator(function() { | ||
var done, ref2, value; | ||
ref2 = i(), done = ref2.done, value = ref2.value; | ||
if (done) { | ||
return { | ||
done: done | ||
}; | ||
} else { | ||
return { | ||
done: done, | ||
value: f(value) | ||
}; | ||
} | ||
}); | ||
}); | ||
Method.define(map, Function, isAsyncIteratorFunction, function(f, i) { | ||
return asyncIterator(function() { | ||
return i().then(function(arg) { | ||
var done, value; | ||
done = arg.done, value = arg.value; | ||
if (done) { | ||
return { | ||
done: done | ||
}; | ||
} else { | ||
return { | ||
done: done, | ||
value: f(value) | ||
}; | ||
} | ||
}); | ||
}); | ||
}); | ||
map = curry(binary(map)); | ||
select = Method.create(); | ||
Method.define(select, Function, isDefined, function(f, x) { | ||
return select(f, iteratorFunction(x)); | ||
}); | ||
Method.define(select, Function, isIteratorFunction, function(f, i) { | ||
return iterator(function() { | ||
var done, ref2, value; | ||
while (true) { | ||
ref2 = i(), done = ref2.done, value = ref2.value; | ||
if (done || (f(value))) { | ||
break; | ||
} | ||
} | ||
return { | ||
done: done, | ||
value: value | ||
}; | ||
}); | ||
}); | ||
Method.define(select, Function, isAsyncIteratorFunction, function(f, i) { | ||
var p; | ||
p = (function(arg) { | ||
var done, value; | ||
done = arg.done, value = arg.value; | ||
return done || (f(value)); | ||
}); | ||
return asyncIterator(function() { | ||
return W.iterate(i, p, (function() {}), i()); | ||
}); | ||
}); | ||
select = filter = curry(binary(select)); | ||
reject = curry(function(f, i) { | ||
return select(negate(f), i); | ||
}); | ||
project = curry(function(p, i) { | ||
return map(property(p), i); | ||
}); | ||
compact = select(isDefined); | ||
partition = Method.create(); | ||
Method.define(partition, Number, isDefined, function(n, x) { | ||
return partition(n, iteratorFunction(x)); | ||
}); | ||
Method.define(partition, Number, isIteratorFunction, function(n, i) { | ||
return iterator(function() { | ||
var batch, done, ref2, value; | ||
batch = []; | ||
while (true) { | ||
ref2 = i(), done = ref2.done, value = ref2.value; | ||
if (done) { | ||
break; | ||
} | ||
batch.push(value); | ||
if (batch.length === n) { | ||
break; | ||
} | ||
} | ||
if (done) { | ||
return { | ||
done: done | ||
}; | ||
} else { | ||
return { | ||
value: batch, | ||
done: done | ||
}; | ||
} | ||
}); | ||
}); | ||
Method.define(partition, Number, isAsyncIteratorFunction, function(n, i) { | ||
return asyncIterator(async(function*() { | ||
var batch, done, ref2, value; | ||
batch = []; | ||
while (true) { | ||
ref2 = (yield i()), done = ref2.done, value = ref2.value; | ||
if (done) { | ||
break; | ||
} | ||
batch.push(value); | ||
if (batch.length === n) { | ||
break; | ||
} | ||
} | ||
if (done) { | ||
return { | ||
done: done | ||
}; | ||
} else { | ||
return { | ||
value: batch, | ||
done: done | ||
}; | ||
} | ||
})); | ||
}); | ||
take = Method.create(); | ||
Method.define(take, Function, isDefined, function(f, x) { | ||
return take(f, iteratorFunction(x)); | ||
}); | ||
Method.define(take, Function, isIteratorFunction, function(f, i) { | ||
return iterator(function() { | ||
var done, ref2, value; | ||
if (!done) { | ||
ref2 = i(), done = ref2.done, value = ref2.value; | ||
if (!done && (f(value))) { | ||
return { | ||
value: value, | ||
done: false | ||
}; | ||
} else { | ||
return { | ||
done: true | ||
}; | ||
} | ||
} | ||
}); | ||
}); | ||
take = curry(binary(take)); | ||
takeN = (function() { | ||
var f; | ||
f = function(n, i) { | ||
if (i == null) { | ||
i = 0; | ||
} | ||
return function() { | ||
return i++ < n; | ||
}; | ||
}; | ||
return function(n, i) { | ||
return take(f(n), i); | ||
}; | ||
})(); | ||
where = curry(function(example, i) { | ||
return select(query(example), i); | ||
}); | ||
events = Method.create(); | ||
isSource = compose(isFunction, property("on")); | ||
Method.define(events, String, isSource, function(name, source) { | ||
return events({ | ||
name: name, | ||
end: "end", | ||
error: "error" | ||
}, source); | ||
}); | ||
Method.define(events, Object, isSource, (function(reject) { | ||
var promise, ref2, resolve; | ||
ref2 = require("when"), promise = ref2.promise, reject = ref2.reject, resolve = ref2.resolve; | ||
return function(map, source) { | ||
var dequeue, done, end, enqueue, error, name, pending, resolved; | ||
name = map.name, end = map.end, error = map.error; | ||
if (end == null) { | ||
end = "end"; | ||
} | ||
if (error == null) { | ||
error = "error"; | ||
} | ||
done = false; | ||
pending = []; | ||
resolved = []; | ||
enqueue = function(x) { | ||
var p; | ||
if (pending.length === 0) { | ||
return resolved.push(x); | ||
} else { | ||
p = pending.shift(); | ||
return x.then(p.resolve)["catch"](p.reject); | ||
} | ||
}; | ||
dequeue = function() { | ||
if (resolved.length === 0) { | ||
if (!done) { | ||
return promise(function(resolve, reject) { | ||
return pending.push({ | ||
resolve: resolve, | ||
reject: reject | ||
}); | ||
}); | ||
} else { | ||
return resolve({ | ||
done: done | ||
}); | ||
} | ||
} else { | ||
return resolved.shift(); | ||
} | ||
}; | ||
source.on(name, function() { | ||
var ax, value; | ||
ax = 1 <= arguments.length ? slice.call(arguments, 0) : []; | ||
value = ax.length < 2 ? ax[0] : ax; | ||
return enqueue(resolve({ | ||
done: done, | ||
value: value | ||
})); | ||
}); | ||
source.on(end, function(error) { | ||
done = true; | ||
return enqueue(resolve({ | ||
done: done | ||
})); | ||
}); | ||
source.on(error, function(error) { | ||
return enqueue(reject(error)); | ||
}); | ||
return asyncIterator(dequeue); | ||
}; | ||
})(reject)); | ||
events = curry(binary(events)); | ||
stream = events("data"); | ||
split = Method.create(); | ||
Method.define(split, Function, isDefined, function(f, x) { | ||
return split(f, iteratorFunction(x)); | ||
}); | ||
Method.define(split, Function, isIteratorFunction, function(f, i) { | ||
var lines, remainder; | ||
lines = []; | ||
remainder = ""; | ||
return iterator(function() { | ||
var done, first, j, last, ref2, ref3, value; | ||
if (lines.length > 0) { | ||
return { | ||
value: lines.shift(), | ||
done: false | ||
}; | ||
} else { | ||
ref2 = i(), value = ref2.value, done = ref2.done; | ||
if (!done) { | ||
ref3 = f(value), first = ref3[0], lines = 3 <= ref3.length ? slice.call(ref3, 1, j = ref3.length - 1) : (j = 1, []), last = ref3[j++]; | ||
first = remainder + first; | ||
remainder = last; | ||
return { | ||
value: first, | ||
done: done | ||
}; | ||
} else if (remainder !== "") { | ||
value = remainder; | ||
remainder = ""; | ||
return { | ||
value: value, | ||
done: false | ||
}; | ||
} else { | ||
return { | ||
done: done | ||
}; | ||
} | ||
} | ||
}); | ||
}); | ||
Method.define(split, Function, isAsyncIteratorFunction, function(f, i) { | ||
var lines, remainder; | ||
lines = []; | ||
remainder = ""; | ||
return asyncIterator(async(function*() { | ||
var done, first, j, last, ref2, ref3, value; | ||
if (lines.length > 0) { | ||
return { | ||
value: lines.shift(), | ||
done: false | ||
}; | ||
} else { | ||
ref2 = (yield i()), value = ref2.value, done = ref2.done; | ||
if (!done) { | ||
ref3 = f(value), first = ref3[0], lines = 3 <= ref3.length ? slice.call(ref3, 1, j = ref3.length - 1) : (j = 1, []), last = ref3[j++]; | ||
first = remainder + first; | ||
remainder = last; | ||
return { | ||
value: first, | ||
done: done | ||
}; | ||
} else if (remainder !== "") { | ||
value = remainder; | ||
remainder = ""; | ||
return { | ||
value: value, | ||
done: false | ||
}; | ||
} else { | ||
return { | ||
done: done | ||
}; | ||
} | ||
} | ||
})); | ||
}); | ||
split = curry(binary(split)); | ||
lines = split(function(s) { | ||
return s.toString().split("\n"); | ||
}); | ||
module.exports = { | ||
isIterable: isIterable, | ||
isAsyncIterable: isAsyncIterable, | ||
iterator: iterator, | ||
asyncIterator: asyncIterator, | ||
isIterator: isIterator, | ||
isAsyncIterator: isAsyncIterator, | ||
isIteratorFunction: isIteratorFunction, | ||
isAsyncIteratorFunction: isAsyncIteratorFunction, | ||
iteratorFunction: iteratorFunction, | ||
pull: pull, | ||
repeat: repeat, | ||
map: map, | ||
select: select, | ||
reject: reject, | ||
filter: filter, | ||
project: project, | ||
compact: compact, | ||
partition: partition, | ||
where: where, | ||
take: take, | ||
takeN: takeN, | ||
events: events, | ||
stream: stream, | ||
lines: lines, | ||
split: split | ||
iteratorFunction: iteratorFunction | ||
}; | ||
}).call(this); |
{ | ||
"name": "fairmont-reactive", | ||
"version": "1.0.0-beta-21", | ||
"version": "1.0.0-beta-22", | ||
"description": "Functional reactive programming in JavaScript and CoffeeScript.", | ||
@@ -5,0 +5,0 @@ "files": [ |
107
README.md
@@ -1,5 +0,98 @@ | ||
# Fairmont | ||
# Fairmont/Reactive | ||
Fairmont is a JavaScript library for functional reactive programming. Fairmont takes full advantage of ES6+ features like iterators (including async iterators), generators, and promises. Inspired by libraries like [Underscore](http://underscorejs.org/) and many others, Fairmont features include: | ||
Fairmont/Reactive is a JavaScript library for functional reactive programming. | ||
### In JavaScript | ||
```javascript | ||
start(flow([ | ||
events("request", server), | ||
select(spread(function(request) { | ||
return request.method === "GET"; | ||
})), | ||
select(spread(function(request) { | ||
return request.url === "/"; | ||
})), | ||
tee(spread(function(ignored, response) { | ||
response.statusCode = 200; | ||
response.write("hello, world"); | ||
response.end(); | ||
})), | ||
map(spread(logger)); | ||
])); | ||
``` | ||
### In CoffeeScript | ||
```coffee | ||
start flow [ | ||
events "request", server | ||
select spread (request) -> request.method == "GET" | ||
select spread (request) -> request.url == "/" | ||
tee spread (ignored, response) -> | ||
response.statusCode = 200 | ||
response.write "hello, world" | ||
response.end() | ||
map spread logger | ||
] | ||
``` | ||
## Examples | ||
You can get a feel for what Fairmont can do for you by [checking out the examples](./examples). | ||
## Introduction | ||
### Iterators | ||
An _iterator_ is an ES6 iterator, with a `next` function that produces a value wrapper. | ||
A _value wrapper_ is what iterators produce, with `done` and `value` properties. | ||
These are part of the ES6 standard. | ||
An _iterator function_ is a function that returns a value wrapper. | ||
This is abstraction introduced by Fairmont/Reactive that allows us to leverage a functional programming when using iterators. | ||
Since iterator functions are isomorphic to iterators, we'll call them iterators for convenience when it isn't ambiguous. | ||
### Reactors | ||
An _asynchronous iterator_ is an iterator that produces promises that resolve to value wrappers. | ||
These are a proposed part of ES7. | ||
An _asynchronous iterator function_ is a function that returns promises that resolve to value wrappers. | ||
A _reactor_ Fairmont lingo for an asynchronous iterator. | ||
Simiarly, a _reactor function_ Fairmont-speak for an asynchronous iterator function. | ||
Since reactor functions are isomorphic to reactors, we'll call them reactors for convenience when it isn't ambiguous. | ||
When talking about values that could be iterators or reactors, we will sometimes say _producers_. | ||
### Adapters, Filters, and Reducers | ||
An _adapter_ creates a producer (an iterator or reactor) from a non-producer. | ||
An _iterator filter_ is a function that takes an iterator and returns another iterator. | ||
Iterator filters are just called _filters_ for convenience whenever it isn't ambiguous. | ||
An _iterator reducer_ is a function that takes an iterator and returns a value that isn't an iterator. | ||
Iterator reducers are just called _reducers_ for convenience whenever it isn't ambiguous. | ||
When talking about functions that could be adapters, filters, or reducers, we will sometimes say _transforms_. | ||
### Polymorphic Filters And Reducers | ||
Most transforms are implemented for both iterators and reactors. | ||
For example, if we pass an iterator to `map` we'll get back an iterator. Whereas if we pass it a reactor, we'll get back a reactor. | ||
Similarly, if we pass an iterator to `collect` we'll get back an array. | ||
If we pass it a reactor, we'll get back a promise that resolves to an array. | ||
Many values that aren't iterators or reactors will be coerced into one or the other when passed to a transform or reduction. | ||
For example, if you pass an array into `map`, the array will be coerced into an iterator. | ||
Similarly, if you pass a promise into `map`, the promise will be coerced into a reactor. | ||
## About Fairmont | ||
Fairmont takes full advantage of ES6+ features like iterators (including async iterators, called _reactors_), generators, and promises. Inspired by libraries like [Underscore](http://underscorejs.org/) and many others, Fairmont features include: | ||
* reactive programming support through async iterators | ||
@@ -10,14 +103,6 @@ * lazy evaluation on collection operations via iterators | ||
* common file and stream based operations | ||
* streams and event emitters modeled as asynchronous iterators | ||
* streams and event emitters modeled as reactors | ||
* seamless integration between synchronous and asynchronous operations | ||
* … and more! | ||
## Examples | ||
You can get a feel for what Fairmont can do for you by [checking out the examples](./examples). | ||
## Reference | ||
Fairmont uses [literate programming](http://www.coffeescriptlove.com/2013/02/literate-coffeescript.html), so each source file doubles as documentation. Please see the [source directory](./src/index.litcoffee) for more. | ||
## Status | ||
@@ -24,0 +109,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
62607
17
1156
116
1