UNPKG

4.6 kBJavaScriptView Raw
1(function() {
2 var JsPath,
3 __slice = Array.prototype.slice;
4
5 this.JsPath = (function() {
6 var primTypes,
7 _this = this;
8
9 primTypes = /^(string|number|boolean)$/;
10
11 /*
12 @constructor.
13 @signature: new JsPath(path, val)
14 @param: path - a dot-notation style "path" to identify a
15 nested JS object.
16 @description: Initialize a new js object with the provided
17 path. I've never actually used this constructor for any-
18 thing, and it is here for the sake of "comprehensiveness"
19 at this time, although I am incredulous as to it's overall
20 usefulness.
21 */
22
23 function JsPath(path, val) {
24 return JsPath.setAt({}, path, val || {});
25 }
26
27 ['forEach', 'indexOf', 'join', 'pop', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'push'].forEach(function(method) {
28 return JsPath[method + 'At'] = function() {
29 var obj, path, rest, target;
30 obj = arguments[0], path = arguments[1], rest = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
31 target = JsPath.getAt(obj, path);
32 if ('function' === typeof (target != null ? target[method] : void 0)) {
33 return target[method].apply(target, rest);
34 } else {
35 throw new Error("Does not implement method " + method + " at " + path);
36 }
37 };
38 });
39
40 /*
41 @method. property of the constructor.
42 @signature: JsPath.getAt(ref, path)
43 @param: ref - the object to traverse.
44 @param: path - a dot-notation style "path" to identify a
45 nested JS object.
46 @return: the object that can be found inside ref at the path
47 described by the second parameter or undefined if the path
48 is not valid.
49 */
50
51 JsPath.getAt = function(ref, path) {
52 var prop;
53 if ('function' === typeof path.split) {
54 path = path.split('.');
55 } else {
56 path = path.slice();
57 }
58 while ((ref != null) && (prop = path.shift())) {
59 ref = ref[prop];
60 }
61 return ref;
62 };
63
64 /*
65 @method. property of the constructor.
66 @signature: JsPath.getAt(ref, path)
67 @param: obj - the object to extend.
68 @param: path - a dot-notation style "path" to identify a
69 nested JS object.
70 @param: val - the value to assign to the path of the obj.
71 @return: the object that was extended.
72 @description: set a property to the path provided by the
73 second parameter with the value provided by the third
74 parameter.
75 */
76
77 JsPath.setAt = function(obj, path, val) {
78 var component, last, prev, ref;
79 if ('function' === typeof path.split) {
80 path = path.split('.');
81 } else {
82 path = path.slice();
83 }
84 last = path.pop();
85 prev = [];
86 ref = obj;
87 while (component = path.shift()) {
88 if (primTypes.test(typeof ref[component])) {
89 throw new Error("" + (prev.concat(component).join('.')) + " is\nprimitive, and cannot be extended.");
90 }
91 ref = ref[component] || (ref[component] = {});
92 prev.push(component);
93 }
94 ref[last] = val;
95 return obj;
96 };
97
98 JsPath.assureAt = function(ref, path, initializer) {
99 var obj;
100 if (obj = this.getAt(ref, path)) {
101 return obj;
102 } else {
103 this.setAt(ref, path, initializer);
104 return initializer;
105 }
106 };
107
108 /*
109 @method. property of the constructor.
110 @signature: JsPath.deleteAt(ref, path)
111 @param: obj - the object to extend.
112 @param: path - a dot-notation style "path" to identify a
113 nested JS object to dereference.
114 @return: boolean success.
115 @description: deletes the reference specified by the last
116 unit of the path from the object specified by other
117 components of the path, belonging to the provided object.
118 */
119
120 JsPath.deleteAt = function(ref, path) {
121 var component, last, prev;
122 if ('function' === typeof path.split) {
123 path = path.split('.');
124 } else {
125 path = path.slice();
126 }
127 prev = [];
128 last = path.pop();
129 while (component = path.shift()) {
130 if (primTypes.test(typeof ref[component])) {
131 throw new Error("" + (prev.concat(component).join('.')) + " is\nprimitive; cannot drill any deeper.");
132 }
133 if (!(ref = ref[component])) return false;
134 prev.push(component);
135 }
136 return delete ref[last];
137 };
138
139 return JsPath;
140
141 }).call(this);
142
143 /*
144 Footnotes:
145 1 - if there's no .split() method, assume it's already an array
146 */
147
148}).call(this);