Skip to content

Commit 01db890

Browse files
committed
feat(builder): Partial MethodBuilder impl
Including documentation at least on the method builder part. The great thing is that fully working examples are now included on every type ! Now more involved part starts ... namely setting up the individual call method signatures.
1 parent 8746f5e commit 01db890

9 files changed

Lines changed: 931 additions & 75 deletions

File tree

gen/youtube3/src/cmn.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ use std::marker::MarkerTrait;
77
/// The hub allows to access all resource methods more easily.
88
pub trait Hub: MarkerTrait {}
99

10+
/// Identifies types for building methods of a particular type
11+
pub trait MethodBuilder: MarkerTrait {}
12+
1013
/// Identifies types which can be inserted and deleted.
1114
/// Types with this trait are most commonly used by clients of this API.
1215
pub trait Resource: MarkerTrait {}

gen/youtube3/src/lib.rs

Lines changed: 807 additions & 1 deletion
Large diffs are not rendered by default.

src/mako/lib.rs.mako

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<%
22
from util import (iter_nested_types, new_context, rust_comment, rust_doc_comment,
33
rust_module_doc_comment, rust_doc_test_norun, canonical_type_name,
4-
rust_test_fn_invisible)
4+
mb_type, singular, rust_test_fn_invisible, put_and)
55
nested_schemas = list(iter_nested_types(schemas))
66
77
c = new_context(resources)
88
99
hub_type = canonical_type_name(canonicalName)
10+
1011
%>\
1112
<%namespace name="lib" file="lib/lib.mako"/>\
1213
<%namespace name="mutil" file="lib/util.mako"/>\
@@ -32,7 +33,7 @@ use std::marker::PhantomData;
3233
use std::borrow::BorrowMut;
3334
use std::cell::RefCell;
3435

35-
pub use cmn::{Hub, Resource, Part, ResponseResult, RequestResult, NestedType};
36+
pub use cmn::{Hub, MethodBuilder, Resource, Part, ResponseResult, RequestResult, NestedType};
3637

3738
// ########
3839
// HUB ###
@@ -45,7 +46,7 @@ pub use cmn::{Hub, Resource, Part, ResponseResult, RequestResult, NestedType};
4546
/// Instantiate a new hub
4647
///
4748
<%block filter="rust_doc_comment">\
48-
${lib.hub_usage_example()}\
49+
<%lib:hub_usage_example/>\
4950
</%block>
5051
pub struct ${hub_type}<C, NC, A> {
5152
client: RefCell<C>,
@@ -67,6 +68,12 @@ impl<'a, C, NC, A> ${hub_type}<C, NC, A>
6768
_m: PhantomData,
6869
}
6970
}
71+
72+
% for resource in sorted(c.rta_map.keys()):
73+
pub fn ${resource}(&'a self) -> ${mb_type(resource)}<'a, C, NC, A> {
74+
${mb_type(resource)} { hub: &self }
75+
}
76+
% endfor
7077
}
7178

7279

@@ -84,4 +91,39 @@ ${schema.new(s, c)}
8491
## We have to find them and process them as normal types
8592
% for s in nested_schemas:
8693
${schema.new(s, c)}
87-
% endfor
94+
% endfor
95+
96+
// ###################
97+
// MethodBuilders ###
98+
// #################
99+
100+
% for resource, methods in c.rta_map.iteritems():
101+
/// A builder providing access to all methods supported on *${singular(resource)}* resources.
102+
/// It is usually not used directly, but through the `${hub_type}` hub.
103+
///
104+
/// # Example
105+
///
106+
/// Instantiate a resource builder
107+
///
108+
<%block filter="rust_doc_test_norun, rust_doc_comment">\
109+
${mutil.test_prelude()}\
110+
111+
<%block filter="rust_test_fn_invisible">\
112+
${lib.test_hub(canonical_type_name(canonicalName))}\
113+
114+
// Usually you wouldn't stick this into a variable, but keep calling `MethodBuilders`
115+
// like ${put_and(sorted('`%s(...)`' % f for f in methods))}
116+
let rb = hub.${resource}();
117+
</%block>
118+
</%block>
119+
pub struct ${mb_type(resource)}<'a, C, NC, A>
120+
where NC: 'a,
121+
C: 'a,
122+
A: 'a, {
123+
124+
hub: &'a ${hub_type}<C, NC, A>
125+
}
126+
127+
impl<'a, C, NC, A> MethodBuilder for ${mb_type(resource)}<'a, C, NC, A> {}
128+
% endfor
129+

src/mako/lib/lib.mako

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,13 @@
1212
# fr == fattest resource, the fatter, the more important, right ?
1313
fr = None
1414
fr = sorted(schemas.values(), key=lambda s: (len(c.sta_map.get(s.id, [])), len(s.get('properties', []))), reverse=True)[0]
15-
16-
# resouce -> [activity, ...]
17-
amap = dict()
18-
for an in c.fqan_map:
19-
resource, activity = activity_split(an)
20-
amap.setdefault(resource, list()).append(activity)
2115
%>\
2216
# Features
2317

2418
Handle the following *Resources* with ease ...
2519

26-
% for r in sorted(amap.keys()):
27-
* ${split_camelcase_s(r)} (${put_and(md_italic(sorted(amap[r])))})
20+
% for r in sorted(c.rta_map.keys()):
21+
* ${split_camelcase_s(r)} (${put_and(md_italic(sorted(c.rta_map[r])))})
2822
% endfor
2923

3024
# Structure of this Library

src/mako/lib/schema.mako

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
<%! from util import (schema_markers, rust_doc_comment, mangle_ident, to_rust_type, put_and, IO_TYPES, activity_split) %>\
1+
<%! from util import (schema_markers, rust_doc_comment, mangle_ident, to_rust_type, put_and,
2+
IO_TYPES, activity_split, enclose_in)
3+
%>\
24
## Create new schema with everything.
35
## 's' contains the schema structure from json to build
46
<%def name="new(s, c)">\
@@ -34,8 +36,7 @@ ${s.get('description', 'There is no detailed description.')}
3436
# Activities
3537
3638
This type is used in activities, which are methods you may call on this type or where this type is involved in.
37-
The list links the activity name, along with information about where it is used (one of ${put_and(list('*%s*' % t
38-
for t in IO_TYPES))}).
39+
The list links the activity name, along with information about where it is used (one of ${put_and(enclose_in('*', IO_TYPES))}).
3940
4041
${''.join("* %s (%s)\n" % (activity_split(a)[1], iot and '|'.join(iot) or 'none')
4142
for a, iot in c.sta_map[s.id].iteritems())}

src/mako/lib/util.py

Lines changed: 58 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,17 @@ def put_and(l):
101101
return l[0]
102102
return ', '.join(l[:-1]) + ' and ' + l[-1]
103103

104+
# ['foo', ...] with e == '*' -> ['*foo*', ...]
105+
def enclose_in(e, l):
106+
return ['%s%s%s' % (e, s, e) for s in l]
107+
104108
def md_italic(l):
105-
return ['*%s*' % s for s in l]
109+
return enclose_in('*', l)
110+
111+
def singular(s):
112+
if s[-1] == 's':
113+
return s[:-1]
114+
return s
106115

107116
def split_camelcase_s(s):
108117
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1 \2', s)
@@ -226,44 +235,6 @@ def schema_markers(s, c):
226235
# -------------------------
227236
## @name Activity Utilities
228237
# @{
229-
230-
# Returns (A, B) where
231-
# A: { SchemaTypeName -> { fqan -> ['request'|'response', ...]}
232-
# B: { fqan -> activity_method_data }
233-
# fqan = fully qualified activity name
234-
def build_activity_mappings(activities):
235-
res = dict()
236-
fqan = dict()
237-
for an, a in activities.iteritems():
238-
if 'methods' not in a:
239-
continue
240-
for mn, m in a.methods.iteritems():
241-
assert m.id not in fqan
242-
fqan[m.id] = m
243-
for in_out_type_name in IO_TYPES:
244-
t = m.get(in_out_type_name, None)
245-
if t is None:
246-
continue
247-
tn = to_rust_type(None, None, t, allow_optionals=False)
248-
info = res.setdefault(tn, dict())
249-
io_info = info.setdefault(m.id, [])
250-
io_info.append(in_out_type_name)
251-
# end for each io type
252-
253-
# handle delete/getrating/(possibly others)
254-
# delete: has no response or request
255-
# getrating: response is a 'SomethingResult', which is still related to activities name
256-
# the latter is used to deduce the resource name
257-
an, _ = activity_split(m.id)
258-
tn = activity_name_to_type_name(an)
259-
info = res.setdefault(tn, dict())
260-
if m.id not in info:
261-
info.setdefault(m.id, [])
262-
# end handle other cases
263-
# end for each method
264-
# end for each activity
265-
return res, fqan
266-
267238
# return (name, method)
268239
def activity_split(fqan):
269240
t = fqan.split('.')
@@ -281,12 +252,54 @@ def iter_acitivities(c):
281252
## -- End Activity Utilities -- @}
282253

283254

284-
Context = collections.namedtuple('Context', ['sta_map', 'fqan_map'])
255+
Context = collections.namedtuple('Context', ['sta_map', 'fqan_map', 'rta_map'])
285256

286257
# return a newly build context from the given data
287258
def new_context(resources):
259+
# Returns (A, B) where
260+
# A: { SchemaTypeName -> { fqan -> ['request'|'response', ...]}
261+
# B: { fqan -> activity_method_data }
262+
# fqan = fully qualified activity name
263+
def build_activity_mappings(activities):
264+
res = dict()
265+
fqan = dict()
266+
for an, a in activities.iteritems():
267+
if 'methods' not in a:
268+
continue
269+
for mn, m in a.methods.iteritems():
270+
assert m.id not in fqan
271+
fqan[m.id] = m
272+
for in_out_type_name in IO_TYPES:
273+
t = m.get(in_out_type_name, None)
274+
if t is None:
275+
continue
276+
tn = to_rust_type(None, None, t, allow_optionals=False)
277+
info = res.setdefault(tn, dict())
278+
io_info = info.setdefault(m.id, [])
279+
io_info.append(in_out_type_name)
280+
# end for each io type
281+
282+
# handle delete/getrating/(possibly others)
283+
# delete: has no response or request
284+
# getrating: response is a 'SomethingResult', which is still related to activities name
285+
# the latter is used to deduce the resource name
286+
an, _ = activity_split(m.id)
287+
tn = activity_name_to_type_name(an)
288+
info = res.setdefault(tn, dict())
289+
if m.id not in info:
290+
info.setdefault(m.id, [])
291+
# end handle other cases
292+
# end for each method
293+
# end for each activity
294+
return res, fqan
295+
# end utility
296+
288297
sta_map, fqan_map = build_activity_mappings(resources)
289-
return Context(sta_map, fqan_map)
298+
rta_map = dict()
299+
for an in fqan_map:
300+
resource, activity = activity_split(an)
301+
rta_map.setdefault(resource, list()).append(activity)
302+
return Context(sta_map, fqan_map, rta_map)
290303

291304
# Expects v to be 'v\d+', throws otherwise
292305
def to_api_version(v):
@@ -296,3 +309,7 @@ def to_api_version(v):
296309
# build a full library name (non-canonical)
297310
def library_name(name, version):
298311
return name + to_api_version(version)
312+
313+
# return type name of a resource builder, from a resource name
314+
def mb_type(r):
315+
return "%sMethodBuilder" % canonical_type_name(r)

src/rust/cmn.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ use std::marker::MarkerTrait;
55
/// The hub allows to access all resource methods more easily.
66
pub trait Hub: MarkerTrait {}
77

8+
/// Identifies types for building methods of a particular type
9+
pub trait MethodBuilder: MarkerTrait {}
10+
811
/// Identifies types which can be inserted and deleted.
912
/// Types with this trait are most commonly used by clients of this API.
1013
pub trait Resource: MarkerTrait {}

src/rust/dev/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ impl<'a, C, NC, A> YouTube<C, NC, A>
4343
}
4444

4545
pub fn videos(&'a self) -> videos::Service<'a, C, NC, A> {
46-
videos::Service::new(&self.client, &self.auth)
46+
videos::Service::new(&self)
4747
}
4848
}
4949

src/rust/dev/videos/service.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use rustc_serialize;
77
use hyper;
88
use oauth2;
99

10+
use super::super::YouTube;
11+
1012
/// Reresents all aspects of a youtube video resource. May only be partially
1113
/// available
1214
#[derive(RustcEncodable, RustcDecodable, Default, Clone)]
@@ -75,32 +77,23 @@ pub struct Service<'a, C, NC, A>
7577
C: 'a,
7678
A: 'a, {
7779

78-
client: &'a RefCell<C>,
79-
auth: &'a RefCell<A>,
80-
81-
_m: PhantomData<NC>
80+
hub: &'a YouTube<C, NC, A>
8281
}
8382

8483
impl<'a, C, NC, A> Service<'a, C, NC, A>
8584
where NC: hyper::net::NetworkConnector,
8685
C: BorrowMut<hyper::Client<NC>> + 'a,
8786
A: oauth2::GetToken + 'a {
8887

89-
pub fn new(client: &'a RefCell<C>, authenticator: &'a RefCell<A>) -> Service<'a, C, NC, A> {
90-
Service {
91-
client: client,
92-
auth: authenticator,
93-
_m: PhantomData,
94-
}
88+
pub fn new(hub: &'a YouTube<C, NC, A>) -> Service<'a, C, NC, A> {
89+
Service { hub: hub }
9590
}
9691

9792
pub fn insert(&self, parts: &str, video: &Video) -> VideosInsertBuilder<'a, C, NC, A> {
9893
VideosInsertBuilder {
99-
client: self.client,
100-
auth: self.auth,
94+
hub: self.hub,
10195
video: video.clone(),
10296
parts: parts.to_string(),
103-
_m: PhantomData,
10497
}
10598
}
10699
}
@@ -110,12 +103,9 @@ pub struct VideosInsertBuilder<'a, C, NC, A>
110103
C: 'a,
111104
A: 'a {
112105

113-
client: &'a RefCell<C>,
114-
auth: &'a RefCell<A>,
106+
hub: &'a YouTube<C, NC, A>,
115107
video: Video,
116108
parts: String,
117-
118-
_m: PhantomData<NC>
119109
}
120110

121111

0 commit comments

Comments
 (0)