UNPKG

5.04 kBJavaScriptView Raw
1'use strict';
2
3var format = require('../../utils/string').format;
4var lazy = require('../../utils/object').lazy;
5
6function factory(type, config, load, typed, math) {
7 /**
8 * @constructor Chain
9 * Wrap any value in a chain, allowing to perform chained operations on
10 * the value.
11 *
12 * All methods available in the math.js library can be called upon the chain,
13 * and then will be evaluated with the value itself as first argument.
14 * The chain can be closed by executing chain.done(), which will return
15 * the final value.
16 *
17 * The Chain has a number of special functions:
18 * - done() Finalize the chained operation and return the
19 * chain's value.
20 * - valueOf() The same as done()
21 * - toString() Returns a string representation of the chain's value.
22 *
23 * @param {*} [value]
24 */
25 function Chain(value) {
26 if (!(this instanceof Chain)) {
27 throw new SyntaxError('Constructor must be called with the new operator');
28 }
29
30 if (type.isChain(value)) {
31 this.value = value.value;
32 } else {
33 this.value = value;
34 }
35 }
36
37 /**
38 * Attach type information
39 */
40 Chain.prototype.type = 'Chain';
41 Chain.prototype.isChain = true;
42
43 /**
44 * Close the chain. Returns the final value.
45 * Does the same as method valueOf()
46 * @returns {*} value
47 */
48 Chain.prototype.done = function () {
49 return this.value;
50 };
51
52 /**
53 * Close the chain. Returns the final value.
54 * Does the same as method done()
55 * @returns {*} value
56 */
57 Chain.prototype.valueOf = function () {
58 return this.value;
59 };
60
61 /**
62 * Get a string representation of the value in the chain
63 * @returns {string}
64 */
65 Chain.prototype.toString = function () {
66 return format(this.value);
67 };
68
69 /**
70 * Get a JSON representation of the chain
71 * @returns {Object}
72 */
73 Chain.prototype.toJSON = function () {
74 return {
75 mathjs: 'Chain',
76 value: this.value
77 };
78 };
79
80 /**
81 * Instantiate a Chain from its JSON representation
82 * @param {Object} json An object structured like
83 * `{"mathjs": "Chain", value: ...}`,
84 * where mathjs is optional
85 * @returns {Chain}
86 */
87 Chain.fromJSON = function (json) {
88 return new Chain(json.value);
89 };
90
91 /**
92 * Create a proxy method for the chain
93 * @param {string} name
94 * @param {Function} fn The function to be proxied
95 * If fn is no function, it is silently ignored.
96 * @private
97 */
98 function createProxy(name, fn) {
99 if (typeof fn === 'function') {
100 Chain.prototype[name] = chainify(fn);
101 }
102 }
103
104 /**
105 * Create a proxy method for the chain
106 * @param {string} name
107 * @param {function} resolver The function resolving with the
108 * function to be proxied
109 * @private
110 */
111 function createLazyProxy(name, resolver) {
112 lazy(Chain.prototype, name, function outerResolver() {
113 var fn = resolver();
114 if (typeof fn === 'function') {
115 return chainify(fn);
116 }
117
118 return undefined; // if not a function, ignore
119 });
120 }
121
122 /**
123 * Make a function chainable
124 * @param {function} fn
125 * @return {Function} chain function
126 * @private
127 */
128 function chainify(fn) {
129 return function () {
130 var args = [this.value]; // `this` will be the context of a Chain instance
131 for (var i = 0; i < arguments.length; i++) {
132 args[i + 1] = arguments[i];
133 }
134
135 return new Chain(fn.apply(fn, args));
136 };
137 }
138
139 /**
140 * Create a proxy for a single method, or an object with multiple methods.
141 * Example usage:
142 *
143 * Chain.createProxy('add', function add (x, y) {...})
144 * Chain.createProxy({
145 * add: function add (x, y) {...},
146 * subtract: function subtract (x, y) {...}
147 * }
148 *
149 * @param {string | Object} arg0 A name (string), or an object with
150 * functions
151 * @param {*} [arg1] A function, when arg0 is a name
152 */
153 Chain.createProxy = function (arg0, arg1) {
154 if (typeof arg0 === 'string') {
155 // createProxy(name, value)
156 createProxy(arg0, arg1);
157 } else {
158 // createProxy(values)
159 for (var prop in arg0) {
160 if (arg0.hasOwnProperty(prop)) {
161 createProxy(prop, arg0[prop]);
162 }
163 }
164 }
165 };
166
167 // create proxy for everything that is in math.js
168 Chain.createProxy(math);
169
170 // register on the import event, automatically add a proxy for every imported function.
171 math.on('import', function (name, resolver, path) {
172 if (path === undefined) {
173 // an imported function (not a data type or something special)
174 createLazyProxy(name, resolver);
175 }
176 });
177
178 return Chain;
179}
180
181exports.name = 'Chain';
182exports.path = 'type';
183exports.factory = factory;
184exports.math = true; // require providing the math namespace as 5th argument
185exports.lazy = false; // we need to register a listener on the import events, so no lazy loading
\No newline at end of file