Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: pkg/json_rpc_2/lib/src/parameters.dart

Issue 812253002: Delete a bunch of packages that are now on GitHub. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Un-delete http Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/json_rpc_2/lib/src/exception.dart ('k') | pkg/json_rpc_2/lib/src/peer.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
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.
4
5 library json_rpc_2.parameters;
6
7 import 'dart:convert';
8
9 import 'exception.dart';
10
11 /// A wrapper for the parameters to a server method.
12 ///
13 /// JSON-RPC 2.0 allows parameters that are either a list or a map. This class
14 /// provides functions that not only assert that the parameters object is the
15 /// correct type, but also that the expected arguments exist and are themselves
16 /// the correct type.
17 ///
18 /// Example usage:
19 ///
20 /// server.registerMethod("subtract", (params) {
21 /// return params["minuend"].asNum - params["subtrahend"].asNum;
22 /// });
23 class Parameters {
24 /// The name of the method that this request called.
25 final String method;
26
27 /// The underlying value of the parameters object.
28 ///
29 /// If this is accessed for a [Parameter] that was not passed, the request
30 /// will be automatically rejected. To avoid this, use [Parameter.valueOr].
31 final value;
32
33 Parameters(this.method, this.value);
34
35 /// Returns a single parameter.
36 ///
37 /// If [key] is a [String], the request is expected to provide named
38 /// parameters. If it's an [int], the request is expected to provide
39 /// positional parameters. Requests that don't do so will be rejected
40 /// automatically.
41 ///
42 /// Whether or not the given parameter exists, this returns a [Parameter]
43 /// object. If a parameter's value is accessed through a getter like [value]
44 /// or [Parameter.asNum], the request will be rejected if that parameter
45 /// doesn't exist. On the other hand, if it's accessed through a method with a
46 /// default value like [Parameter.valueOr] or [Parameter.asNumOr], the default
47 /// value will be returned.
48 Parameter operator [](key) {
49 if (key is int) {
50 _assertPositional();
51 if (key < value.length) {
52 return new Parameter._(method, value[key], this, key);
53 } else {
54 return new _MissingParameter(method, this, key);
55 }
56 } else if (key is String) {
57 _assertNamed();
58 if (value.containsKey(key)) {
59 return new Parameter._(method, value[key], this, key);
60 } else {
61 return new _MissingParameter(method, this, key);
62 }
63 } else {
64 throw new ArgumentError('Parameters[] only takes an int or a string, was '
65 '"$key".');
66 }
67 }
68
69 /// Asserts that [value] exists and is a [List] and returns it.
70 List get asList {
71 _assertPositional();
72 return value;
73 }
74
75 /// Asserts that [value] exists and is a [Map] and returns it.
76 Map get asMap {
77 _assertNamed();
78 return value;
79 }
80
81 /// Asserts that [value] is a positional argument list.
82 void _assertPositional() {
83 if (value is List) return;
84 throw new RpcException.invalidParams('Parameters for method "$method" '
85 'must be passed by position.');
86 }
87
88 /// Asserts that [value] is a named argument map.
89 void _assertNamed() {
90 if (value is Map) return;
91 throw new RpcException.invalidParams('Parameters for method "$method" '
92 'must be passed by name.');
93 }
94 }
95
96 /// A wrapper for a single parameter to a server method.
97 ///
98 /// This provides numerous functions for asserting the type of the parameter in
99 /// question. These functions each have a version that asserts that the
100 /// parameter exists (for example, [asNum] and [asString]) and a version that
101 /// returns a default value if the parameter doesn't exist (for example,
102 /// [asNumOr] and [asStringOr]). If an assertion fails, the request is
103 /// automatically rejected.
104 ///
105 /// This extends [Parameters] to make it easy to access nested parameters. For
106 /// example:
107 ///
108 /// // "params.value" is "{'scores': {'home': [5, 10, 17]}}"
109 /// params['scores']['home'][2].asInt // => 17
110 class Parameter extends Parameters {
111 // The parent parameters, used to construct [_path].
112 final Parameters _parent;
113
114 /// The key used to access [this], used to construct [_path].
115 final _key;
116
117 /// A human-readable representation of the path of getters used to get this.
118 ///
119 /// Named parameters are represented as `.name`, whereas positional parameters
120 /// are represented as `[index]`. For example: `"foo[0].bar.baz"`. Named
121 /// parameters that contain characters that are neither alphanumeric,
122 /// underscores, or hyphens will be JSON-encoded. For example: `"foo
123 /// bar"."baz.bang"`. If quotes are used for an individual component, they
124 /// won't be used for the entire string.
125 ///
126 /// An exception is made for single-level parameters. A single-level
127 /// positional parameter is just represented by the index plus one, because
128 /// "parameter 1" is clearer than "parameter [0]". A single-level named
129 /// parameter is represented by that name in quotes.
130 String get _path {
131 if (_parent is! Parameter) {
132 return _key is int ? (_key + 1).toString() : JSON.encode(_key);
133 }
134
135 quoteKey(key) {
136 if (key.contains(new RegExp(r'[^a-zA-Z0-9_-]'))) return JSON.encode(key);
137 return key;
138 }
139
140 computePath(params) {
141 if (params._parent is! Parameter) {
142 return params._key is int ? "[${params._key}]" : quoteKey(params._key);
143 }
144
145 var path = computePath(params._parent);
146 return params._key is int ?
147 "$path[${params._key}]" : "$path.${quoteKey(params._key)}";
148 }
149
150 return computePath(this);
151 }
152
153 /// Whether this parameter exists.
154 final exists = true;
155
156 Parameter._(String method, value, this._parent, this._key)
157 : super(method, value);
158
159 /// Returns [value], or [defaultValue] if this parameter wasn't passed.
160 valueOr(defaultValue) => value;
161
162 /// Asserts that [value] exists and is a number and returns it.
163 ///
164 /// [asNumOr] may be used to provide a default value instead of rejecting the
165 /// request if [value] doesn't exist.
166 num get asNum => _getTyped('a number', (value) => value is num);
167
168 /// Asserts that [value] is a number and returns it.
169 ///
170 /// If [value] doesn't exist, this returns [defaultValue].
171 num asNumOr(num defaultValue) => asNum;
172
173 /// Asserts that [value] exists and is an integer and returns it.
174 ///
175 /// [asIntOr] may be used to provide a default value instead of rejecting the
176 /// request if [value] doesn't exist.
177 ///
178 /// Note that which values count as integers varies between the Dart VM and
179 /// dart2js. The value `1.0` will be considered an integer under dart2js but
180 /// not under the VM.
181 int get asInt => _getTyped('an integer', (value) => value is int);
182
183 /// Asserts that [value] is an integer and returns it.
184 ///
185 /// If [value] doesn't exist, this returns [defaultValue].
186 ///
187 /// Note that which values count as integers varies between the Dart VM and
188 /// dart2js. The value `1.0` will be considered an integer under dart2js but
189 /// not under the VM.
190 int asIntOr(int defaultValue) => asInt;
191
192 /// Asserts that [value] exists and is a boolean and returns it.
193 ///
194 /// [asBoolOr] may be used to provide a default value instead of rejecting the
195 /// request if [value] doesn't exist.
196 bool get asBool => _getTyped('a boolean', (value) => value is bool);
197
198 /// Asserts that [value] is a boolean and returns it.
199 ///
200 /// If [value] doesn't exist, this returns [defaultValue].
201 bool asBoolOr(bool defaultValue) => asBool;
202
203 /// Asserts that [value] exists and is a string and returns it.
204 ///
205 /// [asStringOr] may be used to provide a default value instead of rejecting
206 /// the request if [value] doesn't exist.
207 String get asString => _getTyped('a string', (value) => value is String);
208
209 /// Asserts that [value] is a string and returns it.
210 ///
211 /// If [value] doesn't exist, this returns [defaultValue].
212 String asStringOr(String defaultValue) => asString;
213
214 /// Asserts that [value] exists and is a [List] and returns it.
215 ///
216 /// [asListOr] may be used to provide a default value instead of rejecting the
217 /// request if [value] doesn't exist.
218 List get asList => _getTyped('an Array', (value) => value is List);
219
220 /// Asserts that [value] is a [List] and returns it.
221 ///
222 /// If [value] doesn't exist, this returns [defaultValue].
223 List asListOr(List defaultValue) => asList;
224
225 /// Asserts that [value] exists and is a [Map] and returns it.
226 ///
227 /// [asMapOr] may be used to provide a default value instead of rejecting the
228 /// request if [value] doesn't exist.
229 Map get asMap => _getTyped('an Object', (value) => value is Map);
230
231 /// Asserts that [value] is a [Map] and returns it.
232 ///
233 /// If [value] doesn't exist, this returns [defaultValue].
234 Map asMapOr(Map defaultValue) => asMap;
235
236 /// Asserts that [value] exists, is a string, and can be parsed as a
237 /// [DateTime] and returns it.
238 ///
239 /// [asDateTimeOr] may be used to provide a default value instead of rejecting
240 /// the request if [value] doesn't exist.
241 DateTime get asDateTime => _getParsed('date/time', DateTime.parse);
242
243 /// Asserts that [value] exists, is a string, and can be parsed as a
244 /// [DateTime] and returns it.
245 ///
246 /// If [value] doesn't exist, this returns [defaultValue].
247 DateTime asDateTimeOr(DateTime defaultValue) => asDateTime;
248
249 /// Asserts that [value] exists, is a string, and can be parsed as a
250 /// [Uri] and returns it.
251 ///
252 /// [asUriOr] may be used to provide a default value instead of rejecting the
253 /// request if [value] doesn't exist.
254 Uri get asUri => _getParsed('URI', Uri.parse);
255
256 /// Asserts that [value] exists, is a string, and can be parsed as a
257 /// [Uri] and returns it.
258 ///
259 /// If [value] doesn't exist, this returns [defaultValue].
260 Uri asUriOr(Uri defaultValue) => asUri;
261
262 /// Get a parameter named [named] that matches [test], or the value of calling
263 /// [orElse].
264 ///
265 /// [type] is used for the error message. It should begin with an indefinite
266 /// article.
267 _getTyped(String type, bool test(value)) {
268 if (test(value)) return value;
269 throw new RpcException.invalidParams('Parameter $_path for method '
270 '"$method" must be $type, but was ${JSON.encode(value)}.');
271 }
272
273 _getParsed(String description, parse(String value)) {
274 var string = asString;
275 try {
276 return parse(string);
277 } on FormatException catch (error) {
278 // DateTime.parse doesn't actually include any useful information in the
279 // FormatException, just the string that was being parsed. There's no use
280 // in including that in the RPC exception. See issue 17753.
281 var message = error.message;
282 if (message == string) {
283 message = '';
284 } else {
285 message = '\n$message';
286 }
287
288 throw new RpcException.invalidParams('Parameter $_path for method '
289 '"$method" must be a valid $description, but was '
290 '${JSON.encode(string)}.$message');
291 }
292 }
293
294 void _assertPositional() {
295 // Throw the standard exception for a mis-typed list.
296 asList;
297 }
298
299 void _assertNamed() {
300 // Throw the standard exception for a mis-typed map.
301 asMap;
302 }
303 }
304
305 /// A subclass of [Parameter] representing a missing parameter.
306 class _MissingParameter extends Parameter {
307 get value {
308 throw new RpcException.invalidParams('Request for method "$method" is '
309 'missing required parameter $_path.');
310 }
311
312 final exists = false;
313
314 _MissingParameter(String method, Parameters parent, key)
315 : super._(method, null, parent, key);
316
317 valueOr(defaultValue) => defaultValue;
318
319 num asNumOr(num defaultValue) => defaultValue;
320
321 int asIntOr(int defaultValue) => defaultValue;
322
323 bool asBoolOr(bool defaultValue) => defaultValue;
324
325 String asStringOr(String defaultValue) => defaultValue;
326
327 List asListOr(List defaultValue) => defaultValue;
328
329 Map asMapOr(Map defaultValue) => defaultValue;
330
331 DateTime asDateTimeOr(DateTime defaultValue) => defaultValue;
332
333 Uri asUriOr(Uri defaultValue) => defaultValue;
334 }
OLDNEW
« no previous file with comments | « pkg/json_rpc_2/lib/src/exception.dart ('k') | pkg/json_rpc_2/lib/src/peer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698