Chromium Code Reviews| 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 |