Chromium Code Reviews| Index: pkg/json_rpc_2/lib/src/parameters.dart |
| diff --git a/pkg/json_rpc_2/lib/src/parameters.dart b/pkg/json_rpc_2/lib/src/parameters.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..e08ef39236bbdadcd66823d0ab79eae6cf638b79 |
| --- /dev/null |
| +++ b/pkg/json_rpc_2/lib/src/parameters.dart |
| @@ -0,0 +1,189 @@ |
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +library json_rpc_2.parameters; |
| + |
| +import 'dart:math' as math; |
| + |
| +import 'exception.dart'; |
| + |
| +/// A wrapper for the parameters to a server method. |
| +/// |
| +/// JSON-RPC 2.0 allows parameters that are either a list or a map. This class |
| +/// provides functions that not only assert that the parameters object is the |
| +/// correct type, but also that the expected arguments exist and are themselves |
| +/// the correct type. |
| +class Parameters { |
| + /// The name of the method that this request called. |
| + final String method; |
| + |
| + /// 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.
|
| + final value; |
| + |
| + /// The path to this parameters map, or null if this is the top-level |
| + /// 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.
|
| + final String _prefix; |
| + |
| + /// Returns the length of the positional parameters array. |
| + /// |
| + /// If the request passed named parameters rather than positional parameters, |
| + /// this will reject the request. |
| + int get length { |
| + _assertPositional(); |
| + return value.length; |
| + } |
| + |
| + Parameters(this.method, this.value, [this._prefix]); |
| + |
| + /// Returns the parameter named [name]. |
| + /// |
| + /// If there is no parameter named [name] and [orElse] was passed, this will |
| + /// call [orElse] and return its result. If [orElse] was not passed, this will |
| + /// reject the request. |
| + /// |
| + /// If the request passed positional parameters rather than named parameters, |
| + /// this will reject the request. |
| + getNamed(String name, {orElse()}) { |
| + _assertNamed(); |
| + if (value.containsKey(name)) return value[name]; |
| + if (orElse != null) return orElse(); |
| + throw new RpcException.invalidParams('Request for method "$method" is ' |
| + 'missing required parameter "${_prefixName(name)}".'); |
| + } |
| + |
| + /// Returns the numeric parameter named [name]. |
| + /// |
| + /// If there is no parameter named [name] and [orElse] was passed, this will |
| + /// call [orElse] and return its result. If [orElse] was not passed, this will |
| + /// reject the request. |
| + /// |
| + /// If the parameter named [name] is not a number or if the request passed |
| + /// positional parameters rather than named parameters, this will reject the |
| + /// request. |
| + num getNum(String name, {num orElse()}) => |
| + _getTyped(name, 'a number', (value) => value is num, orElse); |
| + |
| + /// Returns the integer parameter named [name]. |
| + /// |
| + /// If there is no parameter named [name] and [orElse] was passed, this will |
| + /// call [orElse] and return its result. If [orElse] was not passed, this will |
| + /// reject the request. |
| + /// |
| + /// If the parameter named [name] is not an integer or if the request passed |
| + /// positional parameters rather than named parameters, this will reject the |
| + /// request. |
| + int getInt(String name, {int orElse()}) => |
| + _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
|
| + |
| + /// Returns the boolean parameter named [name]. |
| + /// |
| + /// If there is no parameter named [name] and [orElse] was passed, this will |
| + /// call [orElse] and return its result. If [orElse] was not passed, this will |
| + /// reject the request. |
| + /// |
| + /// If the parameter named [name] is not a boolean or if the request passed |
| + /// positional parameters rather than named parameters, this will reject the |
| + /// request. |
| + bool getBool(String name, {bool orElse()}) => |
| + _getTyped(name, 'a boolean', (value) => value is bool, orElse); |
| + |
| + /// Returns the string parameter named [name]. |
| + /// |
| + /// If there is no parameter named [name] and [orElse] was passed, this will |
| + /// call [orElse] and return its result. If [orElse] was not passed, this will |
| + /// reject the request. |
| + /// |
| + /// If the parameter named [name] is not a string or if the request passed |
| + /// positional parameters rather than named parameters, this will reject the |
| + /// request. |
| + String getString(String name, {String orElse()}) => |
| + _getTyped(name, 'a string', (value) => value is String, orElse); |
| + |
| + /// Returns the list parameter named [name]. |
| + /// |
| + /// If there is no parameter named [name] and [orElse] was passed, this will |
| + /// call [orElse] and return its result. If [orElse] was not passed, this will |
| + /// reject the request. |
| + /// |
| + /// 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.
|
| + /// |
| + /// If the parameter named [name] is not a list or if the request passed |
| + /// positional parameters rather than named parameters, this will reject the |
| + /// request. |
| + List getList(String name, {List orElse()}) => |
| + _getTyped(name, 'an Array', (value) => value is List, orElse).toList(); |
| + |
| + /// Returns the map parameter named [name]. |
| + /// |
| + /// If there is no parameter named [name] and [orElse] was passed, this will |
| + /// call [orElse] and return its result. If [orElse] was not passed, this will |
| + /// reject the request. |
| + /// |
| + /// 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.
|
| + /// |
| + /// If the parameter named [name] is not a map or if the request passed |
| + /// positional parameters rather than named parameters, this will reject the |
| + /// request. |
| + Map getMap(String name, {Map orElse()}) { |
| + var result = _getTyped(name, 'an Object', (value) => value is Map, orElse); |
| + return new Map.from(result); |
| + } |
| + |
| + /// Returns a view of the map parameter named [name] as a [Parameters] object. |
| + /// |
| + /// This can be useful if the request parameters contains nested objects whose |
| + /// structure needs to be validated. |
| + /// |
| + /// If there is no parameter named [name], if the parameter named [name] is |
| + /// 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
|
| + /// named parameters, this will reject the request. |
| + Parameters getNested(String name) { |
| + var map = getMap(name, orElse: () => {}); |
| + var nested = new Parameters(method, map, _prefixName(name)); |
| + return nested; |
| + } |
| + |
| + /// 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
|
| + /// |
| + /// If the request passed named parameters rather than positional parameters, |
| + /// 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
|
| + /// this will reject the request. |
| + getPositional(int index) { |
| + _assertPositional(); |
| + if (index < value.length) return value[index]; |
| + throw new RpcException.invalidParams('Method "$method" requires at least ' |
| + '${index + 1} arguments.'); |
| + } |
| + |
| + /// Get a parameter named [named] that matches [test], or the value of calling |
| + /// [orElse]. |
| + /// |
| + /// [type] is used for the error message. It should begin with an indefinite |
| + /// article. |
| + _getTyped(String name, String type, bool test(value), orElse()) { |
| + var result = getNamed(name, orElse: orElse); |
| + if (!value.containsKey(name)) return result; |
| + if (test(value[name])) return value[name]; |
| + |
| + throw new RpcException.invalidParams('Parameter "${_prefixName(name)}" ' |
| + 'for method "$method" must be $type, but was "${value[name]}".'); |
| + } |
| + |
| + /// Asserts that [value] is a positional argument list. |
| + void _assertPositional() { |
| + if (value is List) return; |
| + throw new RpcException.invalidParams('Parameters for method "$method" ' |
| + '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.
|
| + } |
| + |
| + /// Asserts that [value] is a named argument map. |
| + void _assertNamed() { |
| + if (value is Map) return; |
| + throw new RpcException.invalidParams('Parameters for method "$method" ' |
| + 'must be passed by name.'); |
| + } |
| + |
| + /// Returns [name] with [_prefix] attached. |
| + String _prefixName(String name) => _prefix == null ? name : "$_prefix.$name"; |
| +} |