mirror of
https://github.com/OMGeeky/google-apis-rs.git
synced 2026-02-23 15:49:49 +01:00
feat(traits): add marker traits to schema types
Based on their involvement in activities. It nearly works perfectly.
This commit is contained in:
2
Makefile
2
Makefile
@@ -16,7 +16,7 @@ API_DEPS = .api.deps
|
||||
API_SHARED_INFO = etc/api/shared.yaml
|
||||
API_JSON_FILES = $(shell find etc -type f -name '*-api.json')
|
||||
MAKO_LIB_DIR = $(MAKO_SRC)/lib
|
||||
MAKO_LIB_FILES = $(shell find $(MAKO_LIB_DIR) -type f -name '*.mako' -or -name '*.py')
|
||||
MAKO_LIB_FILES = $(shell find $(MAKO_LIB_DIR) -type f -name '*.*')
|
||||
|
||||
help:
|
||||
$(info using template engine: '$(TPL)')
|
||||
|
||||
@@ -19,6 +19,8 @@ extern crate "yup-oauth2" as oauth2;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use cmn::{Resource, Part, ResponseResult, RequestResult, NestedType};
|
||||
|
||||
// ############
|
||||
// SCHEMAS ###
|
||||
// ##########
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
## Create new schema with everything.
|
||||
## 's' contains the schema structure from json to build
|
||||
<%def name="new(s, c)">\
|
||||
<% assert s.type == "object" %>\
|
||||
<%
|
||||
assert s.type == "object"
|
||||
markers = util.schema_markers(s, c)
|
||||
%>\
|
||||
<%block filter="util.rust_doc_comment">\
|
||||
${doc(s, c)}\
|
||||
</%block>
|
||||
@@ -18,6 +21,10 @@ pub struct ${s.id}\
|
||||
% else:
|
||||
;
|
||||
% endif
|
||||
|
||||
% for marker_trait in markers:
|
||||
impl ${marker_trait} for ${s.id} {}
|
||||
% endfor
|
||||
</%def>
|
||||
|
||||
<%def name="doc(s, c)">\
|
||||
@@ -26,7 +33,11 @@ ${s.get('description', 'There is no detailed description.')}
|
||||
|
||||
# Activities
|
||||
|
||||
${''.join("* %s\n" % a for a in c.sta_map[s.id].keys())}
|
||||
This type is used in activities, which are methods you may call on this type or where this type is involved in.
|
||||
The list links the activity name, along with information about where it is used (one of ${util.put_and(util.IO_TYPES)}.
|
||||
|
||||
${''.join("* %s (%s)\n" % (util.activity_split(a)[1], iot and '|'.join(iot) or 'none')
|
||||
for a, iot in c.sta_map[s.id].iteritems())}
|
||||
% else:
|
||||
|
||||
This schema type is not used in any activity, and only used as *part* of another schema.
|
||||
|
||||
@@ -14,9 +14,14 @@ TYPE_MAP = {'boolean' : 'bool',
|
||||
'string' : 'String',
|
||||
'object' : 'HashMap'}
|
||||
TREF = '$ref'
|
||||
IO_RESPONSE = 'response'
|
||||
IO_REQUEST = 'request'
|
||||
IO_TYPES = (IO_REQUEST, IO_RESPONSE)
|
||||
INS_METHOD = 'insert'
|
||||
DEL_METHOD = 'delete'
|
||||
|
||||
NESTED_TYPE_MARKER = 'is_nested'
|
||||
|
||||
# ==============================================================================
|
||||
## @name Filters
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -79,7 +84,7 @@ def to_rust_type(sn, pn, t, allow_optionals=True):
|
||||
elif nt.get('additionalProperties'):
|
||||
nt = nt.additionalProperties
|
||||
else:
|
||||
assert(is_nested_type(nt))
|
||||
assert(is_nested_type_property(nt))
|
||||
# It's a nested type - we take it literally like $ref, but generate a name for the type ourselves
|
||||
# This of course assumes
|
||||
return nested_type_name(sn, pn)
|
||||
@@ -112,8 +117,13 @@ def to_rust_type(sn, pn, t, allow_optionals=True):
|
||||
except AttributeError as err:
|
||||
raise AssertionError("%s: unknown dict layout: %s" % (str(err), t))
|
||||
|
||||
def is_nested_type(t):
|
||||
return 'type' in t and t.type == 'object' and 'additionalProperties' not in t
|
||||
# return True if this property is actually a nested type
|
||||
def is_nested_type_property(t):
|
||||
return 'type' in t and t.type == 'object' and 'properties' in t
|
||||
|
||||
# Return True if the schema is nested
|
||||
def is_nested_type(s):
|
||||
return NESTED_TYPE_MARKER in s
|
||||
|
||||
# return an iterator yielding fake-schemas that identify a nested type
|
||||
def iter_nested_types(schemas):
|
||||
@@ -121,13 +131,38 @@ def iter_nested_types(schemas):
|
||||
if 'properties' not in s:
|
||||
continue
|
||||
for pn, p in s.properties.iteritems():
|
||||
if is_nested_type(p):
|
||||
if is_nested_type_property(p):
|
||||
ns = p.copy()
|
||||
ns.id = nested_type_name(s.id, pn)
|
||||
ns[NESTED_TYPE_MARKER] = True
|
||||
yield ns
|
||||
# end for ach property
|
||||
# end for aech schma
|
||||
|
||||
# Return sorted type names of all markers applicable to the given schema
|
||||
def schema_markers(s, c):
|
||||
res = set()
|
||||
|
||||
activities = c.sta_map.get(s.id, dict())
|
||||
if len(activities) == 0:
|
||||
res.add('Part')
|
||||
else:
|
||||
# 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)[0]) == s.id:
|
||||
res.add('Resource')
|
||||
if IO_RESPONSE in iot:
|
||||
res.add('ResponseResult')
|
||||
if IO_REQUEST in iot:
|
||||
res.add('RequestResult')
|
||||
# end for each activity
|
||||
# end handle activites
|
||||
|
||||
if is_nested_type(s):
|
||||
res.add('NestedType')
|
||||
|
||||
return sorted(res)
|
||||
|
||||
## -- End Rust TypeSystem -- @}
|
||||
|
||||
|
||||
@@ -148,7 +183,7 @@ def build_activity_mappings(activities):
|
||||
for mn, m in a.methods.iteritems():
|
||||
assert m.id not in fqan
|
||||
fqan[m.id] = m
|
||||
for in_out_type_name in ('request', 'response'):
|
||||
for in_out_type_name in IO_TYPES:
|
||||
t = m.get(in_out_type_name, None)
|
||||
if t is None:
|
||||
continue
|
||||
@@ -163,12 +198,10 @@ def build_activity_mappings(activities):
|
||||
# getrating: response is a 'SomethingResult', which is still related to activities name
|
||||
# the latter is used to deduce the resource name
|
||||
an, _ = activity_split(m.id)
|
||||
# videos -> Video
|
||||
an = an.capitalize()[:-1]
|
||||
info = res.setdefault(an, dict())
|
||||
tn = activity_name_to_type_name(an)
|
||||
info = res.setdefault(tn, dict())
|
||||
if m.id not in info:
|
||||
io_info = info.setdefault(m.id, [])
|
||||
io_info.append([])
|
||||
info.setdefault(m.id, [])
|
||||
# end handle other cases
|
||||
# end for each method
|
||||
# end for each activity
|
||||
@@ -180,6 +213,10 @@ def activity_split(fqan):
|
||||
assert len(t) == 3
|
||||
return t[1:]
|
||||
|
||||
# videos -> Video
|
||||
def activity_name_to_type_name(an):
|
||||
return an.capitalize()[:-1]
|
||||
|
||||
## -- End Activity Utilities -- @}
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,26 @@ extern crate hyper;
|
||||
extern crate "rustc-serialize" as rustc_serialize;
|
||||
extern crate "yup-oauth2" as oauth2;
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
/// Identifies types which can be inserted and deleted.
|
||||
/// Types with this trait are most commonly used by clients of this API.
|
||||
pub trait Resource: MarkerTrait {}
|
||||
|
||||
/// Identifies types which are used in API responses.
|
||||
pub trait ResponseResult: MarkerTrait {}
|
||||
|
||||
/// Identifies types which are used in API requests.
|
||||
pub trait RequestResult: MarkerTrait {}
|
||||
|
||||
/// Identifies types which are only used as part of other types, which
|
||||
/// usually are carrying the `Resource` trait.
|
||||
pub trait Part: MarkerTrait {}
|
||||
|
||||
/// Identifies types which are only used by other types internally.
|
||||
/// They have no special meaning, this trait just marks them for completeness.
|
||||
pub trait NestedType: MarkerTrait {}
|
||||
|
||||
/// This module is for testing only, its code is used in mako templates
|
||||
#[cfg(test)]
|
||||
mod dev;
|
||||
Reference in New Issue
Block a user