OLD | NEW |
---|---|
(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:math' as math; | |
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 class Parameters { | |
18 /// The name of the method that this request called. | |
19 final String method; | |
20 | |
21 /// The underlying value of the parameters. | |
Bob Nystrom
2014/03/20 18:25:58
"parameters" -> "parameters object"
nweiz
2014/03/20 22:55:41
Done.
| |
22 final value; | |
23 | |
24 /// The path to this parameters map, or null if this is the top-level | |
25 /// parameters map. | |
Bob Nystrom
2014/03/20 18:25:58
How about a bit explaining how this is formatted?
nweiz
2014/03/20 22:55:41
Done.
| |
26 final String _prefix; | |
27 | |
28 /// Returns the length of the positional parameters array. | |
29 /// | |
30 /// If the request passed named parameters rather than positional parameters, | |
31 /// this will reject the request. | |
32 int get length { | |
33 _assertPositional(); | |
34 return value.length; | |
35 } | |
36 | |
37 Parameters(this.method, this.value, [this._prefix]); | |
38 | |
39 /// Returns the parameter named [name]. | |
40 /// | |
41 /// If there is no parameter named [name] and [orElse] was passed, this will | |
42 /// call [orElse] and return its result. If [orElse] was not passed, this will | |
43 /// reject the request. | |
44 /// | |
45 /// If the request passed positional parameters rather than named parameters, | |
46 /// this will reject the request. | |
47 getNamed(String name, {orElse()}) { | |
48 _assertNamed(); | |
49 if (value.containsKey(name)) return value[name]; | |
50 if (orElse != null) return orElse(); | |
51 throw new RpcException.invalidParams('Request for method "$method" is ' | |
52 'missing required parameter "${_prefixName(name)}".'); | |
53 } | |
54 | |
55 /// Returns the numeric parameter named [name]. | |
56 /// | |
57 /// If there is no parameter named [name] and [orElse] was passed, this will | |
58 /// call [orElse] and return its result. If [orElse] was not passed, this will | |
59 /// reject the request. | |
60 /// | |
61 /// If the parameter named [name] is not a number or if the request passed | |
62 /// positional parameters rather than named parameters, this will reject the | |
63 /// request. | |
64 num getNum(String name, {num orElse()}) => | |
65 _getTyped(name, 'a number', (value) => value is num, orElse); | |
66 | |
67 /// Returns the integer parameter named [name]. | |
68 /// | |
69 /// If there is no parameter named [name] and [orElse] was passed, this will | |
70 /// call [orElse] and return its result. If [orElse] was not passed, this will | |
71 /// reject the request. | |
72 /// | |
73 /// If the parameter named [name] is not an integer or if the request passed | |
74 /// positional parameters rather than named parameters, this will reject the | |
75 /// request. | |
76 int getInt(String name, {int orElse()}) => | |
77 _getTyped(name, 'an integer', (value) => value is int, orElse); | |
Bob Nystrom
2014/03/20 18:25:58
This will do weird things in dart2js. If the value
nweiz
2014/03/20 22:55:41
I thought about only having [getNum], but I think
| |
78 | |
79 /// Returns the boolean parameter named [name]. | |
80 /// | |
81 /// If there is no parameter named [name] and [orElse] was passed, this will | |
82 /// call [orElse] and return its result. If [orElse] was not passed, this will | |
83 /// reject the request. | |
84 /// | |
85 /// If the parameter named [name] is not a boolean or if the request passed | |
86 /// positional parameters rather than named parameters, this will reject the | |
87 /// request. | |
88 bool getBool(String name, {bool orElse()}) => | |
89 _getTyped(name, 'a boolean', (value) => value is bool, orElse); | |
90 | |
91 /// Returns the string parameter named [name]. | |
92 /// | |
93 /// If there is no parameter named [name] and [orElse] was passed, this will | |
94 /// call [orElse] and return its result. If [orElse] was not passed, this will | |
95 /// reject the request. | |
96 /// | |
97 /// If the parameter named [name] is not a string or if the request passed | |
98 /// positional parameters rather than named parameters, this will reject the | |
99 /// request. | |
100 String getString(String name, {String orElse()}) => | |
101 _getTyped(name, 'a string', (value) => value is String, orElse); | |
102 | |
103 /// Returns the list parameter named [name]. | |
104 /// | |
105 /// If there is no parameter named [name] and [orElse] was passed, this will | |
106 /// call [orElse] and return its result. If [orElse] was not passed, this will | |
107 /// reject the request. | |
108 /// | |
109 /// It's safe to modify the returned list. | |
Bob Nystrom
2014/03/20 18:25:58
If we claim to support this, we're stuck with the
nweiz
2014/03/20 22:55:41
Thinking this over more I think it's probably bett
Bob Nystrom
2014/03/21 00:36:02
SGTM.
| |
110 /// | |
111 /// If the parameter named [name] is not a list or if the request passed | |
112 /// positional parameters rather than named parameters, this will reject the | |
113 /// request. | |
114 List getList(String name, {List orElse()}) => | |
115 _getTyped(name, 'an Array', (value) => value is List, orElse).toList(); | |
116 | |
117 /// Returns the map parameter named [name]. | |
118 /// | |
119 /// If there is no parameter named [name] and [orElse] was passed, this will | |
120 /// call [orElse] and return its result. If [orElse] was not passed, this will | |
121 /// reject the request. | |
122 /// | |
123 /// It's safe to modify the returned map. | |
Bob Nystrom
2014/03/20 18:25:58
Ditto.
nweiz
2014/03/20 22:55:41
See above.
| |
124 /// | |
125 /// If the parameter named [name] is not a map or if the request passed | |
126 /// positional parameters rather than named parameters, this will reject the | |
127 /// request. | |
128 Map getMap(String name, {Map orElse()}) { | |
129 var result = _getTyped(name, 'an Object', (value) => value is Map, orElse); | |
130 return new Map.from(result); | |
131 } | |
132 | |
133 /// Returns a view of the map parameter named [name] as a [Parameters] object. | |
134 /// | |
135 /// This can be useful if the request parameters contains nested objects whose | |
136 /// structure needs to be validated. | |
137 /// | |
138 /// If there is no parameter named [name], if the parameter named [name] is | |
139 /// not a map, or if the request passed positional parameters rather than | |
Bob Nystrom
2014/03/20 18:25:58
Why can't the nested parameter be a list?
nweiz
2014/03/20 22:55:41
N/A
| |
140 /// named parameters, this will reject the request. | |
141 Parameters getNested(String name) { | |
142 var map = getMap(name, orElse: () => {}); | |
143 var nested = new Parameters(method, map, _prefixName(name)); | |
144 return nested; | |
145 } | |
146 | |
147 /// Returns [index]th positional parameter array. | |
Bob Nystrom
2014/03/20 18:25:58
This is confusingly written. How about: "Returns t
nweiz
2014/03/20 22:55:41
N/A
| |
148 /// | |
149 /// If the request passed named parameters rather than positional parameters, | |
150 /// or if there aren't enough positional parameters to return the [index]th, | |
Bob Nystrom
2014/03/20 18:25:58
"indexth" -> "indexth one".
nweiz
2014/03/20 22:55:41
N/A
| |
151 /// this will reject the request. | |
152 getPositional(int index) { | |
153 _assertPositional(); | |
154 if (index < value.length) return value[index]; | |
155 throw new RpcException.invalidParams('Method "$method" requires at least ' | |
156 '${index + 1} arguments.'); | |
157 } | |
158 | |
159 /// Get a parameter named [named] that matches [test], or the value of calling | |
160 /// [orElse]. | |
161 /// | |
162 /// [type] is used for the error message. It should begin with an indefinite | |
163 /// article. | |
164 _getTyped(String name, String type, bool test(value), orElse()) { | |
165 var result = getNamed(name, orElse: orElse); | |
166 if (!value.containsKey(name)) return result; | |
167 if (test(value[name])) return value[name]; | |
168 | |
169 throw new RpcException.invalidParams('Parameter "${_prefixName(name)}" ' | |
170 'for method "$method" must be $type, but was "${value[name]}".'); | |
171 } | |
172 | |
173 /// Asserts that [value] is a positional argument list. | |
174 void _assertPositional() { | |
175 if (value is List) return; | |
176 throw new RpcException.invalidParams('Parameters for method "$method" ' | |
177 'must be passed by position.'); | |
Bob Nystrom
2014/03/20 18:25:58
Handle nesting in the error message, here and belo
nweiz
2014/03/20 22:55:41
Done.
| |
178 } | |
179 | |
180 /// Asserts that [value] is a named argument map. | |
181 void _assertNamed() { | |
182 if (value is Map) return; | |
183 throw new RpcException.invalidParams('Parameters for method "$method" ' | |
184 'must be passed by name.'); | |
185 } | |
186 | |
187 /// Returns [name] with [_prefix] attached. | |
188 String _prefixName(String name) => _prefix == null ? name : "$_prefix.$name"; | |
189 } | |
OLD | NEW |