Use doc comments instead of the doc attribute in the changelog examples ()

This commit is contained in:
Georg Semmler 2018-11-11 23:58:50 +01:00 committed by Christian Legnitto
parent 0f2a654471
commit 4ecf558066
6 changed files with 102 additions and 118 deletions
changelog
juniper/src

View file

@ -57,13 +57,13 @@
} }
// New alternative syntax for field descriptions // New alternative syntax for field descriptions
#[doc = "Description"] /// Description
field my_field() -> { ... } field my_field() -> { ... }
// New alternative syntax for argument descriptions // New alternative syntax for argument descriptions
field my_field( field my_field(
#[doc = "The number of starfish to be returned. \ /// The number of starfish to be returned.
Can't be more than 100."] /// Can't be more than 100.
arg: i32, arg: i32,
) -> { ) -> {
... ...
@ -73,12 +73,11 @@
// //
// Multiple docstrings will be collapsed into a single // Multiple docstrings will be collapsed into a single
// description separated by newlines. // description separated by newlines.
#[doc = r#" /// This is my field.
This is my field. ///
/// Make sure not to filtz the bitlet.
Make sure not to flitz the bitlet. /// Flitzing without a bitlet has undefined behaviour.
Flitzing without a bitlet has undefined behaviour. ///
"]
#[doc = my_consts::ADDED_IN_VERSION_XYZ] #[doc = my_consts::ADDED_IN_VERSION_XYZ]
field my_field() -> { ... } field my_field() -> { ... }
``` ```

View file

@ -677,7 +677,7 @@ macro_rules! __juniper_create_arg {
$info, $info,
) )
$(.description($arg_description))* $(.description($arg_description))*
$(.push_docstring($arg_docstring))* .push_docstring(&[$($arg_docstring,)*])
}; };
( (
@ -695,6 +695,6 @@ macro_rules! __juniper_create_arg {
$info, $info,
) )
$(.description($arg_description))* $(.description($arg_description))*
$(.push_docstring($arg_docstring))* .push_docstring(&[$($arg_docstring,)*])
}; };
} }

View file

@ -153,7 +153,7 @@ macro_rules! graphql_interface {
info info
) )
$(.description($fn_description))* $(.description($fn_description))*
$(.push_docstring($docstring))* .push_docstring(&[$($docstring,)*])
$(.deprecated($deprecated))* $(.deprecated($deprecated))*
$(.argument( $(.argument(
__juniper_create_arg!( __juniper_create_arg!(

View file

@ -35,8 +35,11 @@ graphql_object!(User: () |&self| {
## Documentation and descriptions ## Documentation and descriptions
You can optionally add descriptions to the type itself, the fields, and field You can optionally add descriptions to the type itself, the fields,
arguments: and field arguments. For field and argument descriptions it is
possible to use normal rustdoc comments or doc
attributes. Alternatively the same syntax as for the type could be
used
```rust ```rust
# #[macro_use] extern crate juniper; # #[macro_use] extern crate juniper;
@ -45,7 +48,9 @@ struct User { id: String, name: String, group_ids: Vec<String> }
graphql_object!(User: () |&self| { graphql_object!(User: () |&self| {
description: "A user in the database" description: "A user in the database"
field id() -> &String as "The user's unique identifier" {
/// The user's unique identifier
field id() -> &String {
&self.id &self.id
} }
@ -53,47 +58,11 @@ graphql_object!(User: () |&self| {
&self.name &self.name
} }
#[doc = "Test if a user is member of a group"]
field member_of_group( field member_of_group(
group_id: String as "The group id you want to test membership against" /// The group id you want to test membership against
) -> bool as "Test if a user is member of a group" { /// second line
self.group_ids.iter().any(|gid| gid == &group_id) group_id: String
}
});
# fn main() { }
```
**Alternatively,** descriptions can be added with the builtin `doc` attribute.
Consecutive `#[doc = "..."]` attributes will be collapsed into a single description
where the docstrings are separated by newlines.
```rust
# #[macro_use] extern crate juniper;
struct User { id: String, name: String, group_ids: Vec<String> }
graphql_object!(User: () |&self| {
description: "A user in the database"
#[doc = "The user's unique identifier"]
field id() -> &String {
&self.id
}
#[doc = "The user's name"]
field name() -> &String {
&self.name
}
#[doc = r#"
Test if a user is member of a group.
This may return a flitzbit if the floop is twizled.
Make sure not to rumblejumble the cog-rotater.
"#]
#[doc = "Added in vX.Y.44"]
field member_of_group(
#[doc = "The group id you want to test membership against"]
group_id: String,
) -> bool { ) -> bool {
self.group_ids.iter().any(|gid| gid == &group_id) self.group_ids.iter().any(|gid| gid == &group_id)
} }
@ -275,16 +244,19 @@ A field's description and deprecation can also be set using the
builtin `doc` and `deprecated` attributes. builtin `doc` and `deprecated` attributes.
```text ```text
#[doc = "Field description"] /// Field description
field name(args...) -> Type { } field name(args...) -> Type { }
#[doc = "Field description"]
field name(args...) -> Type {}
#[deprecated] // no reason required #[deprecated] // no reason required
field name(args...) -> Type { } field name(args...) -> Type { }
#[deprecated(note = "Reason")] #[deprecated(note = "Reason")]
field name(args...) -> Type { } field name(args...) -> Type { }
#[doc = "Field description"] /// Field description
#[deprecated(note = "Reason")] // deprecated must come after doc #[deprecated(note = "Reason")] // deprecated must come after doc
field deprecated "Reason" name(args...) -> Type { } field deprecated "Reason" name(args...) -> Type { }
``` ```
@ -326,9 +298,11 @@ arg_name = (Point { x: 1, y: 2 }): Point
arg_name = ("default".to_owned()): String arg_name = ("default".to_owned()): String
``` ```
A description can also be provided using the builtin `doc` attribute. A description can also be provided using normal doc comments or doc attributes.
```text ```text
/// Argument description
arg_name: ArgType
#[doc = "Argument description"] #[doc = "Argument description"]
arg_name: ArgType arg_name: ArgType
``` ```
@ -391,7 +365,7 @@ macro_rules! graphql_object {
info info
) )
$(.description($fn_description))* $(.description($fn_description))*
$(.push_docstring($docstring))* .push_docstring(&[$($docstring,)*])
$(.deprecated($deprecated))* $(.deprecated($deprecated))*
$(.argument( $(.argument(
__juniper_create_arg!( __juniper_create_arg!(

View file

@ -31,19 +31,18 @@ graphql_object!(Root: () |&self| {
field deprecated "Deprecation reason" field deprecated "Deprecation reason"
deprecated_descr() -> i32 as "Field description" { 0 } deprecated_descr() -> i32 as "Field description" { 0 }
#[doc = "Field description"] /// Field description
field attr_description() -> i32 { 0 } field attr_description() -> i32 { 0 }
#[doc = "Field description"] /// Field description
#[doc = "with `collapse_docs` behavior"] // https://doc.rust-lang.org/rustdoc/the-doc-attribute.html /// with `collapse_docs` behavior
field attr_description_collapse() -> i32 { 0 } field attr_description_collapse() -> i32 { 0 }
#[doc = r#" /// Get the i32 representation of 0.
Get the i32 representation of 0. ///
/// - This comment is longer.
- This comment is longer. /// - These two lines are rendered as bullets by GraphiQL.
- These two lines are rendered as bullets by GraphiQL. /// - subsection
"#]
field attr_description_long() -> i32 { 0 } field attr_description_long() -> i32 { 0 }
#[deprecated] #[deprecated]
@ -52,7 +51,7 @@ graphql_object!(Root: () |&self| {
#[deprecated(note = "Deprecation reason")] #[deprecated(note = "Deprecation reason")]
field attr_deprecated_reason() -> i32 { 0 } field attr_deprecated_reason() -> i32 { 0 }
#[doc = "Field description"] /// Field description
#[deprecated(note = "Deprecation reason")] #[deprecated(note = "Deprecation reason")]
field attr_deprecated_descr() -> i32 { 0 } field attr_deprecated_descr() -> i32 { 0 }
@ -76,19 +75,17 @@ graphql_interface!(Interface: () |&self| {
field deprecated "Deprecation reason" field deprecated "Deprecation reason"
deprecated_descr() -> i32 as "Field description" { 0 } deprecated_descr() -> i32 as "Field description" { 0 }
#[doc = "Field description"] /// Field description
field attr_description() -> i32 { 0 } field attr_description() -> i32 { 0 }
#[doc = "Field description"] /// Field description
#[doc = "with `collapse_docs` behavior"] // https://doc.rust-lang.org/rustdoc/the-doc-attribute.html /// with `collapse_docs` behavior
field attr_description_collapse() -> i32 { 0 } field attr_description_collapse() -> i32 { 0 }
#[doc = r#" /// Get the i32 representation of 0.
Get the i32 representation of 0. ///
/// - This comment is longer.
- This comment is longer. /// - These two lines are rendered as bullets by GraphiQL.
- These two lines are rendered as bullets by GraphiQL.
"#]
field attr_description_long() -> i32 { 0 } field attr_description_long() -> i32 { 0 }
#[deprecated] #[deprecated]
@ -97,7 +94,7 @@ graphql_interface!(Interface: () |&self| {
#[deprecated(note = "Deprecation reason")] #[deprecated(note = "Deprecation reason")]
field attr_deprecated_reason() -> i32 { 0 } field attr_deprecated_reason() -> i32 { 0 }
#[doc = "Field description"] /// Field description
#[deprecated(note = "Deprecation reason")] #[deprecated(note = "Deprecation reason")]
field attr_deprecated_descr() -> i32 { 0 } field attr_deprecated_descr() -> i32 { 0 }
@ -384,7 +381,7 @@ fn introspect_object_field_attr_description_long() {
); );
assert_eq!( assert_eq!(
field.get_field_value("description"), field.get_field_value("description"),
Some(&Value::scalar("Get the i32 representation of 0.\n\n- This comment is longer.\n- These two lines are rendered as bullets by GraphiQL.")) Some(&Value::scalar("Get the i32 representation of 0.\n\n- This comment is longer.\n- These two lines are rendered as bullets by GraphiQL.\n - subsection"))
); );
assert_eq!( assert_eq!(
field.get_field_value("isDeprecated"), field.get_field_value("isDeprecated"),

View file

@ -613,15 +613,16 @@ impl<'a, S> Field<'a, S> {
/// ///
/// If the description hasn't been set, the description is set to the provided line. /// If the description hasn't been set, the description is set to the provided line.
/// Otherwise, the doc string is added to the current description after a newline. /// Otherwise, the doc string is added to the current description after a newline.
pub fn push_docstring(mut self, multiline: &str) -> Field<'a, S> { pub fn push_docstring(mut self, multiline: &[&str]) -> Field<'a, S> {
let docstring = clean_docstring(multiline); if let Some(docstring) = clean_docstring(multiline) {
match &mut self.description { match &mut self.description {
&mut Some(ref mut desc) => { &mut Some(ref mut desc) => {
desc.push('\n'); desc.push('\n');
desc.push_str(&docstring); desc.push_str(&docstring);
} }
desc @ &mut None => { desc @ &mut None => {
*desc = Some(docstring.to_string()); *desc = Some(docstring);
}
} }
} }
self self
@ -679,15 +680,16 @@ impl<'a, S> Argument<'a, S> {
/// ///
/// If the description hasn't been set, the description is set to the provided line. /// If the description hasn't been set, the description is set to the provided line.
/// Otherwise, the doc string is added to the current description after a newline. /// Otherwise, the doc string is added to the current description after a newline.
pub fn push_docstring(mut self, multiline: &str) -> Argument<'a, S> { pub fn push_docstring(mut self, multiline: &[&str]) -> Argument<'a, S> {
let docstring = clean_docstring(multiline); if let Some(docstring) = clean_docstring(multiline) {
match &mut self.description { match &mut self.description {
&mut Some(ref mut desc) => { &mut Some(ref mut desc) => {
desc.push('\n'); desc.push('\n');
desc.push_str(&docstring); desc.push_str(&docstring);
} }
desc @ &mut None => { desc @ &mut None => {
*desc = Some(docstring.to_string()); *desc = Some(docstring)
}
} }
} }
self self
@ -766,26 +768,38 @@ where
<T as FromInputValue<S>>::from_input_value(v).is_some() <T as FromInputValue<S>>::from_input_value(v).is_some()
} }
fn clean_docstring<'a>(multiline: &'a str) -> Cow<'a, str> { fn clean_docstring(multiline: &[&str]) -> Option<String> {
let trim_start = multiline.split('\n') if multiline.is_empty() {
.skip(1) return None;
.filter_map(|ln| ln.chars().position(|ch| ch != ' ' && ch != '\t')) }
.min(); let trim_start = multiline
if let Some(trim) = trim_start { .iter()
let trimmed = multiline .filter_map(|ln| ln.chars().position(|ch| !ch.is_whitespace()))
.split('\n') .min()
.map(|ln| { .unwrap_or(0);
if !ln.starts_with(' ') && !ln.starts_with('\t') { Some(
ln // skip trimming the first line multiline
} else if ln.len() >= trim { .iter()
&ln[trim..] .enumerate()
.flat_map(|(line, ln)| {
let new_ln = if !ln
.chars()
.next()
.map(|ch| ch.is_whitespace())
.unwrap_or(false)
{
ln.trim_end() // skip trimming the first line
} else if ln.len() >= trim_start {
&ln[trim_start..].trim_end()
} else { } else {
"" ""
} };
}) new_ln.chars().chain(
.collect::<Vec<_>>(); ['\n']
Cow::from(trimmed.join("\n").trim_matches('\n').to_owned()) .iter()
} else { .take_while(move |_| line < multiline.len() - 1)
Cow::from(multiline.trim_matches('\n')) .cloned(),
} )
}).collect::<String>(),
)
} }