OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// Generic utility functions. Stuff that should possibly be in core. | 5 /// Generic utility functions. Stuff that should possibly be in core. |
6 library utils; | 6 library utils; |
7 | 7 |
| 8 import 'dart:async'; |
8 import 'dart:crypto'; | 9 import 'dart:crypto'; |
9 import 'dart:isolate'; | 10 import 'dart:isolate'; |
10 import 'dart:uri'; | 11 import 'dart:uri'; |
11 | 12 |
12 /// A pair of values. | 13 /// A pair of values. |
13 class Pair<E, F> { | 14 class Pair<E, F> { |
14 E first; | 15 E first; |
15 F last; | 16 F last; |
16 | 17 |
17 Pair(this.first, this.last); | 18 Pair(this.first, this.last); |
(...skipping 17 matching lines...) Expand all Loading... |
35 while (result.length < length) { | 36 while (result.length < length) { |
36 result.add(' '); | 37 result.add(' '); |
37 } | 38 } |
38 | 39 |
39 return result.toString(); | 40 return result.toString(); |
40 } | 41 } |
41 | 42 |
42 /// Runs [fn] after [future] completes, whether it completes successfully or | 43 /// Runs [fn] after [future] completes, whether it completes successfully or |
43 /// not. Essentially an asynchronous `finally` block. | 44 /// not. Essentially an asynchronous `finally` block. |
44 always(Future future, fn()) { | 45 always(Future future, fn()) { |
45 var completer = new Completer(); | 46 future.catchError((_) {}).then((_) => fn()); |
46 future.then((_) => fn()); | |
47 future.handleException((_) { | |
48 fn(); | |
49 return false; | |
50 }); | |
51 } | 47 } |
52 | 48 |
53 /// Flattens nested collections into a single list containing only non-list | 49 /// Flattens nested lists inside an iterable into a single list containing only |
54 /// elements. | 50 /// non-list elements. |
55 List flatten(Collection nested) { | 51 List flatten(Iterable nested) { |
56 var result = []; | 52 var result = []; |
57 helper(list) { | 53 helper(list) { |
58 for (var element in list) { | 54 for (var element in list) { |
59 if (element is List) { | 55 if (element is List) { |
60 helper(element); | 56 helper(element); |
61 } else { | 57 } else { |
62 result.add(element); | 58 result.add(element); |
63 } | 59 } |
64 } | 60 } |
65 } | 61 } |
66 helper(nested); | 62 helper(nested); |
67 return result; | 63 return result; |
68 } | 64 } |
69 | 65 |
70 /// Asserts that [iter] contains only one element, and returns it. | 66 /// Asserts that [iter] contains only one element, and returns it. |
71 only(Iterable iter) { | 67 only(Iterable iter) { |
72 var iterator = iter.iterator(); | 68 var iterator = iter.iterator; |
73 assert(iterator.hasNext); | 69 var currentIsValid = iterator.moveNext(); |
74 var obj = iterator.next(); | 70 assert(currentIsValid); |
75 assert(!iterator.hasNext); | 71 var obj = iterator.current; |
| 72 assert(!iterator.moveNext()); |
76 return obj; | 73 return obj; |
77 } | 74 } |
78 | 75 |
79 /// Returns a set containing all elements in [minuend] that are not in | 76 /// Returns a set containing all elements in [minuend] that are not in |
80 /// [subtrahend]. | 77 /// [subtrahend]. |
81 Set setMinus(Collection minuend, Collection subtrahend) { | 78 Set setMinus(Collection minuend, Collection subtrahend) { |
82 var minuendSet = new Set.from(minuend); | 79 var minuendSet = new Set.from(minuend); |
83 minuendSet.removeAll(subtrahend); | 80 minuendSet.removeAll(subtrahend); |
84 return minuendSet; | 81 return minuendSet; |
85 } | 82 } |
(...skipping 15 matching lines...) Expand all Loading... |
101 /// Returns whether or not [str] ends with [matcher]. | 98 /// Returns whether or not [str] ends with [matcher]. |
102 bool endsWithPattern(String str, Pattern matcher) { | 99 bool endsWithPattern(String str, Pattern matcher) { |
103 for (var match in matcher.allMatches(str)) { | 100 for (var match in matcher.allMatches(str)) { |
104 if (match.end == str.length) return true; | 101 if (match.end == str.length) return true; |
105 } | 102 } |
106 return false; | 103 return false; |
107 } | 104 } |
108 | 105 |
109 /// Returns the hex-encoded sha1 hash of [source]. | 106 /// Returns the hex-encoded sha1 hash of [source]. |
110 String sha1(String source) => | 107 String sha1(String source) => |
111 CryptoUtils.bytesToHex(new SHA1().update(source.charCodes).digest()); | 108 CryptoUtils.bytesToHex(new SHA1().add(source.charCodes).close()); |
112 | 109 |
113 /// Returns a [Future] that completes in [milliseconds]. | 110 /// Returns a [Future] that completes in [milliseconds]. |
114 Future sleep(int milliseconds) { | 111 Future sleep(int milliseconds) { |
115 var completer = new Completer(); | 112 var completer = new Completer(); |
116 new Timer(milliseconds, completer.complete); | 113 new Timer(milliseconds, completer.complete); |
117 return completer.future; | 114 return completer.future; |
118 } | 115 } |
119 | 116 |
120 /// Configures [future] so that its result (success or exception) is passed on | 117 /// Configures [future] so that its result (success or exception) is passed on |
121 /// to [completer]. | 118 /// to [completer]. |
122 void chainToCompleter(Future future, Completer completer) { | 119 void chainToCompleter(Future future, Completer completer) { |
123 future.handleException((e) { | 120 future |
124 completer.completeException(e, future.stackTrace); | 121 .then(completer.complete) |
125 return true; | 122 .catchError((e) { |
126 }); | 123 completer.completeError(e.error, e.stackTrace); |
127 future.then(completer.complete); | 124 }); |
128 } | 125 } |
129 | 126 |
130 // TODO(nweiz): unify the following functions with the utility functions in | 127 // TODO(nweiz): unify the following functions with the utility functions in |
131 // pkg/http. | 128 // pkg/http. |
132 | 129 |
133 /// Like [String.split], but only splits on the first occurrence of the pattern. | 130 /// Like [String.split], but only splits on the first occurrence of the pattern. |
134 /// This will always return an array of two elements or fewer. | 131 /// This will always return an array of two elements or fewer. |
135 List<String> split1(String toSplit, String pattern) { | 132 List<String> split1(String toSplit, String pattern) { |
136 if (toSplit.isEmpty) return <String>[]; | 133 if (toSplit.isEmpty) return <String>[]; |
137 | 134 |
(...skipping 26 matching lines...) Expand all Loading... |
164 } | 161 } |
165 | 162 |
166 /// Convert a [Map] from parameter names to values to a URL query string. | 163 /// Convert a [Map] from parameter names to values to a URL query string. |
167 String mapToQuery(Map<String, String> map) { | 164 String mapToQuery(Map<String, String> map) { |
168 var pairs = <List<String>>[]; | 165 var pairs = <List<String>>[]; |
169 map.forEach((key, value) { | 166 map.forEach((key, value) { |
170 key = encodeUriComponent(key); | 167 key = encodeUriComponent(key); |
171 value = (value == null || value.isEmpty) ? null : encodeUriComponent(value); | 168 value = (value == null || value.isEmpty) ? null : encodeUriComponent(value); |
172 pairs.add([key, value]); | 169 pairs.add([key, value]); |
173 }); | 170 }); |
174 return Strings.join(pairs.map((pair) { | 171 return Strings.join(pairs.mappedBy((pair) { |
175 if (pair[1] == null) return pair[0]; | 172 if (pair[1] == null) return pair[0]; |
176 return "${pair[0]}=${pair[1]}"; | 173 return "${pair[0]}=${pair[1]}"; |
177 }), "&"); | 174 }), "&"); |
178 } | 175 } |
179 | 176 |
180 /// Add all key/value pairs from [source] to [destination], overwriting any | 177 /// Add all key/value pairs from [source] to [destination], overwriting any |
181 /// pre-existing values. | 178 /// pre-existing values. |
182 void mapAddAll(Map destination, Map source) => | 179 void mapAddAll(Map destination, Map source) => |
183 source.forEach((key, value) => destination[key] = value); | 180 source.forEach((key, value) => destination[key] = value); |
184 | 181 |
185 /// Decodes a URL-encoded string. Unlike [decodeUriComponent], this includes | 182 /// Decodes a URL-encoded string. Unlike [decodeUriComponent], this includes |
186 /// replacing `+` with ` `. | 183 /// replacing `+` with ` `. |
187 String urlDecode(String encoded) => | 184 String urlDecode(String encoded) => |
188 decodeUriComponent(encoded.replaceAll("+", " ")); | 185 decodeUriComponent(encoded.replaceAll("+", " ")); |
OLD | NEW |