Mercurial > pub > ImplabJs
comparison src/implab/safe.js @ 34:27e8e9e38e07 default tip
Слияние
author | nickolay |
---|---|
date | Wed, 05 Jun 2019 20:44:15 +0300 |
parents | 8af8e840dd49 1dc2fd263b90 |
children |
comparison
equal
deleted
inserted
replaced
33:8af8e840dd49 | 34:27e8e9e38e07 |
---|---|
1 define([], | |
2 | |
3 function () { | |
4 var _create = Object.create, | |
5 _keys = Object.keys; | |
6 | |
7 var safe = null; | |
8 safe = { | |
9 argumentNotNull: function (arg, name) { | |
10 if (arg === null || arg === undefined) | |
11 throw new Error("The argument " + name + " can't be null or undefined"); | |
12 }, | |
13 | |
14 argumentNotEmptyString: function (arg, name) { | |
15 if (typeof (arg) !== "string" || !arg.length) | |
16 throw new Error("The argument '" + name + "' must be a not empty string"); | |
17 }, | |
18 | |
19 argumentNotEmptyArray: function (arg, name) { | |
20 if (!(arg instanceof Array) || !arg.length) | |
21 throw new Error("The argument '" + name + "' must be a not empty array"); | |
22 }, | |
23 | |
24 argumentOfType: function (arg, type, name) { | |
25 if (!(arg instanceof type)) | |
26 throw new Error("The argument '" + name + "' type doesn't match"); | |
27 }, | |
28 | |
29 isNull: function (arg) { | |
30 return (arg === null || arg === undefined); | |
31 }, | |
32 | |
33 isPrimitive: function (arg) { | |
34 return (arg === null || arg === undefined || typeof (arg) === "string" || | |
35 typeof (arg) === "number" || typeof (arg) === "boolean"); | |
36 }, | |
37 | |
38 isInteger: function (arg) { | |
39 return parseInt(arg) == arg; | |
40 }, | |
41 | |
42 isNumber: function (arg) { | |
43 return parseFloat(arg) == arg; | |
44 }, | |
45 | |
46 isString: function (val) { | |
47 return typeof (val) == "string" || val instanceof String; | |
48 }, | |
49 | |
50 isNullOrEmptyString: function (str) { | |
51 if (str === null || str === undefined || | |
52 ((typeof (str) == "string" || str instanceof String) && str.length === 0)) | |
53 return true; | |
54 }, | |
55 | |
56 isNotEmptyArray: function (arg) { | |
57 return (arg instanceof Array && arg.length > 0); | |
58 }, | |
59 | |
60 /** | |
61 * Выполняет метод для каждого элемента массива, останавливается, когда | |
62 * либо достигнут конец массива, либо функция <c>cb</c> вернула | |
63 * значение. | |
64 * | |
65 * @param{Array | Object} obj массив элементов для просмотра | |
66 * @param{Function} cb функция, вызываемая для каждого элемента | |
67 * @param{Object} thisArg значение, которое будет передано в качестве | |
68 * <c>this</c> в <c>cb</c>. | |
69 * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c> | |
70 * если достигнут конец массива. | |
71 */ | |
72 each: function (obj, cb, thisArg) { | |
73 safe.argumentNotNull(cb, "cb"); | |
74 var i, x; | |
75 if (obj instanceof Array) { | |
76 for (i = 0; i < obj.length; i++) { | |
77 x = cb.call(thisArg, obj[i], i); | |
78 if (x !== undefined) | |
79 return x; | |
80 } | |
81 } else { | |
82 var keys = _keys(obj); | |
83 for (i = 0; i < keys.length; i++) { | |
84 var k = keys[i]; | |
85 x = cb.call(thisArg, obj[k], k); | |
86 if (x !== undefined) | |
87 return x; | |
88 } | |
89 } | |
90 }, | |
91 | |
92 /** | |
93 * Копирует свойства одного объекта в другой. | |
94 * | |
95 * @param{Any} dest объект в который нужно скопировать значения | |
96 * @param{Any} src источник из которого будут копироваться значения | |
97 * @tmpl{Object|Array} tmpl шаблон по которому будет происходить | |
98 * копирование. Если шаблон является массивом | |
99 * (список свойств), тогда значения этого массива | |
100 * являются именами свойсвт которые будут | |
101 * скопированы. Если шаблон является объектом (карта | |
102 * преобразования имен свойств src->dst), тогда | |
103 * копирование будет осуществляться только | |
104 * собственных свойств источника, присутсвующих в | |
105 * шаблоне, при этом значение свойства шаблона | |
106 * является именем свойства в которое будет | |
107 * произведено коприрование | |
108 */ | |
109 mixin: function (dest, src, tmpl) { | |
110 safe.argumentNotNull(dest, "dest"); | |
111 if (!src) | |
112 return dest; | |
113 | |
114 var keys, i, p; | |
115 if (arguments.length < 3) { | |
116 keys = _keys(src); | |
117 for (i = 0; i < keys.length; i++) { | |
118 p = keys[i]; | |
119 dest[p] = src[p]; | |
120 } | |
121 } else { | |
122 if (tmpl instanceof Array) { | |
123 for (i = 0; i < tmpl.length; i++) { | |
124 p = tmpl[i]; | |
125 if (p in src) | |
126 dest[p] = src[p]; | |
127 } | |
128 | |
129 } else { | |
130 keys = _keys(src); | |
131 for (i = 0; i < keys.length; i++) { | |
132 p = keys[i]; | |
133 if (p in tmpl) | |
134 dest[tmpl[p]] = src[p]; | |
135 } | |
136 } | |
137 } | |
138 return dest; | |
139 }, | |
140 | |
141 /** Wraps the specified function to emulate an asynchronous execution. | |
142 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function. | |
143 * @param{Function|String} fn [Required] Function wich will be wrapped. | |
144 */ | |
145 async: function (fn, thisArg) { | |
146 if (arguments.length == 2 && !(fn instanceof Function)) | |
147 fn = thisArg[fn]; | |
148 | |
149 if (fn == null) | |
150 throw new Error("The function must be specified"); | |
151 | |
152 function wrapresult(x, e) { | |
153 if (e) { | |
154 return { | |
155 then: function (cb, eb) { | |
156 try { | |
157 return eb ? wrapresult(eb(e)) : this; | |
158 } catch (e2) { | |
159 return wrapresult(null, e2); | |
160 } | |
161 } | |
162 }; | |
163 } else { | |
164 if (x && x.then) | |
165 return x; | |
166 return { | |
167 then: function (cb) { | |
168 try { | |
169 return cb ? wrapresult(cb(x)) : this; | |
170 } catch (e2) { | |
171 return wrapresult(e2); | |
172 } | |
173 } | |
174 }; | |
175 } | |
176 } | |
177 | |
178 return function () { | |
179 try { | |
180 return wrapresult(fn.apply(thisArg, arguments)); | |
181 } catch (e) { | |
182 return wrapresult(null, e); | |
183 } | |
184 }; | |
185 }, | |
186 | |
187 create: function () { | |
188 if (console && console.warn) | |
189 console.warn("implab/safe::create is deprecated use Object.create instead"); | |
190 _create.apply(this, arguments); | |
191 }, | |
192 | |
193 delegate: function (target, method) { | |
194 if (!(method instanceof Function)) { | |
195 this.argumentNotNull(target, "target"); | |
196 method = target[method]; | |
197 } | |
198 | |
199 if (!(method instanceof Function)) | |
200 throw new Error("'method' argument must be a Function or a method name"); | |
201 | |
202 return function () { | |
203 return method.apply(target, arguments); | |
204 }; | |
205 }, | |
206 | |
207 /** | |
208 * Для каждого элемента массива вызывает указанную функцию и сохраняет | |
209 * возвращенное значение в массиве результатов. | |
210 * | |
211 * @remarks cb может выполняться асинхронно, при этом одновременно будет | |
212 * только одна операция. | |
213 * | |
214 * @async | |
215 */ | |
216 pmap: function (items, cb) { | |
217 safe.argumentNotNull(cb, "cb"); | |
218 | |
219 if (items && items.then instanceof Function) | |
220 return items.then(function (data) { | |
221 return safe.pmap(data, cb); | |
222 }); | |
223 | |
224 if (safe.isNull(items) || !items.length) | |
225 return items; | |
226 | |
227 var i = 0, | |
228 result = []; | |
229 | |
230 function next() { | |
231 var r, ri; | |
232 | |
233 function chain(x) { | |
234 result[ri] = x; | |
235 return next(); | |
236 } | |
237 | |
238 while (i < items.length) { | |
239 r = cb(items[i], i); | |
240 ri = i; | |
241 i++; | |
242 if (r && r.then) { | |
243 return r.then(chain); | |
244 } else { | |
245 result[ri] = r; | |
246 } | |
247 } | |
248 return result; | |
249 } | |
250 | |
251 return next(); | |
252 }, | |
253 | |
254 /** | |
255 * Для каждого элемента массива вызывает указанную функцию, результаты | |
256 * не сохраняются | |
257 * | |
258 * @remarks cb может выполняться асинхронно, при этом одновременно будет | |
259 * только одна операция. | |
260 * @async | |
261 */ | |
262 pfor: function (items, cb) { | |
263 safe.argumentNotNull(cb, "cb"); | |
264 | |
265 if (items && items.then instanceof Function) | |
266 return items.then(function (data) { | |
267 return safe.pmap(data, cb); | |
268 }); | |
269 | |
270 if (safe.isNull(items) || !items.length) | |
271 return items; | |
272 | |
273 var i = 0; | |
274 | |
275 function next() { | |
276 while (i < items.length) { | |
277 var r = cb(items[i], i); | |
278 i++; | |
279 if (r && r.then) | |
280 return r.then(next); | |
281 } | |
282 } | |
283 | |
284 return next(); | |
285 }, | |
286 | |
287 /** | |
288 * Выбирает первый элемент из последовательности, или обещания, если в | |
289 * качестве параметра используется обещание, оно должно вернуть массив. | |
290 * | |
291 * @param{Function} cb обработчик результата, ему будет передан первый | |
292 * элемент последовательности в случае успеха | |
293 * @param{Fucntion} err обработчик исключения, если массив пустой, либо | |
294 * не массив | |
295 * | |
296 * @remarks Если не указаны ни cb ни err, тогда функция вернет либо | |
297 * обещание, либо первый элемент. | |
298 * @async | |
299 */ | |
300 first: function (sequence, cb, err) { | |
301 if (sequence) { | |
302 if (sequence.then instanceof Function) { | |
303 return sequence.then(function (res) { | |
304 return safe.first(res, cb, err); | |
305 }, err); | |
306 } else if (sequence && "length" in sequence) { | |
307 if (sequence.length === 0) { | |
308 if (err) | |
309 return err(new Error("The sequence is empty")); | |
310 else | |
311 throw new Error("The sequence is empty"); | |
312 } | |
313 return cb ? cb(sequence[0]) : sequence[0]; | |
314 } | |
315 } | |
316 | |
317 if (err) | |
318 return err(new Error("The sequence is required")); | |
319 else | |
320 throw new Error("The sequence is required"); | |
321 } | |
322 }; | |
323 | |
324 return safe; | |
325 }); |