Merge branch 'schema'

This commit is contained in:
Sebastian Thiel
2015-03-04 11:07:08 +01:00
19 changed files with 3567 additions and 34 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.timestamp
.pyenv
*.pyc
**target/

View File

@@ -1,4 +1,4 @@
.PHONY: json-to-xml clean help api-deps rebuild-apis license
.PHONY: json-to-xml clean help api-deps regen-apis license
.SUFFIXES:
include Makefile.helpers
@@ -11,12 +11,13 @@ MAKO_RENDER := etc/bin/mako-render
TPL := $(PYTHON) $(MAKO_RENDER)
MAKO_SRC = src/mako
RUST_SRC = src/rust
API_DEPS_TPL = $(MAKO_SRC)/deps.mako
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)')
@@ -24,7 +25,7 @@ help:
$(info Targets)
$(info help - print this help)
$(info api-deps - generate a file to tell make what API file dependencies will be)
$(info rebuild-apis - clear out all generated apis, and regenerate them)
$(info regen-apis - clear out all generated apis, and regenerate them)
$(info help-api - show all api targets to build individually)
$(info license - regenerate the main license file)
@@ -35,18 +36,18 @@ $(PYTHON):
$(MAKO_RENDER): $(PYTHON)
$(API_DEPS): $(API_SHARED_INFO) $(API_DEPS_TPL) $(MAKO_LIB_FILES) $(MAKO_RENDER)
PYTHONPATH=$(MAKO_LIB_DIR) $(TPL) --template-dir '.' -io $(API_DEPS_TPL) --data-files $(API_SHARED_INFO) > $@
PYTHONPATH=$(MAKO_LIB_DIR) $(TPL) --template-dir '.' -io $(API_DEPS_TPL)=$@ --data-files $(API_SHARED_INFO)
api-deps: $(API_DEPS)
include $(API_DEPS)
LICENSE.md: $(MAKO_SRC)/LICENSE.md.mako $(API_SHARED_INFO)
$(TPL) -io $<=$@ --data-files $(API_SHARED_INFO)
PYTHONPATH=$(MAKO_LIB_DIR) $(TPL) -io $<=$@ --data-files $(API_SHARED_INFO)
license: LICENSE.md
rebuild-apis: clean-apis apis license
regen-apis: clean-apis apis license
clean: clean-apis
-rm -Rf $(VENV_DIR)

View File

@@ -13,6 +13,9 @@ api:
- name: youtube
version: v3
base_path: "etc/api"
terms:
# how to actually do something with the API
action: do
templates:
# all output directories are relative to the one set for the respective API
- source: README.md

30
gen/youtube3/LICENSE.md Normal file
View File

@@ -0,0 +1,30 @@
<!---
DO NOT EDIT !
This file was generated automatically from 'src/mako/LICENSE.md.mako'
DO NOT EDIT !
-->
The MIT License (MIT)
=====================
Copyright © `2015` `Sebastian Thiel`
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the “Software”), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

84
gen/youtube3/README.md Normal file
View File

@@ -0,0 +1,84 @@
<!---
DO NOT EDIT !
This file was generated automatically from 'src/mako/README.md.mako'
DO NOT EDIT !
-->
The `youtube3` library allows access to all features of *YouTube*.
# Features
Handle the following *Resources* with ease ...
* activities (*insert* and *list*)
* channel banners (*insert*)
* channel sections (*delete*, *insert*, *list* and *update*)
* channels (*list* and *update*)
* guide categories (*list*)
* i18n languages (*list*)
* i18n regions (*list*)
* live broadcasts (*bind*, *control*, *delete*, *insert*, *list*, *transition* and *update*)
* live streams (*delete*, *insert*, *list* and *update*)
* playlist items (*delete*, *insert*, *list* and *update*)
* playlists (*delete*, *insert*, *list* and *update*)
* search (*list*)
* subscriptions (*delete*, *insert* and *list*)
* thumbnails (*set*)
* video categories (*list*)
* videos (*delete*, *getRating*, *insert*, *list*, *rate* and *update*)
* watermarks (*set* and *unset*)
# Structure of this Library
The API is structured into the following primary items:
* **Hub**
* a central object to maintain state and allow accessing all *Activities*
* **Resources**
* primary types that you can apply *Activities* to
* a collection of properties and *Parts*
* **Parts**
* a collection of properties
* never directly used in *Activities*
* **Activities**
* operations to apply to *Resources*
Generally speaking, you can invoke *Activities* like this:
```Rust,ignore
let r = hub.resource().activity(...).do()
```
Or specifically ...
```ignore
let r = hub.videos().rate(...).do()
let r = hub.videos().getRating(...).do()
let r = hub.videos().list(...).do()
let r = hub.videos().insert(...).do()
let r = hub.videos().update(...).do()
let r = hub.videos().delete(...).do()
```
The `resource()` and `activity(...)` calls create [builders][builder-pattern]. The second one dealing with `Activities`
supports various methods to configure the impending operation. It is made such that all required arguments have to be
specified right away (i.e. `(...)`), whereas all optional ones can be [build up][builder-pattern] as desired.
The `do()` method performs the actual communication with the server and returns the respective result.
# Usage (*TODO*)
## Instantiating the Hub
## About error handling
## About costumization
[builder-pattern]: http://en.wikipedia.org/wiki/Builder_pattern
[google-go-api]: https://github.com/google/google-api-go-client
# License
The **youtube3** library was generated by Sebastian Thiel, and is placed
under the *MIT* license.
You can read the full text at the repository's [license file][repo-license].
[repo-license]: https://github.com/Byron/google-apis-rsLICENSE.md

26
gen/youtube3/cargo.toml Normal file
View File

@@ -0,0 +1,26 @@
# DO NOT EDIT !
# This file was generated automatically from 'src/mako/cargo.toml.mako'
# DO NOT EDIT !
[package]
name = "youtube3"
version = "0.0.1"
authors = ["Sebastian Thiel <byronimo@gmail>"]
description = "A complete library to interact with YouTube (protocol v3)"
repository = "https://github.com/Byron/google-apis-rs/gen/youtube3/.timestamp"
homepage = "https://developers.google.com/youtube/v3"
documentation = "http://byron.github.io/google-apis-rs"
license = "MIT"
keywords = ["youtube", "google", "protocol", "web", "api"]
[dependencies]
# Just to get hyper to work !
openssl = "= 0.4.3"
# Just to get hyper to work !
cookie = "= 0.1.13"
hyper = "*"
rustc-serialize = "*"
yup-oauth2 = "*"
[dev-dependencies]
yup-hyper-mock = "*"

21
gen/youtube3/src/cmn.rs Normal file
View File

@@ -0,0 +1,21 @@
// COPY OF 'src/rust/cmn.rs'
// DO NOT EDIT
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 {}

2948
gen/youtube3/src/lib.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,9 @@
## -*- coding: utf-8 -*-
<%! import util %>\
<%namespace name="mutil" file="lib/util.mako"/>\
<%block filter="util.markdown_comment">\
<%mutil:gen_info source="${self.uri}" />\
</%block>
The MIT License (MIT)
=====================

View File

@@ -1,6 +1,13 @@
<%
from util import (markdown_comment, new_context)
c = new_context(resources)
%>\
<%namespace name="lib" file="lib/lib.mako"/>\
<%namespace name="util" file="lib/util.mako"/>\
<%block filter="markdown_comment">\
<%util:gen_info source="${self.uri}" />\
</%block>
The `${util.library_name()}` library allows access to all features of *${canonicalName}*.
<%lib:docs />
${lib.docs(c)}
<%lib:license />

View File

@@ -1,8 +1,8 @@
<%! import util %>\
<%namespace name="mutil" file="lib/util.mako"/>\
# DO NOT EDIT !
# This file was generated automatically by '${self.uri}'
# DO NOT EDIT !
<%block filter="util.hash_comment">\
<%mutil:gen_info source="${self.uri}" />\
</%block>
[package]
name = "${mutil.library_name()}"
@@ -24,8 +24,5 @@ hyper = "*"
rustc-serialize = "*"
yup-oauth2 = "*"
[dependencies.cmn]
path = "${directories.common}/.."
[dev-dependencies]
yup-hyper-mock = "*"

View File

@@ -7,7 +7,9 @@
<%
import util
gen_root = directories.output + '/' + a.name + util.to_api_version(a.version)
gen_root_stamp = gen_root + '/.timestamp'
api_name = util.library_name(a.name, a.version)
api_common = gen_root + '/src/cmn.rs'
api_clean = api_name + '-clean'
# source, destination of individual output files
sds = [(directories.mako_src + '/' + i.source + '.mako', gen_root + '/' + i.get('output_dir', '') + '/' + i.source)
@@ -16,10 +18,16 @@
api_json_inputs = api_json + " $(API_SHARED_INFO)"
api_info.append((api_name, api_clean, gen_root))
%>\
${gen_root}: ${' '.join(i[0] for i in sds)} ${api_json_inputs} $(MAKO_LIB_FILES) $(MAKO_RENDER)
PYTHONPATH=$(MAKO_LIB_DIR) $(TPL) --template-dir '.' --var OUTPUT_DIR=$@ -io ${' '.join("%s=%s" % (s, d) for s, d in sds)} --data-files ${api_json_inputs}
${api_common}: $(RUST_SRC)/cmn.rs $(lastword $(MAKEFILE_LIST))
@ echo "// COPY OF '$<'" > $@
@ echo "// DO NOT EDIT" >> $@
@cat $< >> $@
${api_name}: ${gen_root}
${gen_root_stamp}: ${' '.join(i[0] for i in sds)} ${api_json_inputs} $(MAKO_LIB_FILES) $(MAKO_RENDER)
PYTHONPATH=$(MAKO_LIB_DIR) $(TPL) --template-dir '.' --var OUTPUT_DIR=$@ -io ${' '.join("%s=%s" % (s, d) for s, d in sds)} --data-files ${api_json_inputs}
@touch $@
${api_name}: ${gen_root_stamp} ${api_common}
${api_clean}:
-rm -Rf ${gen_root}

View File

@@ -1,9 +1,43 @@
<% import util %>\
<%
from util import (iter_nested_types, new_context, rust_comment, rust_module_doc_comment, )
nested_schemas = list(iter_nested_types(schemas))
c = new_context(resources)
%>\
<%namespace name="lib" file="lib/lib.mako"/>\
<%namespace name="mutil" file="lib/util.mako"/>\
<%block filter="util.rust_module_doc_comment">\
<%lib:docs />\
<%namespace name="schema" file="lib/schema.mako"/>\
<%block filter="rust_comment">\
<%mutil:gen_info source="${self.uri}" />\
</%block>
extern crate cmn;
<%block filter="rust_module_doc_comment">\
${lib.docs(c)}
</%block>
#![feature(core)]
#![allow(non_snake_case)]
extern crate "rustc-serialize" as rustc_serialize;
extern crate "yup-oauth2" as oauth2;
extern crate "yup-oauth2" as oauth2;
mod cmn;
use std::collections::HashMap;
pub use cmn::{Resource, Part, ResponseResult, RequestResult, NestedType};
// ############
// SCHEMAS ###
// ##########
% for s in schemas.values():
${schema.new(s, c)}
% endfor
// ###################
// NESTED SCHEMAS ###
// #################
## some schemas are only used once and basically internal types.
## We have to find them and process them as normal types
% for s in nested_schemas:
${schema.new(s, c)}
% endfor

View File

@@ -1,14 +1,79 @@
<%! import util %>\
<%namespace name="util" file="lib/util.mako"/>\
<%! from util import (activity_split, put_and, md_italic, split_camelcase_s) %>\
<%namespace name="util" file="util.mako"/>\
<%def name="docs(c)">\
<%
# fr == fattest resource, the fatter, the more important, right ?
fr = None
fr = sorted(schemas.values(), key=lambda s: (len(c.sta_map.get(s.id, [])), len(s.get('properties', []))), reverse=True)[0]
# resouce -> [activity, ...]
amap = dict()
for an in c.fqan_map:
resource, activity = activity_split(an)
amap.setdefault(resource, list()).append(activity)
%>\
# Features
Handle the following *Resources* with ease ...
% for r in sorted(amap.keys()):
* ${split_camelcase_s(r)} (${put_and(md_italic(sorted(amap[r])))})
% endfor
# Structure of this Library
The API is structured into the following primary items:
* **Hub**
* a central object to maintain state and allow accessing all *Activities*
* **Resources**
* primary types that you can apply *Activities* to
* a collection of properties and *Parts*
* **Parts**
* a collection of properties
* never directly used in *Activities*
* **Activities**
* operations to apply to *Resources*
Generally speaking, you can invoke *Activities* like this:
```Rust,ignore
let r = hub.resource().activity(...).${api.terms.action}()
```
Or specifically ...
```ignore
% for an, a in c.sta_map[fr.id].iteritems():
<%
resource, activity = activity_split(an)
%>\
let r = hub.${resource}().${activity}(...).${api.terms.action}()
% endfor
```
The `resource()` and `activity(...)` calls create [builders][builder-pattern]. The second one dealing with `Activities`
supports various methods to configure the impending operation. It is made such that all required arguments have to be
specified right away (i.e. `(...)`), whereas all optional ones can be [build up][builder-pattern] as desired.
The `${api.terms.action}()` method performs the actual communication with the server and returns the respective result.
# Usage (*TODO*)
${'##'} Instantiating the Hub
${'##'} About error handling
${'##'} About costumization
[builder-pattern]: http://en.wikipedia.org/wiki/Builder_pattern
[google-go-api]: https://github.com/google/google-api-go-client
<%def name="docs()">\
TODO: Library level fully fledged documentation, incuding **summary** and **usage**.
And another line, for testing
</%def>
<%def name="license()">\
# License
The **${util.library_name(name, version)}** library was generated by ${util.put_and(copyright.authors)}, and is placed
The **${util.library_name()}** library was generated by ${put_and(copyright.authors)}, and is placed
under the *${copyright.license_abbrev}* license.
You can read the full text at the repository's [license file][repo-license].

46
src/mako/lib/schema.mako Normal file
View File

@@ -0,0 +1,46 @@
<%! from util import (schema_markers, rust_doc_comment, mangle_ident, to_rust_type, put_and, IO_TYPES, activity_split) %>\
## Create new schema with everything.
## 's' contains the schema structure from json to build
<%def name="new(s, c)">\
<%
assert s.type == "object"
markers = schema_markers(s, c)
%>\
<%block filter="rust_doc_comment">\
${doc(s, c)}\
</%block>
#[derive(RustcEncodable, RustcDecodable, Default, Clone)]
pub struct ${s.id}\
% if 'properties' in s:
{
% for pn, p in s.properties.iteritems():
${p.get('description', 'no description provided') | rust_doc_comment}
pub ${mangle_ident(pn)}: ${to_rust_type(s.id, pn, p)},
% endfor
}
% else:
;
% endif
% for marker_trait in markers:
impl ${marker_trait} for ${s.id} {}
% endfor
</%def>
<%def name="doc(s, c)">\
${s.get('description', 'There is no detailed description.')}
% if s.id in c.sta_map:
# Activities
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 ${put_and(list('*%s*' % t
for t in IO_TYPES))}).
${''.join("* %s (%s)\n" % (activity_split(a)[1], iot and '|'.join(iot) or 'none')
for a, iot in c.sta_map[s.id].iteritems())}
% else:
This type is not used in any activity, and only used as *part* of another schema.
% endif
</%def>

View File

@@ -1,5 +1,12 @@
<%! import util %>\
## source should be ${self.uri}
## you need to escape the output, using a filter for example
<%def name="gen_info(source)">\
DO NOT EDIT !
This file was generated automatically from '${source}'
DO NOT EDIT !\
</%def>
## This will only work within a substitution, not within python code
<%def name="to_api_version(v)">\

View File

@@ -1,6 +1,32 @@
import re
import collections
re_linestart = re.compile('^', flags=re.MULTILINE)
USE_FORMAT = 'use_format_field'
TYPE_MAP = {'boolean' : 'bool',
'integer' : USE_FORMAT,
'number' : USE_FORMAT,
'uint32' : 'u32',
'double' : 'f64',
'int32' : 'i32',
'array' : 'Vec',
'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
# ------------------------------------------------------------------------------
## @{
# rust module doc comment filter
def rust_module_doc_comment(s):
return re_linestart.sub('//! ', s)
@@ -9,10 +35,31 @@ def rust_module_doc_comment(s):
def rust_doc_comment(s):
return re_linestart.sub('/// ', s)
# Expects v to be 'v\d+', throws otherwise
def to_api_version(v):
assert len(v) >= 2 and v[0] == 'v'
return v[1:]
# rust comment filter
def rust_comment(s):
return re_linestart.sub('// ', s)
# hash-based comment filter
def hash_comment(s):
return re_linestart.sub('# ', s)
# markdown comments
def markdown_comment(s):
nl = ''
if not s.endswith('\n'):
nl = '\n'
return "<!---\n%s%s-->" % (s, nl)
# escape each string in l with "s" and return the new list
def estr(l):
return ['"%s"' % i for i in l]
## -- End Filters -- @}
# ==============================================================================
## @name Natural Language Utilities
# ------------------------------------------------------------------------------
## @{
# l must be a list, if it is more than one, 'and' will before last item
# l will also be coma-separtated
@@ -22,9 +69,190 @@ def put_and(l):
return l[0]
return ', '.join(l[:-1]) + ' and ' + l[-1]
# escape each string in l with "s" and return the new list
def estr(l):
return ['"%s"' % i for i in l]
def md_italic(l):
return ['*%s*' % s for s in l]
def split_camelcase_s(s):
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1 \2', s)
return re.sub('([a-z0-9])([A-Z])', r'\1 \2', s1).lower()
## -- End Natural Language Utilities -- @}
# ==============================================================================
## @name Rust TypeSystem
# ------------------------------------------------------------------------------
## @{
def nested_type_name(sn, pn):
return sn + pn.capitalize()
# Make properties which are reserved keywords usable
def mangle_ident(n):
if n == 'type':
return n + '_'
return n
# map a json type to an rust type
# sn = schema name
# pn = property name
# t = type dict
def to_rust_type(sn, pn, t, allow_optionals=True):
def nested_type(nt):
if nt.get('items', None) is not None:
nt = nt.items
elif nt.get('additionalProperties'):
nt = nt.additionalProperties
else:
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)
return to_rust_type(sn, pn, nt, allow_optionals=False)
# unconditionally handle $ref types, which should point to another schema.
if TREF in t:
tn = t[TREF]
if allow_optionals:
return "Option<%s>" % tn
return tn
try:
is_pod = True
rust_type = TYPE_MAP[t.type]
if t.type == 'array':
rust_type = "%s<%s>" % (rust_type, nested_type(t))
is_pod = False
elif t.type == 'object':
rust_type = "%s<String, %s>" % (rust_type, nested_type(t))
is_pod = False
elif t.type == 'string' and 'Count' in pn:
rust_type = 'i64'
elif rust_type == USE_FORMAT:
rust_type = TYPE_MAP[t.format]
if is_pod and allow_optionals:
return "Option<%s>" % rust_type
return rust_type
except KeyError as err:
raise AssertionError("%s: Property type '%s' unknown - add new type mapping: %s" % (str(err), t.type, str(t)))
except AttributeError as err:
raise AssertionError("%s: unknown dict layout: %s" % (str(err), 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):
for s in schemas.values():
if 'properties' not in s:
continue
for pn, p in s.properties.iteritems():
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]).lower() == s.id.lower():
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 -- @}
# -------------------------
## @name Activity Utilities
# @{
# Returns (A, B) where
# A: { SchemaTypeName -> { fqan -> ['request'|'response', ...]}
# B: { fqan -> activity_method }
# fqan = fully qualified activity name
def build_activity_mappings(activities):
res = dict()
fqan = dict()
for an, a in activities.iteritems():
if 'methods' not in a:
continue
for mn, m in a.methods.iteritems():
assert m.id not in fqan
fqan[m.id] = m
for in_out_type_name in IO_TYPES:
t = m.get(in_out_type_name, None)
if t is None:
continue
tn = to_rust_type(None, None, t, allow_optionals=False)
info = res.setdefault(tn, dict())
io_info = info.setdefault(m.id, [])
io_info.append(in_out_type_name)
# end for each io type
# handle delete/getrating/(possibly others)
# delete: has no response or request
# 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)
tn = activity_name_to_type_name(an)
info = res.setdefault(tn, dict())
if m.id not in info:
info.setdefault(m.id, [])
# end handle other cases
# end for each method
# end for each activity
return res, fqan
# return (name, method)
def activity_split(fqan):
t = fqan.split('.')
assert len(t) == 3
return t[1:]
# videos -> Video
def activity_name_to_type_name(an):
return an.capitalize()[:-1]
## -- End Activity Utilities -- @}
Context = collections.namedtuple('Context', ['sta_map', 'fqan_map'])
# return a newly build context from the given data
def new_context(resources):
sta_map, fqan_map = build_activity_mappings(resources)
return Context(sta_map, fqan_map)
# Expects v to be 'v\d+', throws otherwise
def to_api_version(v):
assert len(v) >= 2 and v[0] == 'v'
return v[1:]
# build a full library name (non-canonical)
def library_name(name, version):

19
src/rust/cmn.rs Normal file
View File

@@ -0,0 +1,19 @@
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 {}

View File

@@ -1,8 +1,12 @@
#![feature(core)]
//! library with code shared by all generated implementations
extern crate hyper;
extern crate "rustc-serialize" as rustc_serialize;
extern crate "yup-oauth2" as oauth2;
// just pull it in the check if it compiles
mod cmn;
/// This module is for testing only, its code is used in mako templates
#[cfg(test)]
mod dev;