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

Unified Diff: pkg/json_rpc_2/lib/src/parameters.dart

Issue 205533005: Create a package that implements a JSON-RPC 2.0 server. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 months 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 side-by-side diff with in-line comments
Download patch
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";
+}

Powered by Google App Engine
This is Rietveld 408576698