Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
MapUtil |
|
| 0.0;0 |
1 | /* | |
2 | * Licensed under the MIT License | |
3 | * | |
4 | * Copyright 2010 (c) Flávio Silva, http://flsilva.com | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person | |
7 | * obtaining a copy of this software and associated documentation | |
8 | * files (the "Software"), to deal in the Software without | |
9 | * restriction, including without limitation the rights to use, | |
10 | * copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | * copies of the Software, and to permit persons to whom the | |
12 | * Software is furnished to do so, subject to the following | |
13 | * conditions: | |
14 | * | |
15 | * The above copyright notice and this permission notice shall be | |
16 | * included in all copies or substantial portions of the Software. | |
17 | * | |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
20 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
22 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
23 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
25 | * OTHER DEALINGS IN THE SOFTWARE. | |
26 | * | |
27 | * http://www.opensource.org/licenses/mit-license.php | |
28 | */ | |
29 | ||
30 | 1 | package org.as3collections.utils |
31 | { | |
32 | import org.as3collections.ICollection; | |
33 | import org.as3collections.IIterator; | |
34 | import org.as3collections.IListMap; | |
35 | import org.as3collections.IMap; | |
36 | import org.as3collections.IMapEntry; | |
37 | import org.as3collections.ISortedMap; | |
38 | import org.as3collections.maps.TypedListMap; | |
39 | import org.as3collections.maps.TypedMap; | |
40 | import org.as3collections.maps.TypedSortedMap; | |
41 | import org.as3utils.BooleanUtil; | |
42 | import org.as3utils.NumberUtil; | |
43 | import org.as3utils.ReflectionUtil; | |
44 | ||
45 | import flash.errors.IllegalOperationError; | |
46 | ||
47 | /** | |
48 | * A utility class to work with implementations of the <code>IMap</code> interface. | |
49 | * | |
50 | * @author Flávio Silva | |
51 | */ | |
52 | public class MapUtil | |
53 | { | |
54 | /** | |
55 | * <code>MapUtil</code> is a static class and shouldn't be instantiated. | |
56 | * | |
57 | * @throws IllegalOperationError <code>MapUtil</code> is a static class and shouldn't be instantiated. | |
58 | */ | |
59 | public function MapUtil() | |
60 | 1 | { |
61 | 1 | throw new IllegalOperationError("MapUtil is a static class and shouldn't be instantiated."); |
62 | } | |
63 | ||
64 | /** | |
65 | * Performs an arbitrary, specific evaluation of equality between this object and the <code>other</code> object. | |
66 | * If one of the maps or both maps are <code>null</code> it will be returned <code>false</code>. | |
67 | * <p>Two different objects are considered equal if:</p> | |
68 | * <p> | |
69 | * <ul><li>object A and object B are instances of the same class (i.e. if they have <b>exactly</b> the same type)</li> | |
70 | * <li>object A contains all mappings of object B</li> | |
71 | * <li>object B contains all mappings of object A</li> | |
72 | * <li>mappings have exactly the same order</li> | |
73 | * </ul></p> | |
74 | * <p>This implementation <b>takes care</b> of the order of the mappings in the maps. | |
75 | * So, for two maps are equal the order of entries returned by the iterator object must be equal.</p> | |
76 | * | |
77 | * @param map1 the first map. | |
78 | * @param map2 the second map. | |
79 | * @return <code>true</code> if the arbitrary evaluation considers the objects equal. | |
80 | */ | |
81 | public static function equalConsideringOrder(map1:IMap, map2:IMap): Boolean | |
82 | { | |
83 | 1 | if (!map1 || !map2) return false; |
84 | 1 | if (map1 == map2) return true; |
85 | ||
86 | 1 | if (!ReflectionUtil.classPathEquals(map1, map2)) return false; |
87 | 1 | if (map1.size() != map2.size()) return false; |
88 | ||
89 | 1 | var itEntryList1:IIterator = map1.entryCollection().iterator(); |
90 | 1 | var itEntryList2:IIterator = map2.entryCollection().iterator(); |
91 | var mapEntry1:IMapEntry; | |
92 | var mapEntry2:IMapEntry; | |
93 | ||
94 | 1 | while (itEntryList1.hasNext()) |
95 | { | |
96 | 1 | mapEntry1 = itEntryList1.next(); |
97 | 1 | mapEntry2 = itEntryList2.next(); |
98 | ||
99 | 1 | if (!mapEntry1.equals(mapEntry2)) return false; |
100 | } | |
101 | ||
102 | 1 | return true; |
103 | } | |
104 | ||
105 | /** | |
106 | * Performs an arbitrary, specific evaluation of equality between this object and the <code>other</code> object. | |
107 | * If one of the maps or both maps are <code>null</code> it will be returned <code>false</code>. | |
108 | * <p>Two different objects are considered equal if:</p> | |
109 | * <p> | |
110 | * <ul><li>object A and object B are instances of the same class (i.e. if they have <b>exactly</b> the same type)</li> | |
111 | * <li>object A contains all mappings of object B</li> | |
112 | * <li>object B contains all mappings of object A</li> | |
113 | * </ul></p> | |
114 | * <p>This implementation <b>does not takes care</b> of the order of the mappings in the map.</p> | |
115 | * | |
116 | * @param map1 the first map. | |
117 | * @param map2 the second map. | |
118 | * @return <code>true</code> if the arbitrary evaluation considers the objects equal. | |
119 | */ | |
120 | public static function equalNotConsideringOrder(map1:IMap, map2:IMap): Boolean | |
121 | { | |
122 | 1 | if (!map1 || !map2) return false; |
123 | 1 | if (map1 == map2) return true; |
124 | ||
125 | 1 | if (!ReflectionUtil.classPathEquals(map1, map2)) return false; |
126 | 1 | if (map1.size() != map2.size()) return false; |
127 | ||
128 | 1 | var itMap1:IIterator = map1.entryCollection().iterator(); |
129 | 1 | var entryListMap2:ICollection = map2.entryCollection(); |
130 | ||
131 | // because maps has same size | |
132 | // it's not necessary to perform bidirectional validation | |
133 | // i.e. if map1 contains all entries of map2 | |
134 | // consequently map2 contains all entries of map1 | |
135 | 1 | while (itMap1.hasNext()) |
136 | { | |
137 | 1 | if (!entryListMap2.contains(itMap1.next())) return false; |
138 | } | |
139 | ||
140 | 1 | return true; |
141 | } | |
142 | ||
143 | /** | |
144 | * Feeds argument <code>map</code> with argument <code>list</code>. | |
145 | * <p>The name of the nodes become keys and the values of the nodes become values of the <code>IMap</code> object.</p> | |
146 | * | |
147 | * @example | |
148 | * | |
149 | * <listing version="3.0"> | |
150 | * import org.as3collections.maps.HashMap; | |
151 | * import org.as3collections.utils.MapUtil; | |
152 | * | |
153 | * var map:IMap = new HashMap(); | |
154 | * var xml:XML = <index><key1>value1</key1><key2>value2</key2></index>; | |
155 | * | |
156 | * MapUtil.feedMapFromXmlList(map, xml.children()); | |
157 | * | |
158 | * trace(map); // [key1=value1,key2=value2] | |
159 | * </listing> | |
160 | * | |
161 | * @param map the map to be fed. | |
162 | * @param list the list to retrieve entries. | |
163 | * @param typeCoercion if <code>true</code> performs a type coercion to Boolean if some String is "true" or "false", or a type coercion to Number if some String is a Number <code>(i.e. !isNaN(Number(string)) == true)</code>. | |
164 | */ | |
165 | public static function feedMapWithXmlList(map:IMap, list:XMLList, typeCoercion:Boolean = true): void | |
166 | { | |
167 | 1 | if (!map) throw new ArgumentError("Argument <map> must not be null."); |
168 | 1 | if (!list) return; |
169 | ||
170 | var nodeName:*; | |
171 | var nodeValue:*; | |
172 | ||
173 | 1 | for each (var node:XML in list) |
174 | { | |
175 | 1 | nodeName = node.localName(); |
176 | ||
177 | 1 | if (node.hasComplexContent()) |
178 | { | |
179 | 0 | if (!isNaN(node.children().length()) && node.children().length() > 0) |
180 | { | |
181 | 0 | nodeValue = feedMapWithXmlList(map, node.children(), typeCoercion); |
182 | } | |
183 | else | |
184 | { | |
185 | 0 | nodeValue = node; |
186 | } | |
187 | } | |
188 | else | |
189 | { | |
190 | 1 | nodeValue = node.toString(); |
191 | } | |
192 | ||
193 | 1 | if (typeCoercion) |
194 | { | |
195 | 1 | if (BooleanUtil.isBooleanString(nodeName)) |
196 | { | |
197 | 0 | nodeName = BooleanUtil.string2Boolean(nodeName); |
198 | } | |
199 | 1 | else if (NumberUtil.isNumber(Number(nodeName))) |
200 | { | |
201 | 0 | nodeName = Number(nodeName); |
202 | } | |
203 | ||
204 | 1 | if (BooleanUtil.isBooleanString(nodeValue)) |
205 | { | |
206 | 1 | nodeValue = BooleanUtil.string2Boolean(nodeValue); |
207 | } | |
208 | 1 | else if (NumberUtil.isNumber(Number(nodeValue))) |
209 | { | |
210 | 1 | nodeValue = Number(nodeValue); |
211 | } | |
212 | } | |
213 | ||
214 | 1 | map.put(nodeName, nodeValue); |
215 | } | |
216 | 1 | } |
217 | ||
218 | /** | |
219 | * Returns a new <code>TypedMap</code> with the <code>wrapMap</code> argument wrapped. | |
220 | * | |
221 | * @param wrapMap the target map to be wrapped by the <code>TypedMap</code>. | |
222 | * @param typeKeys the type of the keys allowed by the returned <code>TypedMap</code>. | |
223 | * @param typeValues the type of the values allowed by the returned <code>TypedMap</code>. | |
224 | * @throws ArgumentError if the <code>wrapMap</code> argument is <code>null</code>. | |
225 | * @throws ArgumentError if the <code>typeKeys</code> argument is <code>null</code>. | |
226 | * @throws ArgumentError if the <code>typeValues</code> argument is <code>null</code>. | |
227 | * @throws org.as3coreaddendum.errors.ClassCastError if the types of one or more keys or values in the <code>wrapMap</code> argument are incompatible with the <code>typeKeys</code> or <code>typeValues</code> argument. | |
228 | * @return a new <code>TypedMap</code> with the <code>wrapMap</code> argument wrapped. | |
229 | */ | |
230 | public static function getTypedMap(wrapMap:IMap, typeKeys:*, typeValues:*): TypedMap | |
231 | { | |
232 | 1 | return new TypedMap(wrapMap, typeKeys, typeValues); |
233 | } | |
234 | ||
235 | /** | |
236 | * Returns a new <code>TypedListMap</code> with the <code>wrapMap</code> argument wrapped. | |
237 | * | |
238 | * @param wrapMap the target map to be wrapped by the <code>TypedListMap</code>. | |
239 | * @param typeKeys the type of the keys allowed by the returned <code>TypedListMap</code>. | |
240 | * @param typeValues the type of the values allowed by the returned <code>TypedListMap</code>. | |
241 | * @throws ArgumentError if the <code>wrapMap</code> argument is <code>null</code>. | |
242 | * @throws ArgumentError if the <code>typeKeys</code> argument is <code>null</code>. | |
243 | * @throws ArgumentError if the <code>typeValues</code> argument is <code>null</code>. | |
244 | * @throws org.as3coreaddendum.errors.ClassCastError if the types of one or more keys or values in the <code>wrapMap</code> argument are incompatible with the <code>typeKeys</code> or <code>typeValues</code> argument. | |
245 | * @return a new <code>TypedListMap</code> with the <code>wrapMap</code> argument wrapped. | |
246 | */ | |
247 | public static function getTypedListMap(wrapMap:IListMap, typeKeys:*, typeValues:*): TypedListMap | |
248 | { | |
249 | 1 | return new TypedListMap(wrapMap, typeKeys, typeValues); |
250 | } | |
251 | ||
252 | /** | |
253 | * Returns a new <code>TypedSortedMap</code> with the <code>wrapMap</code> argument wrapped. | |
254 | * | |
255 | * @param wrapMap the target map to be wrapped by the <code>TypedSortedMap</code>. | |
256 | * @param typeKeys the type of the keys allowed by the returned <code>TypedSortedMap</code>. | |
257 | * @param typeValues the type of the values allowed by the returned <code>TypedSortedMap</code>. | |
258 | * @throws ArgumentError if the <code>wrapMap</code> argument is <code>null</code>. | |
259 | * @throws ArgumentError if the <code>typeKeys</code> argument is <code>null</code>. | |
260 | * @throws ArgumentError if the <code>typeValues</code> argument is <code>null</code>. | |
261 | * @throws org.as3coreaddendum.errors.ClassCastError if the types of one or more keys or values in the <code>wrapMap</code> argument are incompatible with the <code>typeKeys</code> or <code>typeValues</code> argument. | |
262 | * @return a new <code>TypedSortedMap</code> with the <code>wrapMap</code> argument wrapped. | |
263 | */ | |
264 | public static function getTypedSortedMap(wrapMap:ISortedMap, typeKeys:*, typeValues:*): TypedSortedMap | |
265 | { | |
266 | 1 | return new TypedSortedMap(wrapMap, typeKeys, typeValues); |
267 | } | |
268 | ||
269 | /** | |
270 | * Returns the string representation of the <code>map</code> argument. | |
271 | * | |
272 | * @param map the target map. | |
273 | * @return the string representation of the target map. | |
274 | */ | |
275 | public static function toString(map:IMap): String | |
276 | { | |
277 | 1 | var s:String = "["; |
278 | 1 | var it:IIterator = map.iterator(); |
279 | var value :*; | |
280 | ||
281 | 1 | while (it.hasNext()) |
282 | { | |
283 | 1 | value = it.next(); |
284 | ||
285 | 1 | s += it.pointer() + "=" + value; |
286 | 1 | if (it.hasNext()) s += ","; |
287 | } | |
288 | ||
289 | 1 | s += "]"; |
290 | ||
291 | 1 | return s; |
292 | } | |
293 | ||
294 | } | |
295 | ||
296 | } |