feat(docs): full usage example on landing page

Related to #4
This commit is contained in:
Sebastian Thiel
2015-03-12 16:40:28 +01:00
parent 4b9dbb28ff
commit 9a17ab9e4e
7 changed files with 334 additions and 241 deletions

View File

@@ -6,7 +6,7 @@
<%
from util import (new_context, rust_comment, rust_doc_comment,
rust_module_doc_comment, rb_type, hub_type, mangle_ident, hub_type_params_s,
hub_type_bounds, rb_type_params_s)
hub_type_bounds, rb_type_params_s, find_fattest_resource)
c = new_context(schemas, resources)
hub_type = hub_type(c.schemas, util.canonical_name())
@@ -34,7 +34,7 @@ extern crate "yup-oauth2" as oauth2;
extern crate mime;
extern crate url;
mod cmn;
pub mod cmn;
use std::collections::HashMap;
use std::marker::PhantomData;
@@ -45,7 +45,7 @@ use std::collections::BTreeMap;
use std::io;
use std::fs;
pub use cmn::{Hub, ReadSeek, Part, ResponseResult, RequestValue, NestedType, Delegate, DefaultDelegate};
use cmn::{Hub, ReadSeek, Part, ResponseResult, RequestValue, NestedType, Delegate, DefaultDelegate};
// ##############
@@ -80,7 +80,7 @@ ${lib.scope_enum()}
/// Instantiate a new hub
///
<%block filter="rust_doc_comment">\
<%lib:hub_usage_example/>\
${lib.hub_usage_example(c)}\
</%block>
pub struct ${hub_type}${ht_params} {
client: RefCell<C>,

View File

@@ -1,7 +1,10 @@
<%! from util import (activity_split, put_and, md_italic, split_camelcase_s, canonical_type_name,
<%! from util import (activity_split, put_and, md_italic, split_camelcase_s, canonical_type_name, hub_type,
rust_test_fn_invisible, rust_doc_test_norun, rust_doc_comment, markdown_rust_block,
unindent_first_by, mangle_ident, mb_type, singular, scope_url_to_variant) %>\
unindent_first_by, mangle_ident, mb_type, singular, scope_url_to_variant,
PART_MARKER_TRAIT, RESOURCE_MARKER_TRAIT, METHOD_BUILDER_MARKERT_TRAIT,
find_fattest_resource, build_all_params, pass_through, parts_from_params) %>\
<%namespace name="util" file="util.mako"/>\
<%namespace name="mbuild" file="mbuild.mako"/>\
## If rust-doc is True, examples will be made to work for rust doc tests. Otherwise they are set
## for github markdown.
@@ -10,28 +13,21 @@
<%def name="docs(c, rust_doc=True)">\
<%
# fr == fattest resource, the fatter, the more important, right ?
fr = None
if schemas:
for candidate in sorted(schemas.values(), key=lambda s: (len(c.sta_map.get(s.id, [])), len(s.get('properties', []))), reverse=True):
if candidate.id in c.sta_map:
fr = candidate
break
# end for each candidate to check
fr = find_fattest_resource(c)
hub_url = 'struct.' + hub_type(c.schemas, util.canonical_name()) + '.html'
%>\
# Features
Handle the following *Resources* with ease ...
Handle the following *Resources* with ease from the central [hub](${hub_url}) ...
% for r in sorted(c.rta_map.keys()):
<%
md_methods = list()
doc_base_url = ''
if not rust_doc:
doc_base_url = cargo.doc_base_url + '/' + util.library_name() + '/'
for method in sorted(c.rta_map[r]):
if rust_doc:
md_methods.append("[*%s*](struct.%s.html)" % (' '.join(n.lower() for n in reversed(method.split('.'))), mb_type(r, method)))
else:
# TODO: link to final destination, possibly just have one for all ...
md_methods.append("*%s*" % method)
md_methods.append("[*%s*](%sstruct.%s.html)" % (' '.join(n.lower() for n in reversed(method.split('.'))), doc_base_url, mb_type(r, method)))
md_resource = split_camelcase_s(r)
sn = singular(canonical_type_name(r))
@@ -45,20 +41,24 @@ Handle the following *Resources* with ease ...
Everything else about the *${util.canonical_name()}* API can be found at the
[official documentation site](${documentationLink}).
% endif
% if rust_doc:
Not what you are looking for ? Find all other google APIs in their Rust [documentation index](../index.html).
% endif
# Structure of this Library
The API is structured into the following primary items:
* **Hub**
* **[Hub](${hub_url})**
* a central object to maintain state and allow accessing all *Activities*
* **Resources**
* **[Resources](cmn/trait.${RESOURCE_MARKER_TRAIT}.html)**
* primary types that you can apply *Activities* to
* a collection of properties and *Parts*
* **Parts**
* **[Parts](cmn/trait.${PART_MARKER_TRAIT}.html)**
* a collection of properties
* never directly used in *Activities*
* **Activities**
* **[Activities](cmn/trait.${METHOD_BUILDER_MARKERT_TRAIT}.html)**
* operations to apply to *Resources*
Generally speaking, you can invoke *Activities* like this:
@@ -87,7 +87,7 @@ The `${api.terms.action}()` method performs the actual communication with the se
${'##'} Instantiating the Hub
${self.hub_usage_example(rust_doc)}\
${self.hub_usage_example(c, rust_doc, fr=fr)}\
**TODO** Example calls - there should soon be a generator able to do that with proper inputs
@@ -142,21 +142,43 @@ let mut hub = ${hub_type}::new(hyper::Client::new(), auth);\
## You will still have to set the filter for your comment type - either nothing, or rust_doc_comment !
###############################################################################################
###############################################################################################
<%def name="hub_usage_example(rust_doc=True)">\
<%def name="hub_usage_example(c, rust_doc=True, fr=None)">\
<%
test_filter = rust_test_fn_invisible
main_filter = rust_doc_test_norun
if not rust_doc:
test_filter = lambda s: s
test_filter = pass_through
main_filter = markdown_rust_block
if fr is None:
fr = find_fattest_resource(c)
if fr is not None:
fqan = None
last_param_count = None
for fqan in c.sta_map[fr.id]:
_, aresource, amethod = activity_split(fqan)
am = c.fqan_map[fqan]
build_all_params(c, am)
aparams, arequest_value = build_all_params(c, am)
if last_param_count is None or len(aparams) > last_param_count:
m, resource, method, params, request_value = am, aresource, amethod, aparams, arequest_value
last_param_count = len(aparams)
# end for each fn to test
part_prop, parts = parts_from_params(params)
# end fill in values
%>\
% if fr:
${mbuild.usage(resource, method, m, params, request_value, parts, show_all=True, rust_doc=rust_doc)}\
% else:
<%block filter="main_filter">\
${util.test_prelude()}\
<%block filter="test_filter">\
${self.test_hub(canonical_type_name(util.canonical_name()))}\
${self.test_hub(hub_type(c.schemas, util.canonical_name()))}
</%block>
</%block>
% endif
</%def>
###############################################################################################

View File

@@ -6,7 +6,8 @@
schema_to_required_property, rust_copy_value_s, is_required_property,
hide_rust_doc_test, build_all_params, REQUEST_VALUE_PROPERTY_NAME, organize_params,
indent_by, to_rust_type, rnd_arg_val_for_type, extract_parts, mb_type_params_s,
hub_type_params_s, method_media_params, enclose_in, mb_type_bounds, method_response)
hub_type_params_s, method_media_params, enclose_in, mb_type_bounds, method_response,
METHOD_BUILDER_MARKERT_TRAIT, pass_through, markdown_rust_block, parts_from_params)
def get_parts(part_prop):
if not part_prop:
@@ -37,13 +38,9 @@
mb_tparams = mb_type_params_s(m)
ThisType = mb_type(resource, method) + mb_tparams
params, request_value = build_all_params(schemas, c, m, IO_REQUEST, REQUEST_VALUE_PROPERTY_NAME)
part_prop = None
for p in params:
if p.name == 'part':
part_prop = p
break
# end for each param
params, request_value = build_all_params(c, m)
part_prop, parts = parts_from_params(params)
part_desc = make_parts_desc(part_prop)
parts = get_parts(part_prop)
%>\
@@ -103,11 +100,11 @@ pub struct ${ThisType}
% endif
}
impl${mb_tparams} cmn::MethodBuilder for ${ThisType} {}
impl${mb_tparams} cmn::${METHOD_BUILDER_MARKERT_TRAIT} for ${ThisType} {}
impl${mb_tparams} ${ThisType} where ${', '.join(mb_type_bounds())} {
${self._action_fn(resource, method, m, params, request_value, parts)}\
${self._action_fn(c, resource, method, m, params, request_value, parts)}\
## SETTERS ###############
% for p in params:
@@ -208,9 +205,11 @@ ${self._setter_fn(resource, method, m, p, part_prop, ThisType, c)}\
## creates usage docs the method builder
## show_all: If True, we will show all comments and hide no prelude. It's good to build a complete,
## documented example for a given method.
###############################################################################################
###############################################################################################
<%def name="usage(resource, method, m, params, request_value, parts)">\
<%def name="usage(resource, method, m, params, request_value, parts=None, show_all=False, rust_doc=True)">\
<%
hub_type_name = hub_type(schemas, util.canonical_name())
required_props, optional_props, part_prop = organize_params(params, request_value)
@@ -250,24 +249,28 @@ ${self._setter_fn(resource, method, m, p, part_prop, ThisType, c)}\
action_args = media_params and media_params[-1].type.example_value or ''
random_value_warning = "Values shown here are possibly random and not representative !"
hide_filter = show_all and pass_through or hide_rust_doc_test
test_block_filter = rust_doc and rust_doc_test_norun or markdown_rust_block
test_fn_filter = rust_doc and rust_test_fn_invisible or pass_through
%>\
<%block filter="rust_doc_test_norun">\
${capture(util.test_prelude) | hide_rust_doc_test}\
<%block filter="test_block_filter">\
${capture(util.test_prelude) | hide_filter}\
% if request_value:
# use ${util.library_name()}::${request_value.id};
% endif
% if media_params:
# use std::fs;
% endif
<%block filter="rust_test_fn_invisible">\
${capture(lib.test_hub, hub_type_name, comments=False) | hide_rust_doc_test}
<%block filter="test_fn_filter">\
${capture(lib.test_hub, hub_type_name, comments=show_all) | hide_filter}
% if request_value:
// As the method needs a request, you would usually fill it with the desired information
// into the respective structure. Some of the parts shown here might not be applicable !
// ${random_value_warning}
let mut ${rb_name}: ${request_value.id} = Default::default();
% for spn, sp in request_value.get('properties', dict()).iteritems():
% if spn not in parts:
% if parts is not None and spn not in parts:
<% continue %>
% endif
<%
@@ -312,7 +315,7 @@ ${'.' + action_name | indent_by(13)}(${action_args});
## create an entire 'api.terms.action' method
###############################################################################################
###############################################################################################
<%def name="_action_fn(resource, method, m, params, request_value, parts)">\
<%def name="_action_fn(c, resource, method, m, params, request_value, parts)">\
<%
import os.path
join_url = lambda b, e: b.strip('/') + e
@@ -323,7 +326,7 @@ ${'.' + action_name | indent_by(13)}(${action_args});
qualifier = 'pub '
add_args = ''
rtype = 'cmn::Result<()>'
response_schema = method_response(schemas, c, m)
response_schema = method_response(c, m)
if response_schema:
rtype = 'cmn::Result<%s>' % (response_schema.id)

View File

@@ -56,7 +56,7 @@ impl${rb_params} ${ThisType} {
# skip part if we have a request resource. Only resources can have parts
# that we can easily deduce
params, request_value = build_all_params(schemas, c, m, IO_REQUEST, REQUEST_VALUE_PROPERTY_NAME)
params, request_value = build_all_params(c, m)
required_props, optional_props, part_prop = organize_params(params, request_value)
method_args = ''

View File

@@ -56,6 +56,8 @@ DELEGATE_TYPE = 'Delegate'
REQUEST_PRIORITY = 100
REQUEST_MARKER_TRAIT = 'RequestValue'
RESPONSE_MARKER_TRAIT = 'ResponseResult'
RESOURCE_MARKER_TRAIT = 'Resource'
METHOD_BUILDER_MARKERT_TRAIT = 'MethodBuilder'
PART_MARKER_TRAIT = 'Part'
NESTED_MARKER_TRAIT = 'NestedType'
REQUEST_VALUE_PROPERTY_NAME = 'request'
@@ -126,6 +128,10 @@ def hide_rust_doc_test(s):
def unindent(s):
return re_first_4_spaces.sub('', s)
# don't do anything with the passed in string
def pass_through(s):
return s
# tabs: 1 tabs is 4 spaces
def unindent_first_by(tabs):
def unindent_inner(s):
@@ -377,7 +383,7 @@ def schema_markers(s, c):
# it should have at least one activity that matches it's type to qualify for the Resource trait
for fqan, iot in activities.iteritems():
if activity_name_to_type_name(activity_split(fqan)[1]).lower() == sid.lower():
res.add('cmn::Resource')
res.add('cmn::%s' % RESOURCE_MARKER_TRAIT)
if IO_RESPONSE in iot:
res.add(RESPONSE_MARKER_TRAIT)
if IO_REQUEST in iot:
@@ -444,8 +450,8 @@ def method_params(m, required=None, location=None):
# end for each parameter
return sorted(res, key=lambda p: (p.priority, p.name), reverse=True)
def _method_io(type_name, schemas, c, m, marker=None):
s = schemas.get(m.get(type_name, dict()).get(TREF))
def _method_io(type_name, c, m, marker=None):
s = c.schemas.get(m.get(type_name, dict()).get(TREF))
if s is None:
return s
if s and marker and marker not in schema_markers(s, c):
@@ -454,12 +460,12 @@ def _method_io(type_name, schemas, c, m, marker=None):
# return the given method's request or response schema (dict), or None.
# optionally return only schemas with the given marker trait
def method_request(schemas, c, m, marker=None):
return _method_io('request', schemas, c, m, marker)
def method_request(c, m, marker=None):
return _method_io('request', c, m, marker)
# As method request, but returns response instead
def method_response(schemas, c, m, marker=None):
return _method_io('response', schemas, c, m, marker)
def method_response(c, m, marker=None):
return _method_io('response', c, m, marker)
# return string like 'n.clone()', but depending on the type name of tn (e.g. &str -> n.to_string())
def rust_copy_value_s(n, tn, p):
@@ -529,11 +535,11 @@ def method_media_params(m):
# Build all parameters used in a given method !
# schemas, context, method(dict), 'request'|'response', request_prop_name -> (params, request_value|None)
def build_all_params(schemas, c, m, n, npn):
request_value = method_request(schemas, c, m)
def build_all_params(c, m):
request_value = method_request(c, m)
params = method_params(m)
if request_value:
params.insert(0, schema_to_required_property(request_value, npn))
params.insert(0, schema_to_required_property(request_value, REQUEST_VALUE_PROPERTY_NAME))
# add the delegate. It's a type parameter, which has to remain in sync with the type-parameters we actually build.
dp = type(m)({ 'name': 'delegate',
TREF: "&'a mut %s" % DELEGATE_TYPE,
@@ -748,6 +754,7 @@ def mb_additional_type_params(m):
def mb_type(r, m):
return "%s%sMethodBuilder" % (singular(canonical_type_name(r)), dot_sep_to_canonical_type_name(m))
# canonicalName = util.canonical_name()
def hub_type(schemas, canonicalName):
name = canonical_type_name(canonicalName)
if schemas and name in schemas:
@@ -772,6 +779,31 @@ def property(n):
def dot_sep_to_canonical_type_name(n):
return ''.join(canonical_type_name(singular(t)) for t in n.split('.'))
def find_fattest_resource(c):
fr = None
if c.schemas:
for candidate in sorted(c.schemas.values(),
key=lambda s: (len(c.sta_map.get(s.id, [])), len(s.get('properties', []))), reverse=True):
if candidate.id in c.sta_map:
fr = candidate
break
# end for each candidate to check
# end if there are schemas
return fr
# Extract valid parts from the description of the parts prop contained within the given parameter list
# can be an empty list.
def parts_from_params(params):
part_prop = None
for p in params:
if p.name == 'part':
part_prop = p
break
# end for each param
if part_prop:
return part_prop, extract_parts(part_prop.get('description', ''))
return part_prop, list()
# Convert a scope url to a nice enum variant identifier, ready for use in code
# name = name of the api, without version
def scope_url_to_variant(name, url, fully_qualified=True):