mirror of
https://github.com/OMGeeky/google-apis-rs.git
synced 2026-01-02 09:31:13 +01:00
docs(mbuild): method builder call example
With nearly fully randomized examples to show how it can be done. It's quite nice to see actual calls, using everything required to get a call. The only thing the user has to manage is to fill in actual values. But, it also shows that our builder pattern doesn't work yet due to ... you guessed it ... lifetime issues :D
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,26 @@ use std::default::Default;
|
||||
|
||||
pub use cmn::{Hub, ResourceMethodsBuilder, MethodBuilder, Resource, Part, ResponseResult, RequestValue, NestedType};
|
||||
|
||||
|
||||
// ##############
|
||||
// UTILITIES ###
|
||||
// ############
|
||||
|
||||
/// This macro is advertised in the documentation, which is why we deliver it as well
|
||||
#[macro_export]
|
||||
macro_rules! map(
|
||||
{ $($key:expr => $value:expr),+ } => {
|
||||
{
|
||||
let mut m = ::std::collections::HashMap::new();
|
||||
$(
|
||||
m.insert($key, $value);
|
||||
)+
|
||||
m
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
|
||||
// ########
|
||||
// HUB ###
|
||||
// ######
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<%!
|
||||
from util import (put_and, rust_test_fn_invisible, rust_doc_test_norun, rust_doc_comment,
|
||||
from util import (put_and, rust_test_fn_invisible, rust_doc_test_norun, rust_doc_comment,
|
||||
rb_type, mb_type, singular, hub_type, to_fqan, indent_all_but_first_by,
|
||||
method_params, activity_rust_type, mangle_ident, activity_input_type, get_word,
|
||||
split_camelcase_s, property, is_pod_property, TREF, method_io, IO_REQUEST,
|
||||
schema_to_required_property, rust_copy_value_s, is_required_property,
|
||||
hide_rust_doc_test, build_all_params, REQUEST_VALUE_PROPERTY_NAME)
|
||||
hide_rust_doc_test, build_all_params, REQUEST_VALUE_PROPERTY_NAME, organize_params,
|
||||
indent_by, to_rust_type, rnd_arg_val_for_type)
|
||||
%>\
|
||||
<%namespace name="util" file="util.mako"/>\
|
||||
<%namespace name="lib" file="lib.mako"/>\
|
||||
@@ -14,12 +15,29 @@
|
||||
###############################################################################################
|
||||
<%def name="new(resource, method, c)">\
|
||||
<%
|
||||
hub_type_name = hub_type(canonicalName)
|
||||
m = c.fqan_map[to_fqan(name, resource, method)]
|
||||
# an identifier for a property. We prefix them to prevent clashes with the setters
|
||||
ThisType = mb_type(resource, method) + "<'a, C, NC, A>"
|
||||
hub_type_name = hub_type(canonicalName)
|
||||
m = c.fqan_map[to_fqan(name, resource, method)]
|
||||
# an identifier for a property. We prefix them to prevent clashes with the setters
|
||||
ThisType = mb_type(resource, method) + "<'a, C, NC, A>"
|
||||
|
||||
params, request_value = build_all_params(schemas, c, m, IO_REQUEST, REQUEST_VALUE_PROPERTY_NAME)
|
||||
params, request_value = build_all_params(schemas, c, m, IO_REQUEST, REQUEST_VALUE_PROPERTY_NAME)
|
||||
required_props, optional_props, part_prop = organize_params(params, request_value)
|
||||
|
||||
# rvfrt = random value for rust type
|
||||
rvfrt = lambda spn, sp, sn=None: rnd_arg_val_for_type(to_rust_type(sn, spn, sp, allow_optionals=False))
|
||||
rb_name = 'request' # name of request binding
|
||||
required_args = request_value and ['&' + rb_name] or []
|
||||
for p in required_props:
|
||||
# could also just skip the first element, but ... let's be safe
|
||||
if request_value and request_value.id == p.get(TREF):
|
||||
continue
|
||||
v = rvfrt(p.name, p)
|
||||
# we chose to replace random strings with their meaning, as indicated by the name !
|
||||
if v.endswith('"'):
|
||||
v = '"%s"' % p.name
|
||||
required_args.append(v)
|
||||
# end for each required property
|
||||
required_args = ', '.join(required_args)
|
||||
%>\
|
||||
% if 'description' in m:
|
||||
${m.description | rust_doc_comment}
|
||||
@@ -34,17 +52,37 @@ ${m.description | rust_doc_comment}
|
||||
///
|
||||
<%block filter="rust_doc_test_norun, rust_doc_comment">\
|
||||
${capture(util.test_prelude) | hide_rust_doc_test}\
|
||||
|
||||
<%block filter="rust_test_fn_invisible">\
|
||||
${capture(lib.test_hub, hub_type_name, comments=False) | hide_rust_doc_test}
|
||||
// Usually you wouldn't bind this to a variable, but keep calling methods
|
||||
// to setup your call.
|
||||
## % for p
|
||||
// let mb = hub.${resource}().${mangle_ident(method)}(...);
|
||||
% if request_value:
|
||||
// As the method needs a request, you would usually fill it with the desired information.
|
||||
// What can actually be filled in depends on the actual call - the following is just a
|
||||
// random selection of properties ! Values are random and not representative !
|
||||
let mut ${rb_name}: ${request_value.id} = Default::default();
|
||||
% for spn, sp in request_value.get('properties', dict()).iteritems():
|
||||
## ${to_rust_type(request_value.id, spn, sp, allow_optionals=False)}
|
||||
${rb_name}.${mangle_ident(spn)} = ${rvfrt(spn, sp)};
|
||||
% if loop.index == 3:
|
||||
// ... and so forth ...
|
||||
<% break %>
|
||||
% endif
|
||||
% endfor
|
||||
|
||||
% endif
|
||||
// Even though you wouldn't bind this to a variable, you can configure optional parameters
|
||||
// by calling the respective setters.
|
||||
// Values are random and not representative !
|
||||
let mut mb = hub.${resource}().${mangle_ident(method)}(${required_args})\
|
||||
% for p in optional_props:
|
||||
|
||||
<%block filter="indent_by(8)">\
|
||||
.${mangle_ident(p.name)}(${rvfrt(p.name, p)})\
|
||||
</%block>\
|
||||
% endfor
|
||||
;
|
||||
|
||||
// Finally, execute your call and process the result
|
||||
// TODO: comment in once args are properly setup !
|
||||
// mb.do()
|
||||
mb.${api.terms.action}()
|
||||
</%block>
|
||||
</%block>
|
||||
pub struct ${ThisType}
|
||||
@@ -55,10 +93,10 @@ pub struct ${ThisType}
|
||||
hub: &'a ${hub_type_name}<C, NC, A>,
|
||||
## PROPERTIES ###############
|
||||
% for p in params:
|
||||
${property(p.name)}:\
|
||||
% if is_required_property(p):
|
||||
${property(p.name)}:\
|
||||
% if is_required_property(p):
|
||||
${activity_rust_type(p, allow_optionals=False)},
|
||||
% else:
|
||||
% else:
|
||||
${activity_rust_type(p)},
|
||||
% endif
|
||||
% endfor
|
||||
@@ -68,12 +106,12 @@ impl<'a, C, NC, A> MethodBuilder for ${ThisType} {}
|
||||
|
||||
impl<'a, C, NC, A> ${ThisType} {
|
||||
|
||||
/// Perform the operation you have build so far.
|
||||
/// Can only be called once !
|
||||
/// TODO: Build actual call
|
||||
pub fn ${api.terms.action}(self) {
|
||||
/// Perform the operation you have build so far.
|
||||
/// Can only be called once !
|
||||
/// TODO: Build actual call
|
||||
pub fn ${api.terms.action}(self) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
## SETTERS ###############
|
||||
% for p in params:
|
||||
@@ -88,38 +126,38 @@ ${self._setter(resource, method, m, p, ThisType, c)}\
|
||||
###############################################################################################
|
||||
<%def name="_setter(resource, method, m, p, ThisType, c)">\
|
||||
<%
|
||||
InType = activity_input_type(p)
|
||||
InType = activity_input_type(p)
|
||||
|
||||
def show_part_info(m, p):
|
||||
if p.name != 'part':
|
||||
return False
|
||||
if not (m.get('request') and m.get('response')):
|
||||
return False
|
||||
return m.request.get(TREF, 'first') == m.response.get(TREF, 'second')
|
||||
def show_part_info(m, p):
|
||||
if p.name != 'part':
|
||||
return False
|
||||
if not (m.get('request') and m.get('response')):
|
||||
return False
|
||||
return m.request.get(TREF, 'first') == m.response.get(TREF, 'second')
|
||||
|
||||
value_name = 'new_value'
|
||||
new_value_copied = rust_copy_value_s(value_name, InType, p)
|
||||
if not is_required_property(p):
|
||||
new_value_copied = 'Some(%s)' % new_value_copied
|
||||
value_name = 'new_value'
|
||||
new_value_copied = rust_copy_value_s(value_name, InType, p)
|
||||
if not is_required_property(p):
|
||||
new_value_copied = 'Some(%s)' % new_value_copied
|
||||
%>\
|
||||
/// Sets the *${split_camelcase_s(p.name)}* ${get_word(p, 'location')}property to the given value.
|
||||
///
|
||||
% if show_part_info(m, p):
|
||||
/// Even though the *parts* list is automatically derived from *Resource* passed in
|
||||
/// during instantiation and indicates which values you are passing, the response would contain the very same parts.
|
||||
/// This may not always be desirable, as you can obtain (newly generated) parts you cannot pass in,
|
||||
/// like statistics that are generated server side. Therefore you should use this method to specify
|
||||
/// the parts you provide in addition to the ones you want in the response.
|
||||
% elif is_required_property(p):
|
||||
/// Even though the property as already been set when instantiating this call,
|
||||
/// we provide this method for API completeness.
|
||||
% endif
|
||||
///
|
||||
% if 'description' in p:
|
||||
/// Sets the *${split_camelcase_s(p.name)}* ${get_word(p, 'location')}property to the given value.
|
||||
///
|
||||
% if show_part_info(m, p):
|
||||
/// Even though the *parts* list is automatically derived from *Resource* passed in
|
||||
/// during instantiation and indicates which values you are passing, the response would contain the very same parts.
|
||||
/// This may not always be desirable, as you can obtain (newly generated) parts you cannot pass in,
|
||||
/// like statistics that are generated server side. Therefore you should use this method to specify
|
||||
/// the parts you provide in addition to the ones you want in the response.
|
||||
% elif is_required_property(p):
|
||||
/// Even though the property as already been set when instantiating this call,
|
||||
/// we provide this method for API completeness.
|
||||
% endif
|
||||
///
|
||||
% if 'description' in p:
|
||||
${p.description | rust_doc_comment, indent_all_but_first_by(1)}
|
||||
% endif
|
||||
pub fn ${mangle_ident(p.name)}(&mut self, ${value_name}: ${InType}) -> &mut ${ThisType} {
|
||||
self.${property(p.name)} = ${new_value_copied};
|
||||
return self;
|
||||
}
|
||||
% endif
|
||||
pub fn ${mangle_ident(p.name)}(&mut self, ${value_name}: ${InType}) -> &mut ${ThisType} {
|
||||
self.${property(p.name)} = ${new_value_copied};
|
||||
return self;
|
||||
}
|
||||
</%def>
|
||||
@@ -1,6 +1,9 @@
|
||||
import re
|
||||
from random import (randint, random, choice, seed)
|
||||
import collections
|
||||
|
||||
seed(7337)
|
||||
|
||||
re_linestart = re.compile('^', flags=re.MULTILINE)
|
||||
re_first_4_spaces = re.compile('^ {1,4}', flags=re.MULTILINE)
|
||||
|
||||
@@ -14,6 +17,14 @@ TYPE_MAP = {'boolean' : 'bool',
|
||||
'array' : 'Vec',
|
||||
'string' : 'String',
|
||||
'object' : 'HashMap'}
|
||||
|
||||
_words = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.".split(' ')
|
||||
RUST_TYPE_RND_MAP = {'bool': lambda: str(bool(randint(0, 1))).lower(),
|
||||
'u32' : lambda: randint(0, 100),
|
||||
'f64' : lambda: random(),
|
||||
'i32' : lambda: randint(-101, -1),
|
||||
'String': lambda: '"%s"' % choice(_words),
|
||||
}
|
||||
TREF = '$ref'
|
||||
IO_RESPONSE = 'response'
|
||||
IO_REQUEST = 'request'
|
||||
@@ -81,7 +92,13 @@ def indent_all_but_first_by(tabs):
|
||||
# useful if you have defs embedded in an unindent block - they need to counteract.
|
||||
# It's a bit itchy, but logical
|
||||
def indent(s):
|
||||
return re_linestart.sub(' ', s)
|
||||
return re_linestart.sub(' ' * SPACES_PER_TAB, s)
|
||||
|
||||
# indent by given amount of spaces
|
||||
def indent_by(n):
|
||||
def indent_inner(s):
|
||||
return re_linestart.sub(' ' * n, s)
|
||||
return indent_inner
|
||||
|
||||
# return s, with trailing newline
|
||||
def trailing_newline(s):
|
||||
@@ -466,3 +483,10 @@ def get_word(d, n, e = ''):
|
||||
def property(n):
|
||||
return '_' + mangle_ident(n)
|
||||
|
||||
# given a rust type-name (no optional, as from to_rust_type), you will get a suitable random default value
|
||||
# as string suitable to be passed as reference (or copy, where applicable)
|
||||
def rnd_arg_val_for_type(tn):
|
||||
try:
|
||||
return str(RUST_TYPE_RND_MAP[tn]())
|
||||
except KeyError:
|
||||
return '&Default::default()'
|
||||
|
||||
Reference in New Issue
Block a user