feat(hub): generate hub implementation and docs

This includes docs for the library usage.
It's totally great to be able to paste example code right were it
belongs, and also put the same elsewhere to compose more complex docs.
This commit is contained in:
Sebastian Thiel
2015-03-04 11:05:41 +01:00
parent 85171ceb97
commit 615a124654
9 changed files with 264 additions and 19 deletions

View File

@@ -60,7 +60,7 @@ 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
supports various methods to configure the impending operation (not shown here). 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.
@@ -68,9 +68,34 @@ The `do()` method performs the actual communication with the server and returns
## Instantiating the Hub
```Rust
extern crate hyper;
extern crate "yup-oauth2" as oauth2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate youtube3;
use oauth2::{Authenticator, DefaultAuthenticatorDelegate, ApplicationSecret, MemoryStorage};
use std::default::Default;
use youtube3::YouTube;
// Get an ApplicationSecret instance by some means. It contains the `client_id` and `client_secret`,
// among other things.
let secret: ApplicationSecret = Default::default();
// Instantiate the authenticator. It will choose a suitable authentication flow for you,
// unless you replace `None` with the desired Flow
// Provide your own `AuthenticatorDelegate` to adjust the way it operates and get feedback about what's going on
// You probably want to bring in your own `TokenStorage` to persist tokens and retrieve them from storage.
let auth = Authenticator::new(&secret, DefaultAuthenticatorDelegate,
hyper::Client::new(),
<MemoryStorage as Default>::default(), None);
let mut hub = YouTube::new(hyper::Client::new(), auth);
```
**TODO** Example calls - there should soon be a generator able to do that with proper inputs
## About error handling
## About costumization
## About Customization/Callbacks
[builder-pattern]: http://en.wikipedia.org/wiki/Builder_pattern
[google-go-api]: https://github.com/google/google-api-go-client

View File

@@ -2,6 +2,11 @@
// DO NOT EDIT
use std::marker::MarkerTrait;
/// Identifies the Hub. There is only one per library, this trait is supposed
/// to make intended use more explicit.
/// The hub allows to access all resource methods more easily.
pub trait Hub: 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 {}

View File

@@ -57,7 +57,7 @@
//! ```
//!
//! 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
//! supports various methods to configure the impending operation (not shown here). 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.
//!
@@ -65,9 +65,36 @@
//!
//! ## Instantiating the Hub
//!
//! ```test_harness,no_run
//! extern crate hyper;
//! extern crate "yup-oauth2" as oauth2;
//! extern crate "rustc-serialize" as rustc_serialize;
//! extern crate youtube3;
//!
//! # #[test] fn egal() {
//! use oauth2::{Authenticator, DefaultAuthenticatorDelegate, ApplicationSecret, MemoryStorage};
//! use std::default::Default;
//!
//! use youtube3::YouTube;
//!
//! // Get an ApplicationSecret instance by some means. It contains the `client_id` and `client_secret`,
//! // among other things.
//! let secret: ApplicationSecret = Default::default();
//! // Instantiate the authenticator. It will choose a suitable authentication flow for you,
//! // unless you replace `None` with the desired Flow
//! // Provide your own `AuthenticatorDelegate` to adjust the way it operates and get feedback about what's going on
//! // You probably want to bring in your own `TokenStorage` to persist tokens and retrieve them from storage.
//! let auth = Authenticator::new(&secret, DefaultAuthenticatorDelegate,
//! hyper::Client::new(),
//! <MemoryStorage as Default>::default(), None);
//! let mut hub = YouTube::new(hyper::Client::new(), auth);
//! # }
//! ```
//!
//! **TODO** Example calls - there should soon be a generator able to do that with proper inputs
//! ## About error handling
//!
//! ## About costumization
//! ## About Customization/Callbacks
//!
//! [builder-pattern]: http://en.wikipedia.org/wiki/Builder_pattern
//! [google-go-api]: https://github.com/google/google-api-go-client
@@ -77,14 +104,77 @@
#![feature(core)]
#![allow(non_snake_case)]
extern crate hyper;
extern crate "rustc-serialize" as rustc_serialize;
extern crate "yup-oauth2" as oauth2;
mod cmn;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::borrow::BorrowMut;
use std::cell::RefCell;
pub use cmn::{Hub, Resource, Part, ResponseResult, RequestResult, NestedType};
// ########
// HUB ###
// ######
/// Central instance to access all YouTube related resource activities
///
/// # Examples
///
/// Instantiate a new hub
///
/// ```test_harness,no_run
/// extern crate hyper;
/// extern crate "yup-oauth2" as oauth2;
/// extern crate "rustc-serialize" as rustc_serialize;
/// extern crate youtube3;
///
/// # #[test] fn egal() {
/// use oauth2::{Authenticator, DefaultAuthenticatorDelegate, ApplicationSecret, MemoryStorage};
/// use std::default::Default;
///
/// use youtube3::YouTube;
///
/// // Get an ApplicationSecret instance by some means. It contains the `client_id` and `client_secret`,
/// // among other things.
/// let secret: ApplicationSecret = Default::default();
/// // Instantiate the authenticator. It will choose a suitable authentication flow for you,
/// // unless you replace `None` with the desired Flow
/// // Provide your own `AuthenticatorDelegate` to adjust the way it operates and get feedback about what's going on
/// // You probably want to bring in your own `TokenStorage` to persist tokens and retrieve them from storage.
/// let auth = Authenticator::new(&secret, DefaultAuthenticatorDelegate,
/// hyper::Client::new(),
/// <MemoryStorage as Default>::default(), None);
/// let mut hub = YouTube::new(hyper::Client::new(), auth);
/// # }
/// ```
///
pub struct YouTube<C, NC, A> {
client: RefCell<C>,
auth: RefCell<A>,
_m: PhantomData<NC>
}
impl<'a, C, NC, A> Hub for YouTube<C, NC, A> {}
impl<'a, C, NC, A> YouTube<C, NC, A>
where NC: hyper::net::NetworkConnector,
C: BorrowMut<hyper::Client<NC>> + 'a,
A: oauth2::GetToken {
pub fn new(client: C, authenticator: A) -> YouTube<C, NC, A> {
YouTube {
client: RefCell::new(client),
auth: RefCell::new(authenticator),
_m: PhantomData,
}
}
}
pub use cmn::{Resource, Part, ResponseResult, RequestResult, NestedType};
// ############
// SCHEMAS ###

View File

@@ -9,5 +9,5 @@
</%block>
The `${util.library_name()}` library allows access to all features of *${canonicalName}*.
${lib.docs(c)}
${lib.docs(c, rust_doc=False)}
<%lib:license />

View File

@@ -1,8 +1,12 @@
<%
from util import (iter_nested_types, new_context, rust_comment, rust_module_doc_comment, )
from util import (iter_nested_types, new_context, rust_comment, rust_doc_comment,
rust_module_doc_comment, rust_doc_test_norun, canonical_type_name,
rust_test_fn_invisible)
nested_schemas = list(iter_nested_types(schemas))
c = new_context(resources)
c = new_context(resources)
hub_type = canonical_type_name(canonicalName)
%>\
<%namespace name="lib" file="lib/lib.mako"/>\
<%namespace name="mutil" file="lib/util.mako"/>\
@@ -17,14 +21,54 @@ ${lib.docs(c)}
#![feature(core)]
#![allow(non_snake_case)]
extern crate hyper;
extern crate "rustc-serialize" as rustc_serialize;
extern crate "yup-oauth2" as oauth2;
mod cmn;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::borrow::BorrowMut;
use std::cell::RefCell;
pub use cmn::{Hub, Resource, Part, ResponseResult, RequestResult, NestedType};
// ########
// HUB ###
// ######
/// Central instance to access all ${hub_type} related resource activities
///
/// # Examples
///
/// Instantiate a new hub
///
<%block filter="rust_doc_comment">\
${lib.hub_usage_example()}\
</%block>
pub struct ${hub_type}<C, NC, A> {
client: RefCell<C>,
auth: RefCell<A>,
_m: PhantomData<NC>
}
impl<'a, C, NC, A> Hub for ${hub_type}<C, NC, A> {}
impl<'a, C, NC, A> ${hub_type}<C, NC, A>
where NC: hyper::net::NetworkConnector,
C: BorrowMut<hyper::Client<NC>> + 'a,
A: oauth2::GetToken {
pub fn new(client: C, authenticator: A) -> ${hub_type}<C, NC, A> {
${hub_type} {
client: RefCell::new(client),
auth: RefCell::new(authenticator),
_m: PhantomData,
}
}
}
pub use cmn::{Resource, Part, ResponseResult, RequestResult, NestedType};
// ############
// SCHEMAS ###

View File

@@ -1,7 +1,10 @@
<%! from util import (activity_split, put_and, md_italic, split_camelcase_s) %>\
<%! from util import (activity_split, put_and, md_italic, split_camelcase_s, canonical_type_name,
rust_test_fn_invisible, rust_doc_test_norun, rust_doc_comment, markdown_rust_block) %>\
<%namespace name="util" file="util.mako"/>\
<%def name="docs(c)">\
## If rust-doc is True, examples will be made to work for rust doc tests. Otherwise they are set
## for github markdown.
<%def name="docs(c, rust_doc=True)">\
<%
# fr == fattest resource, the fatter, the more important, right ?
fr = None
@@ -54,7 +57,7 @@ let r = hub.${resource}().${activity}(...).${api.terms.action}()
```
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
supports various methods to configure the impending operation (not shown here). 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.
@@ -62,15 +65,57 @@ The `${api.terms.action}()` method performs the actual communication with the se
${'##'} Instantiating the Hub
${self.hub_usage_example(rust_doc)}\
**TODO** Example calls - there should soon be a generator able to do that with proper inputs
${'##'} About error handling
${'##'} About costumization
${'##'} About Customization/Callbacks
[builder-pattern]: http://en.wikipedia.org/wiki/Builder_pattern
[google-go-api]: https://github.com/google/google-api-go-client
</%def>
## Sets up a hub ready for use. You must wrap it into a test function for it to work
## Needs test_prelude.
<%def name="test_hub(hub_type)">\
use oauth2::{Authenticator, DefaultAuthenticatorDelegate, ApplicationSecret, MemoryStorage};
use std::default::Default;
use ${util.library_name()}::${hub_type};
// Get an ApplicationSecret instance by some means. It contains the `client_id` and `client_secret`,
// among other things.
let secret: ApplicationSecret = Default::default();
// Instantiate the authenticator. It will choose a suitable authentication flow for you,
// unless you replace `None` with the desired Flow
// Provide your own `AuthenticatorDelegate` to adjust the way it operates and get feedback about what's going on
// You probably want to bring in your own `TokenStorage` to persist tokens and retrieve them from storage.
let auth = Authenticator::new(&secret, DefaultAuthenticatorDelegate,
hyper::Client::new(),
<MemoryStorage as Default>::default(), None);
let mut hub = ${hub_type}::new(hyper::Client::new(), auth);\
</%def>
## 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)">\
<%
test_filter = rust_test_fn_invisible
main_filter = rust_doc_test_norun
if not rust_doc:
test_filter = lambda s: s
main_filter = markdown_rust_block
%>\
<%block filter="main_filter">\
${util.test_prelude()}\
<%block filter="test_filter">\
${self.test_hub(canonical_type_name(canonicalName))}\
</%block>
</%block>
</%def>
<%def name="license()">\
# License
The **${util.library_name()}** library was generated by ${put_and(copyright.authors)}, and is placed

View File

@@ -21,4 +21,13 @@ ${cargo.repo_base_url}/${OUTPUT_DIR}\
<%def name="library_name()">\
${util.library_name(name, version)}\
</%def>
## All crates and standard `use` declaration, required for all examples
## Must be outside of a test function
<%def name="test_prelude()">\
extern crate hyper;
extern crate "yup-oauth2" as oauth2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate ${self.library_name()};
</%def>

View File

@@ -43,12 +43,27 @@ def rust_comment(s):
def hash_comment(s):
return re_linestart.sub('# ', s)
# return s, with trailing newline
def trailing_newline(s):
if not s.endswith('\n'):
return s + '\n'
return s
# a rust test that doesn't run though
def rust_doc_test_norun(s):
return "```test_harness,no_run\n%s```" % trailing_newline(s)
# a rust code block in (github) markdown
def markdown_rust_block(s):
return "```Rust\n%s```" % trailing_newline(s)
# wraps s into an invisible doc test function.
def rust_test_fn_invisible(s):
return "# #[test] fn egal() {\n%s# }" % trailing_newline(s)
# markdown comments
def markdown_comment(s):
nl = ''
if not s.endswith('\n'):
nl = '\n'
return "<!---\n%s%s-->" % (s, nl)
return "<!---\n%s-->" % trailing_newline(s)
# escape each string in l with "s" and return the new list
def estr(l):
@@ -84,7 +99,10 @@ def split_camelcase_s(s):
# ------------------------------------------------------------------------------
## @{
# Return transformed string that could make a good type name
def canonical_type_name(s):
# can't use s.capitalize() as it will lower-case the remainder of the string
return s[:1].upper() + s[1:]
def nested_type_name(sn, pn):
return sn + pn.capitalize()
@@ -194,7 +212,7 @@ def schema_markers(s, c):
# Returns (A, B) where
# A: { SchemaTypeName -> { fqan -> ['request'|'response', ...]}
# B: { fqan -> activity_method }
# B: { fqan -> activity_method_data }
# fqan = fully qualified activity name
def build_activity_mappings(activities):
res = dict()
@@ -239,6 +257,10 @@ def activity_split(fqan):
def activity_name_to_type_name(an):
return an.capitalize()[:-1]
# yields (resource, activity, activity_data)
def iter_acitivities(c):
return ((activity_split(an) + [a]) for an, a in c.fqan_map.iteritems())
## -- End Activity Utilities -- @}

View File

@@ -1,5 +1,10 @@
use std::marker::MarkerTrait;
/// Identifies the Hub. There is only one per library, this trait is supposed
/// to make intended use more explicit.
/// The hub allows to access all resource methods more easily.
pub trait Hub: 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 {}