mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
parent
e0a766081b
commit
d7ad2054c1
@ -35,13 +35,13 @@ geolocation API in Firefox.
|
||||
## Using Geolocation in an Add-on ##
|
||||
|
||||
Suppose we want to use the
|
||||
[geolocation API built into Firefox](https://developer.mozilla.org/en/using_geolocation).
|
||||
[geolocation API built into Firefox](https://developer.mozilla.org/en-US/docs/WebAPI/Using_geolocation).
|
||||
The SDK doesn't provide an API to access geolocation, but we can
|
||||
[access the underlying XPCOM API using `require("chrome")`](dev-guide/guides/xul-migration.html#xpcom).
|
||||
|
||||
The following add-on adds a [button to the toolbar](dev-guide/tutorials/adding-toolbar-button.html):
|
||||
when the user clicks the button, it loads the
|
||||
[XPCOM nsIDOMGeoGeolocation](https://developer.mozilla.org/en/XPCOM_Interface_Reference/NsIDOMGeoGeolocation)
|
||||
[XPCOM nsIDOMGeoGeolocation](https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/NsIDOMGeoGeolocation)
|
||||
object, and retrieves the user's current position:
|
||||
|
||||
var {Cc, Ci} = require("chrome");
|
||||
@ -88,7 +88,7 @@ info: longitude: 93.0785269
|
||||
</pre>
|
||||
|
||||
So far, so good. But the geolocation guide on MDN tells us that we must
|
||||
[ask the user for permission](https://developer.mozilla.org/en/using_geolocation#Prompting_for_permission)
|
||||
[ask the user for permission](https://developer.mozilla.org/en-US/docs/WebAPI/Using_geolocation#Prompting_for_permission)
|
||||
before using the API.
|
||||
|
||||
So we'll extend the add-on to include an adapted version of the code in
|
||||
|
@ -13,15 +13,17 @@ When the method is invoked on an instance of the object, the original
|
||||
function is called. It is passed the object instance (i.e. `this`) as
|
||||
the first parameter, followed by any parameters passed into the method.
|
||||
|
||||
let { method } = require("sdk/lang/functional");
|
||||
let myNumber = {
|
||||
const { method } = require("sdk/lang/functional");
|
||||
|
||||
const times = (target, x) => target.number *= x;
|
||||
const add = (target, x) => target.number += x;
|
||||
|
||||
const myNumber = {
|
||||
times: method(times),
|
||||
add: method(add),
|
||||
number: 0
|
||||
};
|
||||
|
||||
function times (target, x) { return target.number *= x; }
|
||||
function add (target, x) { return target.number += x; }
|
||||
|
||||
console.log(myNumber.number); // 0
|
||||
myNumber.add(10); // 10
|
||||
@ -44,8 +46,8 @@ wait (i.e. `setTimeout(function () { ... }, 0)`), except that the wrapped functi
|
||||
may be reused and does not need to be repeated each time. This also enables you
|
||||
to use these functions as event listeners.
|
||||
|
||||
let { defer } = require("sdk/lang/functional");
|
||||
let fn = defer(function myEvent (event, value) {
|
||||
const { defer } = require("sdk/lang/functional");
|
||||
const fn = defer((event, value) => {
|
||||
console.log(event + " : " + value);
|
||||
});
|
||||
|
||||
@ -74,16 +76,11 @@ An alias for [defer](modules/sdk/lang/functional.html#defer(fn)).
|
||||
Invokes `callee`, passing `params` as an argument and `self` as `this`.
|
||||
Returns the value that is returned by `callee`.
|
||||
|
||||
let { invoke } = require("sdk/lang/functional");
|
||||
const { invoke } = require("sdk/lang/functional");
|
||||
|
||||
const sum = (...args) => args.reduce((a, b) => a + b);
|
||||
invoke(sum, [1,2,3,4,5], null); // 15
|
||||
|
||||
function sum () {
|
||||
return Array.slice(arguments).reduce(function (a, b) {
|
||||
return a + b;
|
||||
});
|
||||
}
|
||||
|
||||
@param callee {function}
|
||||
Function to invoke.
|
||||
@param params {Array}
|
||||
@ -98,9 +95,9 @@ Returns the value that is returned by `callee`.
|
||||
@function
|
||||
Takes a function and bind values to one or more arguments, returning a new function of smaller arity.
|
||||
|
||||
let { partial } = require("sdk/lang/functional");
|
||||
let add = function add (x, y) { return x + y; }
|
||||
let addOne = partial(add, 1);
|
||||
const { partial } = require("sdk/lang/functional");
|
||||
const add = (x, y) => x + y;
|
||||
const addOne = partial(add, 1);
|
||||
|
||||
addOne(5); // 6
|
||||
addOne(10); // 11
|
||||
@ -122,14 +119,16 @@ Returns the [composition](http://en.wikipedia.org/wiki/Function_composition_(com
|
||||
return value of the function that follows. In math terms, composing the functions
|
||||
`f()`, `g()`, and `h()` produces `f(g(h()))`.
|
||||
|
||||
let { compose } = require("sdk/lang/functional");
|
||||
const { compose } = require("sdk/lang/functional");
|
||||
|
||||
let welcome = compose(exclaim, greet);
|
||||
const square = x => x * x;
|
||||
const increment = x => x + 1;
|
||||
|
||||
welcome('moe'); // "hi: moe!";
|
||||
const f1 = compose(increment, square);
|
||||
f1(5); // => 26
|
||||
|
||||
function greet (name) { return "hi: " + name; }
|
||||
function exclaim (statement) { return statement + "!"; }
|
||||
const f2 = compose(square, increment);
|
||||
f2(5); // => 36
|
||||
|
||||
@param fn... {function}
|
||||
Takes a variable number of functions as arguments and composes them from right to left.
|
||||
@ -144,16 +143,14 @@ Returns the first function passed as an argument to the second,
|
||||
allowing you to adjust arguments, run code before and after, and
|
||||
conditionally execute the original function.
|
||||
|
||||
let { wrap } = require("sdk/lang/functional");
|
||||
const { wrap } = require("sdk/lang/functional");
|
||||
|
||||
let wrappedHello = wrap(hello, function (fn, name) {
|
||||
return "before, " + fn(name) + "after";
|
||||
});
|
||||
const hello = name => "hello: " + name;
|
||||
const wrappedHello = wrap(hello, (fn, name) =>
|
||||
"before, " + fn(name) + "after");
|
||||
|
||||
wrappedHello("moe"); // "before, hello: moe, after"
|
||||
|
||||
function hello (name) { return "hello: " + name; }
|
||||
|
||||
@param fn {function}
|
||||
The function to be passed into the `wrapper` function.
|
||||
|
||||
@ -170,8 +167,8 @@ conditionally execute the original function.
|
||||
@function
|
||||
Returns the same value that is used as the argument. In math: f(x) = x.
|
||||
|
||||
let { identity } = require("sdk/lang/functional");
|
||||
let x = 5;
|
||||
const { identity } = require("sdk/lang/functional");
|
||||
const x = 5;
|
||||
identity(x); // 5
|
||||
|
||||
@param value {mixed}
|
||||
@ -190,15 +187,15 @@ storing the result, based on the arguments to the original function. The
|
||||
default `hashFunction` just uses the first argument to the memoized function as
|
||||
the key.
|
||||
|
||||
let { memoize } = require("sdk/lang/functional");
|
||||
const { memoize } = require("sdk/lang/functional");
|
||||
|
||||
let memoizedFn = memoize(primeFactorization);
|
||||
const memoizedFn = memoize(primeFactorization);
|
||||
|
||||
memoizedFn(50); // Returns [2, 5, 5], had to compute
|
||||
memoizedFn(100); // Returns [2, 2, 5, 5], had to compute
|
||||
memoizedFn(50); // Returns [2, 5, 5] again, but pulled from cache
|
||||
|
||||
function primeFactorization (x) {
|
||||
const primeFactorization = x => {
|
||||
// Some tricky stuff
|
||||
}
|
||||
|
||||
@ -209,16 +206,14 @@ the key.
|
||||
// function will just parse the last name, as our naive
|
||||
// implementation assumes that they will share the same lineage
|
||||
|
||||
let getLineage = memoize(function (name) {
|
||||
const getLineage = memoize(name => {
|
||||
// computes lineage
|
||||
return data;
|
||||
}, hasher);
|
||||
|
||||
// Hashing function takes a string of first and last name
|
||||
// and returns the last name.
|
||||
function hasher (input) {
|
||||
return input.split(" ")[1];
|
||||
}
|
||||
const hasher = input => input.split(" ")[1];
|
||||
|
||||
getLineage("homer simpson"); // Computes and returns information for "simpson"
|
||||
getLineage("lisa simpson"); // Returns cached for "simpson"
|
||||
@ -240,12 +235,11 @@ Much like `setTimeout`, `delay` invokes a function after waiting a set number of
|
||||
milliseconds. If you pass additional, optional, arguments, they will be forwarded
|
||||
on to the function when it is invoked.
|
||||
|
||||
let { delay } = require("sdk/lang/functional");
|
||||
const { delay } = require("sdk/lang/functional");
|
||||
|
||||
const printAdd = (a, b) console.log(a + "+" + b + "=" + (a+b));
|
||||
delay(printAdd, 2000, 5, 10);
|
||||
|
||||
// Prints "5+10=15" in two seconds (2000ms)
|
||||
function printAdd (a, b) { console.log(a + "+" + b + "=" + (a+b)); }
|
||||
|
||||
@param fn {function}
|
||||
A function to be delayed.
|
||||
@ -264,8 +258,8 @@ Repeated calls to the modified function will have no effect, returning
|
||||
the value from the original call. Useful for initialization functions, instead
|
||||
of having to set a boolean flag and checking it later.
|
||||
|
||||
let { once } = require("sdk/lang/functional");
|
||||
let setup = once(function (env) {
|
||||
const { once } = require("sdk/lang/functional");
|
||||
const setup = once(env => {
|
||||
// initializing important things
|
||||
console.log("successfully initialized " + env);
|
||||
return 1; // Assume success and return 1
|
||||
@ -286,16 +280,156 @@ of having to set a boolean flag and checking it later.
|
||||
The wrapped `fn` that can only be executed once.
|
||||
</api>
|
||||
|
||||
<api name="chain">
|
||||
<api name="cache">
|
||||
@function
|
||||
An alias for [once](modules/sdk/lang/functional.html#once(fn)).
|
||||
</api>
|
||||
|
||||
<api name="complement">
|
||||
@function
|
||||
Takes a `f` function and returns a function that takes the same
|
||||
arguments as `f`, has the same effects, if any, and returns the
|
||||
opposite truth value.
|
||||
|
||||
const { complement } = require("sdk/lang/functional");
|
||||
|
||||
let isOdd = x => Boolean(x % 2);
|
||||
|
||||
isOdd(1) // => true
|
||||
isOdd(2) // => false
|
||||
|
||||
let isEven = complement(isOdd);
|
||||
|
||||
isEven(1) // => false
|
||||
isEven(2) // => true
|
||||
|
||||
@param lambda {function}
|
||||
The function to compose from
|
||||
|
||||
@returns {boolean}
|
||||
`!lambda(...)`
|
||||
</api>
|
||||
|
||||
<api name="constant">
|
||||
@function
|
||||
Constructs function that returns `x` no matter what is it
|
||||
invoked with.
|
||||
|
||||
const { constant } = require("sdk/lang/functional");
|
||||
|
||||
const one = constant(1);
|
||||
|
||||
one(); // => 1
|
||||
one(2); // => 1
|
||||
one.apply({}, 3); // => 1
|
||||
|
||||
@param x {object}
|
||||
Value that will be returned by composed function
|
||||
|
||||
@returns {function}
|
||||
</api>
|
||||
|
||||
|
||||
<api name="apply">
|
||||
@function
|
||||
Apply function that behaves like `apply` in other functional
|
||||
languages:
|
||||
|
||||
const { apply } = require("sdk/lang/functional");
|
||||
|
||||
const dashify = (...args) => args.join("-");
|
||||
|
||||
apply(dashify, 1, [2, 3]); // => "1-2-3"
|
||||
apply(dashify, "a"); // => "a"
|
||||
apply(dashify, ["a", "b"]); // => "a-b"
|
||||
apply(dashify, ["a", "b"], "c"); // => "a,b-c"
|
||||
apply(dashify, [1, 2], [3, 4]); // => "1,2-3-4"
|
||||
|
||||
@param f {function}
|
||||
function to be invoked
|
||||
</api>
|
||||
|
||||
<api name="flip">
|
||||
@function
|
||||
Returns function identical to given `f` but with flipped order
|
||||
of arguments.
|
||||
|
||||
const { flip } = require("sdk/lang/functional");
|
||||
|
||||
const append = (left, right) => left + " " + right;
|
||||
const prepend = flip(append);
|
||||
|
||||
append("hello", "world") // => "hello world"
|
||||
prepend("hello", "world") // => "world hello"
|
||||
|
||||
@param f {function}
|
||||
function whose arguments should to be flipped
|
||||
|
||||
@returns {function}
|
||||
function with flipped arguments
|
||||
</api>
|
||||
|
||||
<api name="when">
|
||||
@function
|
||||
Takes `p` predicate, `consequent` function and an optional
|
||||
`alternate` function and composes function that returns
|
||||
application of arguments over `consequent` if application over
|
||||
`p` is `true` otherwise returns application over `alternate`.
|
||||
If `alternate` is not a function returns `undefined`.
|
||||
|
||||
const { when } = require("sdk/lang/functional");
|
||||
|
||||
function Point(x, y) {
|
||||
this.x = x
|
||||
this.y = y
|
||||
}
|
||||
|
||||
const isPoint = x => x instanceof Point;
|
||||
|
||||
const inc = when(isPoint, ({x, y}) => new Point(x + 1, y + 1));
|
||||
|
||||
inc({}); // => undefined
|
||||
inc(new Point(0, 0)); // => { x: 1, y: 1 }
|
||||
|
||||
const axis = when(isPoint,
|
||||
({ x, y }) => [x, y],
|
||||
_ => [0, 0]);
|
||||
|
||||
axis(new Point(1, 4)); // => [1, 4]
|
||||
axis({ foo: "bar" }); // => [0, 0]
|
||||
|
||||
@param p {function}
|
||||
predicate function whose return value determines to which
|
||||
function be delegated control.
|
||||
|
||||
@param consequent {function}
|
||||
function to which arguments are applied if `predicate` returned
|
||||
`true`.
|
||||
|
||||
@param alternate {function}
|
||||
function to which arguments are applied if `predicate` returned
|
||||
`false`.
|
||||
|
||||
@returns {object|string|number|function}
|
||||
Return value from `consequent` if `p` returned `true` or return
|
||||
value from `alternate` if `p` returned `false`. If `alternate`
|
||||
is not provided and `p` returned `false` then `undefined` is
|
||||
returned.
|
||||
</api>
|
||||
|
||||
|
||||
<api name="chainable">
|
||||
@function
|
||||
Creates a version of the input function that will return `this`.
|
||||
|
||||
let { chain } = require("sdk/lang/functional");
|
||||
const { chainable } = require("sdk/lang/functional");
|
||||
|
||||
function Person (age) { this.age = age; }
|
||||
Person.prototype.happyBirthday = chain(function () this.age++);
|
||||
Person.prototype.happyBirthday = chainable(function() {
|
||||
return this.age++
|
||||
});
|
||||
|
||||
let person = new Person(30);
|
||||
const person = new Person(30);
|
||||
|
||||
person
|
||||
.happyBirthday()
|
||||
@ -311,7 +445,126 @@ Creates a version of the input function that will return `this`.
|
||||
The wrapped function that executes `fn` and returns `this`.
|
||||
</api>
|
||||
|
||||
<api name="cache">
|
||||
<api name="field">
|
||||
@function
|
||||
An alias for [once](modules/sdk/lang/functional.html#once(fn)).
|
||||
|
||||
Takes field `name` and `target` and returns value of that field.
|
||||
If `target` is `null` or `undefined` it would be returned back
|
||||
instead of attempt to access it's field. Function is implicitly
|
||||
curried, this allows accessor function generation by calling it
|
||||
with only `name` argument.
|
||||
|
||||
const { field } = require("sdk/lang/functional");
|
||||
|
||||
field("x", { x: 1, y: 2}); // => 1
|
||||
field("x")({ x: 1 }); // => 1
|
||||
field("x", { y: 2 }); // => undefiend
|
||||
|
||||
const getX = field("x");
|
||||
getX({ x: 1 }); // => 1
|
||||
getX({ y: 1 }); // => undefined
|
||||
getX(null); // => null
|
||||
|
||||
@param name {string}
|
||||
Name of the field to be returned
|
||||
|
||||
@param target {object}
|
||||
Target to get a field by the given `name` from
|
||||
|
||||
@returns {object|function|string|number|boolean}
|
||||
Field value
|
||||
</api>
|
||||
|
||||
<api name="query">
|
||||
@function
|
||||
|
||||
Takes `.` delimited string representing `path` to a nested field
|
||||
and a `target` to get it from. For convinience function is
|
||||
implicitly curried, there for accessors can be created by invoking
|
||||
it with just a `path` argument.
|
||||
|
||||
const { query } = require("sdk/lang/functional");
|
||||
|
||||
query("x", { x: 1, y: 2}); // => 1
|
||||
query("top.x", { x: 1 }); // => undefiend
|
||||
query("top.x", { top: { x: 2 } }); // => 2
|
||||
|
||||
const topX = query("top.x");
|
||||
topX({ top: { x: 1 } }); // => 1
|
||||
topX({ y: 1 }); // => undefined
|
||||
topX(null); // => null
|
||||
|
||||
@param path {string}
|
||||
`.` delimited path to a field
|
||||
|
||||
@param target {object}
|
||||
Target to get a field by the given `name` from
|
||||
|
||||
@returns {object|function|string|number|boolean}
|
||||
Field value
|
||||
</api>
|
||||
|
||||
<api name="isInstance">
|
||||
@function
|
||||
|
||||
Takes `Type` (constructor function) and a `value` and returns
|
||||
`true` if `value` is instance of the given `Type`. Function is
|
||||
implicitly curried this allows predicate generation by calling
|
||||
function with just first argument.
|
||||
|
||||
const { isInstance } = require("sdk/lang/functional");
|
||||
|
||||
function X() {}
|
||||
function Y() {}
|
||||
let isX = isInstance(X);
|
||||
|
||||
isInstance(X, new X); // true
|
||||
isInstance(X)(new X); // true
|
||||
isInstance(X, new Y); // false
|
||||
isInstance(X)(new Y); // false
|
||||
|
||||
isX(new X); // true
|
||||
isX(new Y); // false
|
||||
|
||||
@param Type {function}
|
||||
Type (constructor function)
|
||||
|
||||
@param instance {object}
|
||||
Instance to test
|
||||
|
||||
@returns {boolean}
|
||||
</api>
|
||||
|
||||
<api name="is">
|
||||
@function
|
||||
|
||||
Functions takes `expected` and `actual` values and returns `true` if
|
||||
`expected === actual`. If invoked with just one argument returns pratially
|
||||
applied function, which can be invoked to provide a second argument, this
|
||||
is handy with `map`, `filter` and other high order functions:
|
||||
|
||||
const { is } = require("sdk/util/oops");
|
||||
[ 1, 0, 1, 0, 1 ].map(is(1)) // => [ true, false, true, false, true ]
|
||||
|
||||
@param expected {object|string|number|boolean}
|
||||
@param actual {object|string|number|boolean}
|
||||
|
||||
@returns {boolean}
|
||||
</api>
|
||||
|
||||
<api name="isnt">
|
||||
@function
|
||||
|
||||
Functions takes `expected` and `actual` values and returns `true` if
|
||||
`expected !== actual`. If invoked with just one argument returns pratially
|
||||
applied function, which can be invoked with a second argument, which is
|
||||
handy with `map`, `filter` and other high order functions:
|
||||
|
||||
const { isnt } = require("sdk/util/oops");
|
||||
[ 1, 0, 1, 0, 1 ].map(isnt(0)) // => [ true, false, true, false, true ]
|
||||
|
||||
@param expected {object|string|number|boolean}
|
||||
@param actual {object|string|number|boolean}
|
||||
|
||||
@returns {boolean}
|
||||
</api>
|
||||
|
@ -9,7 +9,7 @@ module.metadata = {
|
||||
};
|
||||
|
||||
const { on, once, off, setListeners } = require('./core');
|
||||
const { method, chain } = require('../lang/functional');
|
||||
const { method, chainable } = require('../lang/functional');
|
||||
const { Class } = require('../core/heritage');
|
||||
|
||||
/**
|
||||
@ -43,7 +43,7 @@ const EventTarget = Class({
|
||||
* console.log('data received: ' + data)
|
||||
* })
|
||||
*/
|
||||
on: chain(method(on)),
|
||||
on: chainable(method(on)),
|
||||
/**
|
||||
* Registers an event `listener` that is called once the next time an event
|
||||
* of the specified `type` is emitted.
|
||||
@ -52,7 +52,7 @@ const EventTarget = Class({
|
||||
* @param {Function} listener
|
||||
* The listener function that processes the event.
|
||||
*/
|
||||
once: chain(method(once)),
|
||||
once: chainable(method(once)),
|
||||
/**
|
||||
* Removes an event `listener` for the given event `type`.
|
||||
* @param {String} type
|
||||
|
@ -2,7 +2,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Disclaimer: Most of the functions in this module implement APIs from
|
||||
// Disclaimer: Some of the functions in this module implement APIs from
|
||||
// Jeremy Ashkenas's http://underscorejs.org/ library and all credits for
|
||||
// those goes to him.
|
||||
|
||||
@ -12,19 +12,33 @@ module.metadata = {
|
||||
"stability": "unstable"
|
||||
};
|
||||
|
||||
const { setImmediate, setTimeout } = require("../timers");
|
||||
const { deprecateFunction } = require("../util/deprecate");
|
||||
const { setImmediate, setTimeout } = require("../timers");
|
||||
|
||||
const arity = f => f.arity || f.length;
|
||||
|
||||
const name = f => f.displayName || f.name;
|
||||
|
||||
const derive = (f, source) => {
|
||||
f.displayName = name(source);
|
||||
f.arity = arity(source);
|
||||
return f;
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes `lambda` function and returns a method. When returned method is
|
||||
* invoked it calls wrapped `lambda` and passes `this` as a first argument
|
||||
* and given argument as rest.
|
||||
* Takes variadic numeber of functions and returns composed one.
|
||||
* Returned function pushes `this` pseudo-variable to the head
|
||||
* of the passed arguments and invokes all the functions from
|
||||
* left to right passing same arguments to them. Composite function
|
||||
* returns return value of the right most funciton.
|
||||
*/
|
||||
function method(lambda) {
|
||||
return function method() {
|
||||
return lambda.apply(null, [this].concat(Array.slice(arguments)));
|
||||
}
|
||||
}
|
||||
const method = (...lambdas) => {
|
||||
return function method(...args) {
|
||||
args.unshift(this);
|
||||
return lambdas.reduce((_, lambda) => lambda.apply(this, args),
|
||||
void(0));
|
||||
};
|
||||
};
|
||||
exports.method = method;
|
||||
|
||||
/**
|
||||
@ -34,24 +48,13 @@ exports.method = method;
|
||||
* function is reused, instead of creating a new one each time. This also allows
|
||||
* to use this functions as event listeners.
|
||||
*/
|
||||
function defer(f) {
|
||||
return function deferred() setImmediate(invoke, f, arguments, this);
|
||||
}
|
||||
const defer = f => derive(function(...args) {
|
||||
setImmediate(invoke, f, args, this);
|
||||
}, f);
|
||||
exports.defer = defer;
|
||||
// Exporting `remit` alias as `defer` may conflict with promises.
|
||||
exports.remit = defer;
|
||||
|
||||
/*
|
||||
* Takes a funtion and returns a wrapped function that returns `this`
|
||||
*/
|
||||
function chain(f) {
|
||||
return function chainable(...args) {
|
||||
f.apply(this, args);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
exports.chain = chain;
|
||||
|
||||
/**
|
||||
* Invokes `callee` by passing `params` as an arguments and `self` as `this`
|
||||
* pseudo-variable. Returns value that is returned by a callee.
|
||||
@ -62,7 +65,7 @@ exports.chain = chain;
|
||||
* @param {Object} self
|
||||
* Object to be passed as a `this` pseudo variable.
|
||||
*/
|
||||
function invoke(callee, params, self) callee.apply(self, params);
|
||||
const invoke = (callee, params, self) => callee.apply(self, params);
|
||||
exports.invoke = invoke;
|
||||
|
||||
/**
|
||||
@ -74,14 +77,16 @@ exports.invoke = invoke;
|
||||
*
|
||||
* @returns The new function with binded values
|
||||
*/
|
||||
function partial(fn) {
|
||||
if (typeof fn !== "function")
|
||||
throw new TypeError(String(fn) + " is not a function");
|
||||
const partial = (f, ...curried) => {
|
||||
if (typeof(f) !== "function")
|
||||
throw new TypeError(String(f) + " is not a function");
|
||||
|
||||
let args = Array.slice(arguments, 1);
|
||||
|
||||
return function() fn.apply(this, args.concat(Array.slice(arguments)));
|
||||
}
|
||||
let fn = derive(function(...args) {
|
||||
return f.apply(this, curried.concat(args));
|
||||
}, f);
|
||||
fn.arity = arity(f) - curried.length;
|
||||
return fn;
|
||||
};
|
||||
exports.partial = partial;
|
||||
|
||||
/**
|
||||
@ -98,12 +103,11 @@ exports.partial = partial;
|
||||
* console.log(sum(2, 2)) // 4
|
||||
* console.log(sum(2)(4)) // 6
|
||||
*/
|
||||
var curry = new function() {
|
||||
function currier(fn, arity, params) {
|
||||
const curry = new function() {
|
||||
const currier = (fn, arity, params) => {
|
||||
// Function either continues to curry arguments or executes function
|
||||
// if desired arguments have being collected.
|
||||
return function curried() {
|
||||
var input = Array.slice(arguments);
|
||||
const curried = function(...input) {
|
||||
// Prepend all curried arguments to the given arguments.
|
||||
if (params) input.unshift.apply(input, params);
|
||||
// If expected number of arguments has being collected invoke fn,
|
||||
@ -111,11 +115,12 @@ var curry = new function() {
|
||||
return (input.length >= arity) ? fn.apply(this, input) :
|
||||
currier(fn, arity, input);
|
||||
};
|
||||
}
|
||||
curried.arity = arity - (params ? params.length : 0);
|
||||
|
||||
return function curry(fn) {
|
||||
return currier(fn, fn.length);
|
||||
}
|
||||
return curried;
|
||||
};
|
||||
|
||||
return fn => currier(fn, arity(fn));
|
||||
};
|
||||
exports.curry = curry;
|
||||
|
||||
@ -131,12 +136,12 @@ exports.curry = curry;
|
||||
*
|
||||
* welcome('moe'); // => 'hi: moe!'
|
||||
*/
|
||||
function compose() {
|
||||
let lambdas = Array.slice(arguments);
|
||||
return function composed() {
|
||||
let args = Array.slice(arguments), index = lambdas.length;
|
||||
function compose(...lambdas) {
|
||||
return function composed(...args) {
|
||||
let index = lambdas.length;
|
||||
while (0 <= --index)
|
||||
args = [ lambdas[index].apply(this, args) ];
|
||||
args = [lambdas[index].apply(this, args)];
|
||||
|
||||
return args[0];
|
||||
};
|
||||
}
|
||||
@ -155,16 +160,15 @@ exports.compose = compose;
|
||||
*
|
||||
* hello(); // => 'before, hello: moe, after'
|
||||
*/
|
||||
function wrap(f, wrapper) {
|
||||
return function wrapped()
|
||||
wrapper.apply(this, [ f ].concat(Array.slice(arguments)))
|
||||
};
|
||||
const wrap = (f, wrapper) => derive(function wrapped(...args) {
|
||||
return wrapper.apply(this, [f].concat(args));
|
||||
}, f);
|
||||
exports.wrap = wrap;
|
||||
|
||||
/**
|
||||
* Returns the same value that is used as the argument. In math: f(x) = x
|
||||
*/
|
||||
function identity(value) value
|
||||
const identity = value => value;
|
||||
exports.identity = identity;
|
||||
|
||||
/**
|
||||
@ -174,14 +178,25 @@ exports.identity = identity;
|
||||
* the arguments to the original function. The default hashFunction just uses
|
||||
* the first argument to the memoized function as the key.
|
||||
*/
|
||||
function memoize(f, hasher) {
|
||||
const memoize = (f, hasher) => {
|
||||
let memo = Object.create(null);
|
||||
let cache = new WeakMap();
|
||||
hasher = hasher || identity;
|
||||
return function memoizer() {
|
||||
let key = hasher.apply(this, arguments);
|
||||
return key in memo ? memo[key] : (memo[key] = f.apply(this, arguments));
|
||||
};
|
||||
}
|
||||
return derive(function memoizer(...args) {
|
||||
const key = hasher.apply(this, args);
|
||||
const type = typeof(key);
|
||||
if (key && (type === "object" || type === "function")) {
|
||||
if (!cache.has(key))
|
||||
cache.set(key, f.apply(this, args));
|
||||
return cache.get(key);
|
||||
}
|
||||
else {
|
||||
if (!(key in memo))
|
||||
memo[key] = f.apply(this, args);
|
||||
return memo[key];
|
||||
}
|
||||
}, f);
|
||||
};
|
||||
exports.memoize = memoize;
|
||||
|
||||
/**
|
||||
@ -189,9 +204,8 @@ exports.memoize = memoize;
|
||||
* the optional arguments, they will be forwarded on to the function when it is
|
||||
* invoked.
|
||||
*/
|
||||
function delay(f, ms) {
|
||||
let args = Array.slice(arguments, 2);
|
||||
setTimeout(function(context) { return f.apply(context, args); }, ms, this);
|
||||
const delay = function delay(f, ms, ...args) {
|
||||
setTimeout(() => f.apply(this, args), ms);
|
||||
};
|
||||
exports.delay = delay;
|
||||
|
||||
@ -201,10 +215,116 @@ exports.delay = delay;
|
||||
* the original call. Useful for initialization functions, instead of having to
|
||||
* set a boolean flag and then check it later.
|
||||
*/
|
||||
function once(f) {
|
||||
const once = f => {
|
||||
let ran = false, cache;
|
||||
return function() ran ? cache : (ran = true, cache = f.apply(this, arguments))
|
||||
return derive(function(...args) {
|
||||
return ran ? cache : (ran = true, cache = f.apply(this, args));
|
||||
}, f);
|
||||
};
|
||||
exports.once = once;
|
||||
// export cache as once will may be conflicting with event once a lot.
|
||||
exports.cache = once;
|
||||
|
||||
// Takes a `f` function and returns a function that takes the same
|
||||
// arguments as `f`, has the same effects, if any, and returns the
|
||||
// opposite truth value.
|
||||
const complement = f => derive(function(...args) {
|
||||
return args.length < arity(f) ? complement(partial(f, ...args)) :
|
||||
!f.apply(this, args);
|
||||
}, f);
|
||||
exports.complement = complement;
|
||||
|
||||
// Constructs function that returns `x` no matter what is it
|
||||
// invoked with.
|
||||
const constant = x => _ => x;
|
||||
exports.constant = constant;
|
||||
|
||||
// Takes `p` predicate, `consequent` function and an optional
|
||||
// `alternate` function and composes function that returns
|
||||
// application of arguments over `consequent` if application over
|
||||
// `p` is `true` otherwise returns application over `alternate`.
|
||||
// If `alternate` is not a function returns `undefined`.
|
||||
const when = (p, consequent, alternate) => {
|
||||
if (typeof(alternate) !== "function" && alternate !== void(0))
|
||||
throw TypeError("alternate must be a function");
|
||||
if (typeof(consequent) !== "function")
|
||||
throw TypeError("consequent must be a function");
|
||||
|
||||
return function(...args) {
|
||||
return p.apply(this, args) ?
|
||||
consequent.apply(this, args) :
|
||||
alternate && alternate.apply(this, args);
|
||||
};
|
||||
};
|
||||
exports.when = when;
|
||||
|
||||
// Apply function that behaves as `apply` does in lisp:
|
||||
// apply(f, x, [y, z]) => f.apply(f, [x, y, z])
|
||||
// apply(f, x) => f.apply(f, [x])
|
||||
const apply = (f, ...rest) => f.apply(f, rest.concat(rest.pop()));
|
||||
exports.apply = apply;
|
||||
|
||||
// Returns function identical to given `f` but with flipped order
|
||||
// of arguments.
|
||||
const flip = f => derive(function(...args) {
|
||||
return f.apply(this, args.reverse());
|
||||
}, f);
|
||||
exports.flip = flip;
|
||||
|
||||
|
||||
// Takes field `name` and `target` and returns value of that field.
|
||||
// If `target` is `null` or `undefined` it would be returned back
|
||||
// instead of attempt to access it's field. Function is implicitly
|
||||
// curried, this allows accessor function generation by calling it
|
||||
// with only `name` argument.
|
||||
const field = curry((name, target) =>
|
||||
// Note: Permisive `==` is intentional.
|
||||
target == null ? target : target[name]);
|
||||
exports.field = field;
|
||||
|
||||
// Takes `.` delimited string representing `path` to a nested field
|
||||
// and a `target` to get it from. For convinience function is
|
||||
// implicitly curried, there for accessors can be created by invoking
|
||||
// it with just a `path` argument.
|
||||
const query = curry((path, target) => {
|
||||
const names = path.split(".");
|
||||
const count = names.length;
|
||||
let index = 0;
|
||||
let result = target;
|
||||
// Note: Permisive `!=` is intentional.
|
||||
while (result != null && index < count) {
|
||||
result = result[names[index]];
|
||||
index = index + 1;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
exports.query = query;
|
||||
|
||||
// Takes `Type` (constructor function) and a `value` and returns
|
||||
// `true` if `value` is instance of the given `Type`. Function is
|
||||
// implicitly curried this allows predicate generation by calling
|
||||
// function with just first argument.
|
||||
const isInstance = curry((Type, value) => value instanceof Type);
|
||||
exports.isInstance = isInstance;
|
||||
|
||||
/*
|
||||
* Takes a funtion and returns a wrapped function that returns `this`
|
||||
*/
|
||||
const chainable = f => derive(function(...args) {
|
||||
f.apply(this, args);
|
||||
return this;
|
||||
}, f);
|
||||
exports.chainable = chainable;
|
||||
exports.chain =
|
||||
deprecateFunction(chainable, "Function `chain` was renamed to `chainable`");
|
||||
|
||||
// Functions takes `expected` and `actual` values and returns `true` if
|
||||
// `expected === actual`. Returns curried function if called with less then
|
||||
// two arguments.
|
||||
//
|
||||
// [ 1, 0, 1, 0, 1 ].map(is(1)) // => [ true, false, true, false, true ]
|
||||
const is = curry((expected, actual) => actual === expected);
|
||||
exports.is = is;
|
||||
|
||||
const isnt = complement(is);
|
||||
exports.isnt = isnt;
|
||||
|
@ -1,21 +1,22 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { setTimeout } = require('sdk/timers');
|
||||
const utils = require('sdk/lang/functional');
|
||||
const { invoke, defer, partial, compose, memoize, once, delay, wrap, curry, chain } = utils;
|
||||
const { invoke, defer, partial, compose, memoize, once, is, isnt,
|
||||
delay, wrap, curry, chainable, field, query, isInstance } = utils;
|
||||
const { LoaderWithHookedConsole } = require('sdk/test/loader');
|
||||
|
||||
exports['test forwardApply'] = function(assert) {
|
||||
function sum(b, c) this.a + b + c
|
||||
function sum(b, c) { return this.a + b + c; }
|
||||
assert.equal(invoke(sum, [2, 3], { a: 1 }), 6,
|
||||
'passed arguments and pseoude-variable are used');
|
||||
|
||||
assert.equal(invoke(sum.bind({ a: 2 }), [2, 3], { a: 1 }), 7,
|
||||
'bounded `this` pseoudo variable is used');
|
||||
}
|
||||
};
|
||||
|
||||
exports['test deferred function'] = function(assert, done) {
|
||||
let nextTurn = false;
|
||||
@ -26,13 +27,13 @@ exports['test deferred function'] = function(assert, done) {
|
||||
done();
|
||||
}
|
||||
|
||||
let fixture = { a: 1, method: defer(sum) }
|
||||
let fixture = { a: 1, method: defer(sum) };
|
||||
fixture.method(2, 3);
|
||||
nextTurn = true;
|
||||
};
|
||||
|
||||
exports['test partial function'] = function(assert) {
|
||||
function sum(b, c) this.a + b + c;
|
||||
function sum(b, c) { return this.a + b + c; }
|
||||
|
||||
let foo = { a : 5 };
|
||||
|
||||
@ -68,11 +69,11 @@ exports['test compose'] = function(assert) {
|
||||
let target = {
|
||||
name: 'Joe',
|
||||
greet: compose(function exclaim(sentence) {
|
||||
return sentence + '!'
|
||||
return sentence + '!';
|
||||
}, function(title) {
|
||||
return 'hi : ' + title + ' ' + this.name;
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
assert.equal(target.greet('Mr'), 'hi : Mr Joe!',
|
||||
'this can be passed in');
|
||||
@ -106,7 +107,7 @@ exports['test wrap'] = function(assert) {
|
||||
|
||||
assert.equal(target.hi(), 'Hello Matteo', 'works with this');
|
||||
|
||||
function noop() { };
|
||||
function noop() { }
|
||||
let wrapped = wrap(noop, function(f) {
|
||||
return Array.slice(arguments);
|
||||
});
|
||||
@ -117,7 +118,7 @@ exports['test wrap'] = function(assert) {
|
||||
};
|
||||
|
||||
exports['test memoize'] = function(assert) {
|
||||
function fib(n) n < 2 ? n : fib(n - 1) + fib(n - 2)
|
||||
const fib = n => n < 2 ? n : fib(n - 1) + fib(n - 2);
|
||||
let fibnitro = memoize(fib);
|
||||
|
||||
assert.equal(fib(10), 55,
|
||||
@ -125,7 +126,7 @@ exports['test memoize'] = function(assert) {
|
||||
assert.equal(fibnitro(10), 55,
|
||||
'a memoized version of fibonacci produces identical results');
|
||||
|
||||
function o(key, value) { return value; };
|
||||
function o(key, value) { return value; }
|
||||
let oo = memoize(o), v1 = {}, v2 = {};
|
||||
|
||||
|
||||
@ -136,12 +137,12 @@ exports['test memoize'] = function(assert) {
|
||||
assert.notEqual(oo(1), oo(2), 'values do not override');
|
||||
assert.equal(o(3, v2), oo(2, 3), 'returns same value as un-memoized');
|
||||
|
||||
let get = memoize(function(attribute) this[attribute])
|
||||
let target = { name: 'Bob', get: get }
|
||||
let get = memoize(function(attribute) { return this[attribute]; });
|
||||
let target = { name: 'Bob', get: get };
|
||||
|
||||
assert.equal(target.get('name'), 'Bob', 'has correct `this`');
|
||||
assert.equal(target.get.call({ name: 'Jack' }, 'name'), 'Bob',
|
||||
'name is memoized')
|
||||
'name is memoized');
|
||||
assert.equal(get('name'), 'Bob', 'once memoized can be called without this');
|
||||
};
|
||||
|
||||
@ -155,13 +156,13 @@ exports['test delay'] = function(assert, done) {
|
||||
};
|
||||
|
||||
exports['test delay with this'] = function(assert, done) {
|
||||
let context = {}
|
||||
let context = {};
|
||||
delay.call(context, function(name) {
|
||||
assert.equal(this, context, 'this was passed in');
|
||||
assert.equal(name, 'Tom', 'argument was passed in');
|
||||
done();
|
||||
}, 10, 'Tom');
|
||||
}
|
||||
};
|
||||
|
||||
exports['test once'] = function(assert) {
|
||||
let n = 0;
|
||||
@ -172,7 +173,12 @@ exports['test once'] = function(assert) {
|
||||
|
||||
assert.equal(n, 1, 'only incremented once');
|
||||
|
||||
let target = { state: 0, update: once(function() this.state ++ ) };
|
||||
let target = {
|
||||
state: 0,
|
||||
update: once(function() {
|
||||
return this.state ++;
|
||||
})
|
||||
};
|
||||
|
||||
target.update();
|
||||
target.update();
|
||||
@ -182,7 +188,7 @@ exports['test once'] = function(assert) {
|
||||
|
||||
exports['test once with argument'] = function(assert) {
|
||||
let n = 0;
|
||||
let increment = once(function(a) n++);
|
||||
let increment = once(a => n++);
|
||||
|
||||
increment();
|
||||
increment('foo');
|
||||
@ -195,11 +201,121 @@ exports['test once with argument'] = function(assert) {
|
||||
assert.equal(n, 1, 'only incremented once');
|
||||
};
|
||||
|
||||
exports['test chain'] = function (assert) {
|
||||
exports['test complement'] = assert => {
|
||||
let { complement } = require("sdk/lang/functional");
|
||||
|
||||
let isOdd = x => Boolean(x % 2);
|
||||
|
||||
assert.equal(isOdd(1), true);
|
||||
assert.equal(isOdd(2), false);
|
||||
|
||||
let isEven = complement(isOdd);
|
||||
|
||||
assert.equal(isEven(1), false);
|
||||
assert.equal(isEven(2), true);
|
||||
|
||||
let foo = {};
|
||||
let isFoo = function() { return this === foo; };
|
||||
let insntFoo = complement(isFoo);
|
||||
|
||||
assert.equal(insntFoo.call(foo), false);
|
||||
assert.equal(insntFoo.call({}), true);
|
||||
};
|
||||
|
||||
exports['test constant'] = assert => {
|
||||
let { constant } = require("sdk/lang/functional");
|
||||
|
||||
let one = constant(1);
|
||||
|
||||
assert.equal(one(1), 1);
|
||||
assert.equal(one(2), 1);
|
||||
};
|
||||
|
||||
exports['test apply'] = assert => {
|
||||
let { apply } = require("sdk/lang/functional");
|
||||
|
||||
let dashify = (...args) => args.join("-");
|
||||
|
||||
assert.equal(apply(dashify, 1, [2, 3]), "1-2-3");
|
||||
assert.equal(apply(dashify, "a"), "a");
|
||||
assert.equal(apply(dashify, ["a", "b"]), "a-b");
|
||||
assert.equal(apply(dashify, ["a", "b"], "c"), "a,b-c");
|
||||
assert.equal(apply(dashify, [1, 2], [3, 4]), "1,2-3-4");
|
||||
};
|
||||
|
||||
exports['test flip'] = assert => {
|
||||
let { flip } = require("sdk/lang/functional");
|
||||
|
||||
let append = (left, right) => left + " " + right;
|
||||
let prepend = flip(append);
|
||||
|
||||
assert.equal(append("hello", "world"), "hello world");
|
||||
assert.equal(prepend("hello", "world"), "world hello");
|
||||
|
||||
let wrap = function(left, right) {
|
||||
return left + " " + this + " " + right;
|
||||
};
|
||||
let invertWrap = flip(wrap);
|
||||
|
||||
assert.equal(wrap.call("@", "hello", "world"), "hello @ world");
|
||||
assert.equal(invertWrap.call("@", "hello", "world"), "world @ hello");
|
||||
|
||||
let reverse = flip((...args) => args);
|
||||
|
||||
assert.deepEqual(reverse(1, 2, 3, 4), [4, 3, 2, 1]);
|
||||
assert.deepEqual(reverse(1), [1]);
|
||||
assert.deepEqual(reverse(), []);
|
||||
|
||||
// currying still works
|
||||
let prependr = curry(prepend);
|
||||
|
||||
assert.equal(prependr("hello", "world"), "world hello");
|
||||
assert.equal(prependr("hello")("world"), "world hello");
|
||||
};
|
||||
|
||||
exports["test when"] = assert => {
|
||||
let { when } = require("sdk/lang/functional");
|
||||
|
||||
let areNums = (...xs) => xs.every(x => typeof(x) === "number");
|
||||
|
||||
let sum = when(areNums, (...xs) => xs.reduce((y, x) => x + y, 0));
|
||||
|
||||
assert.equal(sum(1, 2, 3), 6);
|
||||
assert.equal(sum(1, 2, "3"), undefined);
|
||||
|
||||
let multiply = when(areNums,
|
||||
(...xs) => xs.reduce((y, x) => x * y, 1),
|
||||
(...xs) => xs);
|
||||
|
||||
assert.equal(multiply(2), 2);
|
||||
assert.equal(multiply(2, 3), 6);
|
||||
assert.deepEqual(multiply(2, "4"), [2, "4"]);
|
||||
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
let isPoint = x => x instanceof Point;
|
||||
|
||||
let inc = when(isPoint, ({x, y}) => new Point(x + 1, y + 1));
|
||||
|
||||
assert.equal(inc({}), undefined);
|
||||
assert.deepEqual(inc(new Point(0, 0)), { x: 1, y: 1 });
|
||||
|
||||
let axis = when(isPoint,
|
||||
({ x, y }) => [x, y],
|
||||
_ => [0, 0]);
|
||||
|
||||
assert.deepEqual(axis(new Point(1, 4)), [1, 4]);
|
||||
assert.deepEqual(axis({ foo: "bar" }), [0, 0]);
|
||||
};
|
||||
|
||||
exports["test chainable"] = function(assert) {
|
||||
let Player = function () { this.volume = 5; };
|
||||
Player.prototype = {
|
||||
setBand: chain(function (band) this.band = band),
|
||||
incVolume: chain(function () this.volume++)
|
||||
setBand: chainable(function (band) { return (this.band = band); }),
|
||||
incVolume: chainable(function () { return this.volume++; })
|
||||
};
|
||||
let player = new Player();
|
||||
player
|
||||
@ -210,4 +326,97 @@ exports['test chain'] = function (assert) {
|
||||
assert.equal(player.volume, 11, 'accepts no arguments in chain');
|
||||
};
|
||||
|
||||
exports["test field"] = assert => {
|
||||
let Num = field("constructor", 0);
|
||||
assert.equal(Num.name, Number.name);
|
||||
assert.ok(typeof(Num), "function");
|
||||
|
||||
let x = field("x");
|
||||
|
||||
[
|
||||
[field("foo", { foo: 1 }), 1],
|
||||
[field("foo")({ foo: 1 }), 1],
|
||||
[field("bar", {}), undefined],
|
||||
[field("bar")({}), undefined],
|
||||
[field("hey", undefined), undefined],
|
||||
[field("hey")(undefined), undefined],
|
||||
[field("how", null), null],
|
||||
[field("how")(null), null],
|
||||
[x(1), undefined],
|
||||
[x(undefined), undefined],
|
||||
[x(null), null],
|
||||
[x({ x: 1 }), 1],
|
||||
[x({ x: 2 }), 2],
|
||||
].forEach(([actual, expected]) => assert.equal(actual, expected));
|
||||
};
|
||||
|
||||
exports["test query"] = assert => {
|
||||
let Num = query("constructor", 0);
|
||||
assert.equal(Num.name, Number.name);
|
||||
assert.ok(typeof(Num), "function");
|
||||
|
||||
let x = query("x");
|
||||
let xy = query("x.y");
|
||||
|
||||
[
|
||||
[query("foo", { foo: 1 }), 1],
|
||||
[query("foo")({ foo: 1 }), 1],
|
||||
[query("foo.bar", { foo: { bar: 2 } }), 2],
|
||||
[query("foo.bar")({ foo: { bar: 2 } }), 2],
|
||||
[query("foo.bar", { foo: 1 }), undefined],
|
||||
[query("foo.bar")({ foo: 1 }), undefined],
|
||||
[x(1), undefined],
|
||||
[x(undefined), undefined],
|
||||
[x(null), null],
|
||||
[x({ x: 1 }), 1],
|
||||
[x({ x: 2 }), 2],
|
||||
[xy(1), undefined],
|
||||
[xy(undefined), undefined],
|
||||
[xy(null), null],
|
||||
[xy({ x: 1 }), undefined],
|
||||
[xy({ x: 2 }), undefined],
|
||||
[xy({ x: { y: 1 } }), 1],
|
||||
[xy({ x: { y: 2 } }), 2]
|
||||
].forEach(([actual, expected]) => assert.equal(actual, expected));
|
||||
};
|
||||
|
||||
exports["test isInstance"] = assert => {
|
||||
function X() {}
|
||||
function Y() {}
|
||||
let isX = isInstance(X);
|
||||
|
||||
[
|
||||
isInstance(X, new X()),
|
||||
isInstance(X)(new X()),
|
||||
!isInstance(X, new Y()),
|
||||
!isInstance(X)(new Y()),
|
||||
isX(new X()),
|
||||
!isX(new Y())
|
||||
].forEach(x => assert.ok(x));
|
||||
};
|
||||
|
||||
exports["test is"] = assert => {
|
||||
|
||||
assert.deepEqual([ 1, 0, 1, 0, 1 ].map(is(1)),
|
||||
[ true, false, true, false, true ],
|
||||
"is can be partially applied");
|
||||
|
||||
assert.ok(is(1, 1));
|
||||
assert.ok(!is({}, {}));
|
||||
assert.ok(is()(1)()(1), "is is curried");
|
||||
assert.ok(!is()(1)()(2));
|
||||
};
|
||||
|
||||
exports["test isnt"] = assert => {
|
||||
|
||||
assert.deepEqual([ 1, 0, 1, 0, 1 ].map(isnt(0)),
|
||||
[ true, false, true, false, true ],
|
||||
"is can be partially applied");
|
||||
|
||||
assert.ok(!isnt(1, 1));
|
||||
assert.ok(isnt({}, {}));
|
||||
assert.ok(!isnt()(1)()(1));
|
||||
assert.ok(isnt()(1)()(2));
|
||||
};
|
||||
|
||||
require('test').run(exports);
|
||||
|
Loading…
Reference in New Issue
Block a user