Mercurial > pub > ImplabJs
comparison core/src/js/safe.js @ 29:acdcdf1a8d21
repository reorganized
author | cin |
---|---|
date | Tue, 26 Jun 2018 19:35:44 +0300 |
parents | src/implab/safe.js@8332e287d552 |
children | 27e8e9e38e07 |
comparison
equal
deleted
inserted
replaced
28:d796bbbe558c | 29:acdcdf1a8d21 |
---|---|
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 try { | |
179 return wrapresult(fn.apply(thisArg, arguments)); | |
180 } catch (e) { | |
181 return wrapresult(null, e); | |
182 }; | |
183 }, | |
184 | |
185 create: function () { | |
186 if (console && console.warn) | |
187 console.warn("implab/safe::create is deprecated use Object.create instead"); | |
188 _create.apply(this, arguments); | |
189 }, | |
190 | |
191 delegate: function (target, method) { | |
192 if (!(method instanceof Function)) { | |
193 this.argumentNotNull(target, "target"); | |
194 method = target[method]; | |
195 } | |
196 | |
197 if (!(method instanceof Function)) | |
198 throw new Error("'method' argument must be a Function or a method name"); | |
199 | |
200 return function () { | |
201 return method.apply(target, arguments); | |
202 }; | |
203 }, | |
204 | |
205 /** | |
206 * Для каждого элемента массива вызывает указанную функцию и сохраняет | |
207 * возвращенное значение в массиве результатов. | |
208 * | |
209 * @remarks cb может выполняться асинхронно, при этом одновременно будет | |
210 * только одна операция. | |
211 * | |
212 * @async | |
213 */ | |
214 pmap: function (items, cb) { | |
215 safe.argumentNotNull(cb, "cb"); | |
216 | |
217 if (items && items.then instanceof Function) | |
218 return items.then(function (data) { | |
219 return safe.pmap(data, cb); | |
220 }); | |
221 | |
222 if (safe.isNull(items) || !items.length) | |
223 return items; | |
224 | |
225 var i = 0, | |
226 result = []; | |
227 | |
228 function next() { | |
229 var r, ri; | |
230 | |
231 function chain(x) { | |
232 result[ri] = x; | |
233 return next(); | |
234 } | |
235 | |
236 while (i < items.length) { | |
237 r = cb(items[i], i); | |
238 ri = i; | |
239 i++; | |
240 if (r && r.then) { | |
241 return r.then(chain); | |
242 } else { | |
243 result[ri] = r; | |
244 } | |
245 } | |
246 return result; | |
247 } | |
248 | |
249 return next(); | |
250 }, | |
251 | |
252 /** | |
253 * Для каждого элемента массива вызывает указанную функцию, результаты | |
254 * не сохраняются | |
255 * | |
256 * @remarks cb может выполняться асинхронно, при этом одновременно будет | |
257 * только одна операция. | |
258 * @async | |
259 */ | |
260 pfor: function (items, cb) { | |
261 safe.argumentNotNull(cb, "cb"); | |
262 | |
263 if (items && items.then instanceof Function) | |
264 return items.then(function (data) { | |
265 return safe.pmap(data, cb); | |
266 }); | |
267 | |
268 if (safe.isNull(items) || !items.length) | |
269 return items; | |
270 | |
271 var i = 0; | |
272 | |
273 function next() { | |
274 while (i < items.length) { | |
275 var r = cb(items[i], i); | |
276 i++; | |
277 if (r && r.then) | |
278 return r.then(next); | |
279 } | |
280 } | |
281 | |
282 return next(); | |
283 }, | |
284 | |
285 /** | |
286 * Выбирает первый элемент из последовательности, или обещания, если в | |
287 * качестве параметра используется обещание, оно должно вернуть массив. | |
288 * | |
289 * @param{Function} cb обработчик результата, ему будет передан первый | |
290 * элемент последовательности в случае успеха | |
291 * @param{Fucntion} err обработчик исключения, если массив пустой, либо | |
292 * не массив | |
293 * | |
294 * @remarks Если не указаны ни cb ни err, тогда функция вернет либо | |
295 * обещание, либо первый элемент. | |
296 * @async | |
297 */ | |
298 first: function (sequence, cb, err) { | |
299 if (sequence) { | |
300 if (sequence.then instanceof Function) { | |
301 return sequence.then(function (res) { | |
302 return safe.first(res, cb, err); | |
303 }, err); | |
304 } else if (sequence && "length" in sequence) { | |
305 if (sequence.length === 0) { | |
306 if (err) | |
307 return err(new Error("The sequence is empty")); | |
308 else | |
309 throw new Error("The sequence is empty"); | |
310 } | |
311 return cb ? cb(sequence[0]) : sequence[0]; | |
312 } | |
313 } | |
314 | |
315 if (err) | |
316 return err(new Error("The sequence is required")); | |
317 else | |
318 throw new Error("The sequence is required"); | |
319 } | |
320 }; | |
321 | |
322 return safe; | |
323 }); |