Remove `HttpSend` and `HttpSender`

this was maybe a good idea, but it isn't really needed
master
Paul Woolcock 4 years ago
parent cfe810be4e
commit d66c63dd28
  1. 2
      README.md
  2. 4
      src/apps.rs
  3. 14
      src/entities/itemsiter.rs
  4. 4
      src/helpers/cli.rs
  5. 26
      src/http_send.rs
  6. 72
      src/lib.rs
  7. 6
      src/macros.rs
  8. 57
      src/mastodon_client.rs
  9. 32
      src/page.rs
  10. 50
      src/registration.rs
  11. 2
      src/requests/filter.rs
  12. 14
      src/scopes.rs

@ -76,7 +76,7 @@ use elefren::entities::event::Event;
use std::error::Error; use std::error::Error;
fn main() -> Result<(), Box<Error>> { fn main() -> Result<(), Box<dyn Error>> {
let data = Data { let data = Data {
base: "".into(), base: "".into(),
client_id: "".into(), client_id: "".into(),

@ -61,7 +61,7 @@ impl App {
/// use elefren::apps::App; /// use elefren::apps::App;
/// use std::error::Error; /// use std::error::Error;
/// ///
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let mut builder = App::builder(); /// let mut builder = App::builder();
/// builder.client_name("elefren_test"); /// builder.client_name("elefren_test");
/// let app = builder.build()?; /// let app = builder.build()?;
@ -120,7 +120,7 @@ impl<'a> AppBuilder<'a> {
Ok(App { Ok(App {
client_name: self client_name: self
.client_name .client_name
.ok_or_else(|| Error::MissingField("client_name"))? .ok_or(Error::MissingField("client_name"))?
.into(), .into(),
redirect_uris: self redirect_uris: self
.redirect_uris .redirect_uris

@ -1,4 +1,4 @@
use crate::{http_send::HttpSend, page::Page}; use crate::page::Page;
use serde::Deserialize; use serde::Deserialize;
/// Abstracts away the `next_page` logic into a single stream of items /// Abstracts away the `next_page` logic into a single stream of items
@ -7,7 +7,7 @@ use serde::Deserialize;
/// # extern crate elefren; /// # extern crate elefren;
/// # use elefren::prelude::*; /// # use elefren::prelude::*;
/// # use std::error::Error; /// # use std::error::Error;
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data { /// # let data = Data {
/// # base: "".into(), /// # base: "".into(),
/// # client_id: "".into(), /// # client_id: "".into(),
@ -24,15 +24,15 @@ use serde::Deserialize;
/// # } /// # }
/// ``` /// ```
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct ItemsIter<'a, T: Clone + for<'de> Deserialize<'de>, H: 'a + HttpSend> { pub(crate) struct ItemsIter<'a, T: Clone + for<'de> Deserialize<'de>> {
page: Page<'a, T, H>, page: Page<'a, T>,
buffer: Vec<T>, buffer: Vec<T>,
cur_idx: usize, cur_idx: usize,
use_initial: bool, use_initial: bool,
} }
impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> ItemsIter<'a, T, H> { impl<'a, T: Clone + for<'de> Deserialize<'de>> ItemsIter<'a, T> {
pub(crate) fn new(page: Page<'a, T, H>) -> ItemsIter<'a, T, H> { pub(crate) fn new(page: Page<'a, T>) -> ItemsIter<'a, T> {
ItemsIter { ItemsIter {
page, page,
buffer: vec![], buffer: vec![],
@ -64,7 +64,7 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> ItemsIter<'a, T, H>
} }
} }
impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Iterator for ItemsIter<'a, T, H> { impl<'a, T: Clone + for<'de> Deserialize<'de>> Iterator for ItemsIter<'a, T> {
type Item = T; type Item = T;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {

@ -1,10 +1,10 @@
use std::io::{self, BufRead, Write}; use std::io::{self, BufRead, Write};
use crate::{errors::Result, http_send::HttpSend, registration::Registered, Mastodon}; use crate::{errors::Result, registration::Registered, Mastodon};
/// Finishes the authentication process for the given `Registered` object, /// Finishes the authentication process for the given `Registered` object,
/// using the command-line /// using the command-line
pub fn authenticate<H: HttpSend>(registration: Registered<H>) -> Result<Mastodon<H>> { pub fn authenticate(registration: Registered) -> Result<Mastodon> {
let url = registration.authorize_url()?; let url = registration.authorize_url()?;
let stdout = io::stdout(); let stdout = io::stdout();

@ -1,26 +0,0 @@
use crate::Result;
use reqwest::{Client, Request, RequestBuilder, Response};
use std::fmt::Debug;
/// Abstracts away the process of turning an HTTP request into an HTTP response
pub trait HttpSend: Clone + Debug {
/// Converts an HTTP request into an HTTP response
fn execute(&self, client: &Client, request: Request) -> Result<Response>;
/// Convenience method so that .build() doesn't have to be called at every
/// call site
fn send(&self, client: &Client, builder: RequestBuilder) -> Result<Response> {
let request = builder.build()?;
self.execute(client, request)
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct HttpSender;
impl HttpSend for HttpSender {
fn execute(&self, client: &Client, request: Request) -> Result<Response> {
Ok(client.execute(request)?)
}
}

@ -36,7 +36,7 @@
//! # use elefren::prelude::*; //! # use elefren::prelude::*;
//! # use std::error::Error; //! # use std::error::Error;
//! use elefren::entities::event::Event; //! use elefren::entities::event::Event;
//! # fn main() -> Result<(), Box<Error>> { //! # fn main() -> Result<(), Box<dyn Error>> {
//! # let data = Data { //! # let data = Data {
//! # base: "".into(), //! # base: "".into(),
//! # client_id: "".into(), //! # client_id: "".into(),
@ -77,11 +77,7 @@ use reqwest::{Client, RequestBuilder, Response};
use tap_reader::Tap; use tap_reader::Tap;
use tungstenite::client::AutoStream; use tungstenite::client::AutoStream;
use crate::{ use crate::{entities::prelude::*, page::Page};
entities::prelude::*,
http_send::{HttpSend, HttpSender},
page::Page,
};
pub use crate::{ pub use crate::{
data::Data, data::Data,
@ -110,8 +106,6 @@ pub mod entities;
pub mod errors; pub mod errors;
/// Collection of helpers for serializing/deserializing `Data` objects /// Collection of helpers for serializing/deserializing `Data` objects
pub mod helpers; pub mod helpers;
/// Contains trait for converting `reqwest::Request`s to `reqwest::Response`s
pub mod http_send;
mod mastodon_client; mod mastodon_client;
/// Constructing media attachments for a status. /// Constructing media attachments for a status.
pub mod media_builder; pub mod media_builder;
@ -143,14 +137,13 @@ pub mod prelude {
/// Your mastodon application client, handles all requests to and from Mastodon. /// Your mastodon application client, handles all requests to and from Mastodon.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Mastodon<H: HttpSend = HttpSender> { pub struct Mastodon {
client: Client, client: Client,
http_sender: H,
/// Raw data about your mastodon instance. /// Raw data about your mastodon instance.
pub data: Data, pub data: Data,
} }
impl<H: HttpSend> Mastodon<H> { impl Mastodon {
methods![get, post, delete,]; methods![get, post, delete,];
fn route(&self, url: &str) -> String { fn route(&self, url: &str) -> String {
@ -158,16 +151,15 @@ impl<H: HttpSend> Mastodon<H> {
} }
pub(crate) fn send(&self, req: RequestBuilder) -> Result<Response> { pub(crate) fn send(&self, req: RequestBuilder) -> Result<Response> {
Ok(self let request = req.bearer_auth(&self.token).build()?;
.http_sender Ok(self.client.execute(request)?)
.send(&self.client, req.bearer_auth(&self.token))?)
} }
} }
impl From<Data> for Mastodon<HttpSender> { impl From<Data> for Mastodon {
/// Creates a mastodon instance from the data struct. /// Creates a mastodon instance from the data struct.
fn from(data: Data) -> Mastodon<HttpSender> { fn from(data: Data) -> Mastodon {
let mut builder = MastodonBuilder::new(HttpSender); let mut builder = MastodonBuilder::new();
builder.data(data); builder.data(data);
builder builder
.build() .build()
@ -175,7 +167,7 @@ impl From<Data> for Mastodon<HttpSender> {
} }
} }
impl<H: HttpSend> MastodonClient<H> for Mastodon<H> { impl MastodonClient for Mastodon {
type Stream = EventReader<WebSocket>; type Stream = EventReader<WebSocket>;
paged_routes! { paged_routes! {
@ -307,7 +299,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// Get timeline filtered by a hashtag(eg. `#coffee`) either locally or /// Get timeline filtered by a hashtag(eg. `#coffee`) either locally or
/// federated. /// federated.
fn get_hashtag_timeline(&self, hashtag: &str, local: bool) -> Result<Page<Status, H>> { fn get_hashtag_timeline(&self, hashtag: &str, local: bool) -> Result<Page<Status>> {
let base = "/api/v1/timelines/tag/"; let base = "/api/v1/timelines/tag/";
let url = if local { let url = if local {
self.route(&format!("{}{}?local=1", base, hashtag)) self.route(&format!("{}{}?local=1", base, hashtag))
@ -327,7 +319,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// # extern crate elefren; /// # extern crate elefren;
/// # use elefren::prelude::*; /// # use elefren::prelude::*;
/// # use std::error::Error; /// # use std::error::Error;
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data { /// # let data = Data {
/// # base: "".into(), /// # base: "".into(),
/// # client_id: "".into(), /// # client_id: "".into(),
@ -345,7 +337,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// # extern crate elefren; /// # extern crate elefren;
/// # use elefren::prelude::*; /// # use elefren::prelude::*;
/// # use std::error::Error; /// # use std::error::Error;
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data { /// # let data = Data {
/// # base: "".into(), /// # base: "".into(),
/// # client_id: "".into(), /// # client_id: "".into(),
@ -360,7 +352,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status, H>> fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status>>
where where
S: Into<Option<StatusesRequest<'a>>>, S: Into<Option<StatusesRequest<'a>>>,
{ {
@ -377,7 +369,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// Returns the client account's relationship to a list of other accounts. /// Returns the client account's relationship to a list of other accounts.
/// Such as whether they follow them or vice versa. /// Such as whether they follow them or vice versa.
fn relationships(&self, ids: &[&str]) -> Result<Page<Relationship, H>> { fn relationships(&self, ids: &[&str]) -> Result<Page<Relationship>> {
let mut url = self.route("/api/v1/accounts/relationships?"); let mut url = self.route("/api/v1/accounts/relationships?");
if ids.len() == 1 { if ids.len() == 1 {
@ -423,13 +415,13 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
} }
/// Get all accounts that follow the authenticated user /// Get all accounts that follow the authenticated user
fn follows_me(&self) -> Result<Page<Account, H>> { fn follows_me(&self) -> Result<Page<Account>> {
let me = self.verify_credentials()?; let me = self.verify_credentials()?;
Ok(self.followers(&me.id)?) Ok(self.followers(&me.id)?)
} }
/// Get all accounts that the authenticated user follows /// Get all accounts that the authenticated user follows
fn followed_by_me(&self) -> Result<Page<Account, H>> { fn followed_by_me(&self) -> Result<Page<Account>> {
let me = self.verify_credentials()?; let me = self.verify_credentials()?;
Ok(self.following(&me.id)?) Ok(self.following(&me.id)?)
} }
@ -444,7 +436,7 @@ impl<H: HttpSend> MastodonClient<H> for Mastodon<H> {
/// # use elefren::prelude::*; /// # use elefren::prelude::*;
/// # use std::error::Error; /// # use std::error::Error;
/// use elefren::entities::event::Event; /// use elefren::entities::event::Event;
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data { /// # let data = Data {
/// # base: "".into(), /// # base: "".into(),
/// # client_id: "".into(), /// # client_id: "".into(),
@ -737,7 +729,7 @@ impl<R: EventStream> EventReader<R> {
} }
} }
impl<H: HttpSend> ops::Deref for Mastodon<H> { impl ops::Deref for Mastodon {
type Target = Data; type Target = Data;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -745,16 +737,14 @@ impl<H: HttpSend> ops::Deref for Mastodon<H> {
} }
} }
struct MastodonBuilder<H: HttpSend> { struct MastodonBuilder {
client: Option<Client>, client: Option<Client>,
http_sender: H,
data: Option<Data>, data: Option<Data>,
} }
impl<H: HttpSend> MastodonBuilder<H> { impl MastodonBuilder {
pub fn new(sender: H) -> Self { pub fn new() -> Self {
MastodonBuilder { MastodonBuilder {
http_sender: sender,
client: None, client: None,
data: None, data: None,
} }
@ -770,11 +760,10 @@ impl<H: HttpSend> MastodonBuilder<H> {
self self
} }
pub fn build(self) -> Result<Mastodon<H>> { pub fn build(self) -> Result<Mastodon> {
Ok(if let Some(data) = self.data { Ok(if let Some(data) = self.data {
Mastodon { Mastodon {
client: self.client.unwrap_or_else(Client::new), client: self.client.unwrap_or_else(Client::new),
http_sender: self.http_sender,
data, data,
} }
} else { } else {
@ -785,15 +774,14 @@ impl<H: HttpSend> MastodonBuilder<H> {
/// Client that can make unauthenticated calls to a mastodon instance /// Client that can make unauthenticated calls to a mastodon instance
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MastodonUnauth<H: HttpSend = HttpSender> { pub struct MastodonUnauth {
client: Client, client: Client,
http_sender: H,
base: url::Url, base: url::Url,
} }
impl MastodonUnauth<HttpSender> { impl MastodonUnauth {
/// Create a new unauthenticated client /// Create a new unauthenticated client
pub fn new(base: &str) -> Result<MastodonUnauth<HttpSender>> { pub fn new(base: &str) -> Result<MastodonUnauth> {
let base = if base.starts_with("https://") { let base = if base.starts_with("https://") {
base.to_string() base.to_string()
} else { } else {
@ -801,19 +789,19 @@ impl MastodonUnauth<HttpSender> {
}; };
Ok(MastodonUnauth { Ok(MastodonUnauth {
client: Client::new(), client: Client::new(),
http_sender: HttpSender,
base: url::Url::parse(&base)?, base: url::Url::parse(&base)?,
}) })
} }
} }
impl<H: HttpSend> MastodonUnauth<H> { impl MastodonUnauth {
fn route(&self, url: &str) -> Result<url::Url> { fn route(&self, url: &str) -> Result<url::Url> {
Ok(self.base.join(url)?) Ok(self.base.join(url)?)
} }
fn send(&self, req: RequestBuilder) -> Result<Response> { fn send(&self, req: RequestBuilder) -> Result<Response> {
Ok(self.http_sender.send(&self.client, req)?) let req = req.build()?;
Ok(self.client.execute(req)?)
} }
/// Get a stream of the public timeline /// Get a stream of the public timeline
@ -835,7 +823,7 @@ impl<H: HttpSend> MastodonUnauth<H> {
} }
} }
impl<H: HttpSend> MastodonUnauthenticated<H> for MastodonUnauth<H> { impl MastodonUnauthenticated for MastodonUnauth {
/// GET /api/v1/statuses/:id /// GET /api/v1/statuses/:id
fn get_status(&self, id: &str) -> Result<Status> { fn get_status(&self, id: &str) -> Result<Status> {
let route = self.route("/api/v1/statuses")?; let route = self.route("/api/v1/statuses")?;

@ -40,7 +40,7 @@ macro_rules! paged_routes {
"# }\n", "# }\n",
"```" "```"
), ),
fn $name(&self) -> Result<Page<$ret, H>> { fn $name(&self) -> Result<Page<$ret>> {
let url = self.route(concat!("/api/v1/", $url)); let url = self.route(concat!("/api/v1/", $url));
let response = self.send( let response = self.send(
self.client.$method(&url) self.client.$method(&url)
@ -61,7 +61,7 @@ macro_rules! paged_routes {
$url, $url,
"`\n# Errors\nIf `access_token` is not set." "`\n# Errors\nIf `access_token` is not set."
), ),
fn $name<'a>(&self, $($param: $typ,)*) -> Result<Page<$ret, H>> { fn $name<'a>(&self, $($param: $typ,)*) -> Result<Page<$ret>> {
use serde_urlencoded; use serde_urlencoded;
use serde::Serialize; use serde::Serialize;
@ -315,7 +315,7 @@ macro_rules! paged_routes_with_id {
"# }\n", "# }\n",
"```" "```"
), ),
fn $name(&self, id: &str) -> Result<Page<$ret, H>> { fn $name(&self, id: &str) -> Result<Page<$ret>> {
let url = self.route(&format!(concat!("/api/v1/", $url), id)); let url = self.route(&format!(concat!("/api/v1/", $url), id));
let response = self.send( let response = self.send(
self.client.$method(&url) self.client.$method(&url)

@ -3,7 +3,6 @@ use std::borrow::Cow;
use crate::{ use crate::{
entities::prelude::*, entities::prelude::*,
errors::Result, errors::Result,
http_send::{HttpSend, HttpSender},
media_builder::MediaBuilder, media_builder::MediaBuilder,
page::Page, page::Page,
requests::{ requests::{
@ -19,60 +18,60 @@ use crate::{
/// Represents the set of methods that a Mastodon Client can do, so that /// Represents the set of methods that a Mastodon Client can do, so that
/// implementations might be swapped out for testing /// implementations might be swapped out for testing
#[allow(unused)] #[allow(unused)]
pub trait MastodonClient<H: HttpSend = HttpSender> { pub trait MastodonClient {
/// Type that wraps streaming API streams /// Type that wraps streaming API streams
type Stream: Iterator<Item = Event>; type Stream: Iterator<Item = Event>;
/// GET /api/v1/favourites /// GET /api/v1/favourites
fn favourites(&self) -> Result<Page<Status, H>> { fn favourites(&self) -> Result<Page<Status>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/blocks /// GET /api/v1/blocks
fn blocks(&self) -> Result<Page<Account, H>> { fn blocks(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/domain_blocks /// GET /api/v1/domain_blocks
fn domain_blocks(&self) -> Result<Page<String, H>> { fn domain_blocks(&self) -> Result<Page<String>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/follow_requests /// GET /api/v1/follow_requests
fn follow_requests(&self) -> Result<Page<Account, H>> { fn follow_requests(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/timelines/home /// GET /api/v1/timelines/home
fn get_home_timeline(&self) -> Result<Page<Status, H>> { fn get_home_timeline(&self) -> Result<Page<Status>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/custom_emojis /// GET /api/v1/custom_emojis
fn get_emojis(&self) -> Result<Page<Emoji, H>> { fn get_emojis(&self) -> Result<Page<Emoji>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/mutes /// GET /api/v1/mutes
fn mutes(&self) -> Result<Page<Account, H>> { fn mutes(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/notifications /// GET /api/v1/notifications
fn notifications(&self) -> Result<Page<Notification, H>> { fn notifications(&self) -> Result<Page<Notification>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/reports /// GET /api/v1/reports
fn reports(&self) -> Result<Page<Report, H>> { fn reports(&self) -> Result<Page<Report>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/accounts/:id/followers /// GET /api/v1/accounts/:id/followers
fn followers(&self, id: &str) -> Result<Page<Account, H>> { fn followers(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/accounts/:id/following /// GET /api/v1/accounts/:id/following
fn following(&self, id: &str) -> Result<Page<Account, H>> { fn following(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/statuses/:id/reblogged_by /// GET /api/v1/statuses/:id/reblogged_by
fn reblogged_by(&self, id: &str) -> Result<Page<Account, H>> { fn reblogged_by(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/statuses/:id/favourited_by /// GET /api/v1/statuses/:id/favourited_by
fn favourited_by(&self, id: &str) -> Result<Page<Account, H>> { fn favourited_by(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// DELETE /api/v1/domain_blocks /// DELETE /api/v1/domain_blocks
@ -200,26 +199,26 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/timelines/public?local=true /// GET /api/v1/timelines/public?local=true
fn get_local_timeline(&self) -> Result<Page<Status, H>> { fn get_local_timeline(&self) -> Result<Page<Status>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/timelines/public?local=false /// GET /api/v1/timelines/public?local=false
fn get_federated_timeline(&self) -> Result<Page<Status, H>> { fn get_federated_timeline(&self) -> Result<Page<Status>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/timelines/tag/:hashtag /// GET /api/v1/timelines/tag/:hashtag
fn get_hashtag_timeline(&self, hashtag: &str, local: bool) -> Result<Page<Status, H>> { fn get_hashtag_timeline(&self, hashtag: &str, local: bool) -> Result<Page<Status>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/accounts/:id/statuses /// GET /api/v1/accounts/:id/statuses
fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status, H>> fn statuses<'a, 'b: 'a, S>(&'b self, id: &'b str, request: S) -> Result<Page<Status>>
where where
S: Into<Option<StatusesRequest<'a>>>, S: Into<Option<StatusesRequest<'a>>>,
{ {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/accounts/relationships /// GET /api/v1/accounts/relationships
fn relationships(&self, ids: &[&str]) -> Result<Page<Relationship, H>> { fn relationships(&self, ids: &[&str]) -> Result<Page<Relationship>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/accounts/search?q=:query&limit=:limit&following=:following /// GET /api/v1/accounts/search?q=:query&limit=:limit&following=:following
@ -228,7 +227,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
query: &str, query: &str,
limit: Option<u64>, limit: Option<u64>,
following: bool, following: bool,
) -> Result<Page<Account, H>> { ) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// POST /api/v1/push/subscription /// POST /api/v1/push/subscription
@ -276,7 +275,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/endorsements /// GET /api/v1/endorsements
fn get_endorsements(&self) -> Result<Page<Account, H>> { fn get_endorsements(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// POST /api/v1/accounts/:id/pin /// POST /api/v1/accounts/:id/pin
@ -293,7 +292,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
/// # extern crate elefren; /// # extern crate elefren;
/// # use std::error::Error; /// # use std::error::Error;
/// # use elefren::prelude::*; /// # use elefren::prelude::*;
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data { /// # let data = Data {
/// # base: "".into(), /// # base: "".into(),
/// # client_id: "".into(), /// # client_id: "".into(),
@ -305,7 +304,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
/// let follows_me = client.follows_me()?; /// let follows_me = client.follows_me()?;
/// # Ok(()) /// # Ok(())
/// # } /// # }
fn follows_me(&self) -> Result<Page<Account, H>> { fn follows_me(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// Shortcut for /// Shortcut for
@ -315,7 +314,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
/// # extern crate elefren; /// # extern crate elefren;
/// # use std::error::Error; /// # use std::error::Error;
/// # use elefren::prelude::*; /// # use elefren::prelude::*;
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data { /// # let data = Data {
/// # base: "".into(), /// # base: "".into(),
/// # client_id: "".into(), /// # client_id: "".into(),
@ -327,7 +326,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
/// let follows_me = client.followed_by_me()?; /// let follows_me = client.followed_by_me()?;
/// # Ok(()) /// # Ok(())
/// # } /// # }
fn followed_by_me(&self) -> Result<Page<Account, H>> { fn followed_by_me(&self) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
@ -371,7 +370,7 @@ pub trait MastodonClient<H: HttpSend = HttpSender> {
/// Trait that represents clients that can make unauthenticated calls to a /// Trait that represents clients that can make unauthenticated calls to a
/// mastodon instance /// mastodon instance
#[allow(unused)] #[allow(unused)]
pub trait MastodonUnauthenticated<H: HttpSend> { pub trait MastodonUnauthenticated {
/// GET /api/v1/statuses/:id /// GET /api/v1/statuses/:id
fn get_status(&self, id: &str) -> Result<Status> { fn get_status(&self, id: &str) -> Result<Status> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
@ -385,11 +384,11 @@ pub trait MastodonUnauthenticated<H: HttpSend> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/statuses/:id/reblogged_by /// GET /api/v1/statuses/:id/reblogged_by
fn reblogged_by(&self, id: &str) -> Result<Page<Account, H>> { fn reblogged_by(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
/// GET /api/v1/statuses/:id/favourited_by /// GET /api/v1/statuses/:id/favourited_by
fn favourited_by(&self, id: &str) -> Result<Page<Account, H>> { fn favourited_by(&self, id: &str) -> Result<Page<Account>> {
unimplemented!("This method was not implemented"); unimplemented!("This method was not implemented");
} }
} }

@ -5,8 +5,6 @@ use reqwest::{header::LINK, Response};
use serde::Deserialize; use serde::Deserialize;
use url::Url; use url::Url;
use crate::http_send::HttpSend;
macro_rules! pages { macro_rules! pages {
($($direction:ident: $fun:ident),*) => { ($($direction:ident: $fun:ident),*) => {
@ -42,7 +40,6 @@ macro_rules! pages {
/// # extern crate elefren; /// # extern crate elefren;
/// # use elefren::Mastodon; /// # use elefren::Mastodon;
/// # use elefren::page::OwnedPage; /// # use elefren::page::OwnedPage;
/// # use elefren::http_send::HttpSender;
/// # use elefren::entities::status::Status; /// # use elefren::entities::status::Status;
/// # use std::cell::RefCell; /// # use std::cell::RefCell;
/// # use elefren::prelude::*; /// # use elefren::prelude::*;
@ -56,7 +53,7 @@ macro_rules! pages {
/// # }; /// # };
/// struct HomeTimeline { /// struct HomeTimeline {
/// client: Mastodon, /// client: Mastodon,
/// page: RefCell<Option<OwnedPage<Status, HttpSender>>>, /// page: RefCell<Option<OwnedPage<Status>>>,
/// } /// }
/// let client = Mastodon::from(data); /// let client = Mastodon::from(data);
/// let home = client.get_home_timeline()?.into_owned(); /// let home = client.get_home_timeline()?.into_owned();
@ -68,23 +65,23 @@ macro_rules! pages {
/// # } /// # }
/// ``` /// ```
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct OwnedPage<T: for<'de> Deserialize<'de>, H: HttpSend> { pub struct OwnedPage<T: for<'de> Deserialize<'de>> {
mastodon: Mastodon<H>, mastodon: Mastodon,
next: Option<Url>, next: Option<Url>,
prev: Option<Url>, prev: Option<Url>,
/// Initial set of items /// Initial set of items
pub initial_items: Vec<T>, pub initial_items: Vec<T>,
} }
impl<T: for<'de> Deserialize<'de>, H: HttpSend> OwnedPage<T, H> { impl<T: for<'de> Deserialize<'de>> OwnedPage<T> {
pages! { pages! {
next: next_page, next: next_page,
prev: prev_page prev: prev_page
} }
} }
impl<'a, T: for<'de> Deserialize<'de>, H: HttpSend> From<Page<'a, T, H>> for OwnedPage<T, H> { impl<'a, T: for<'de> Deserialize<'de>> From<Page<'a, T>> for OwnedPage<T> {
fn from(page: Page<'a, T, H>) -> OwnedPage<T, H> { fn from(page: Page<'a, T>) -> OwnedPage<T> {
OwnedPage { OwnedPage {
mastodon: page.mastodon.clone(), mastodon: page.mastodon.clone(),
next: page.next, next: page.next,
@ -96,21 +93,21 @@ impl<'a, T: for<'de> Deserialize<'de>, H: HttpSend> From<Page<'a, T, H>> for Own
/// Represents a single page of API results /// Represents a single page of API results
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Page<'a, T: for<'de> Deserialize<'de>, H: 'a + HttpSend> { pub struct Page<'a, T: for<'de> Deserialize<'de>> {
mastodon: &'a Mastodon<H>, mastodon: &'a Mastodon,
next: Option<Url>, next: Option<Url>,
prev: Option<Url>, prev: Option<Url>,
/// Initial set of items /// Initial set of items
pub initial_items: Vec<T>, pub initial_items: Vec<T>,
} }
impl<'a, T: for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> { impl<'a, T: for<'de> Deserialize<'de>> Page<'a, T> {
pages! { pages! {
next: next_page, next: next_page,
prev: prev_page prev: prev_page
} }
pub(crate) fn new(mastodon: &'a Mastodon<H>, response: Response) -> Result<Self> { pub(crate) fn new(mastodon: &'a Mastodon, response: Response) -> Result<Self> {
let (prev, next) = get_links(&response)?; let (prev, next) = get_links(&response)?;
Ok(Page { Ok(Page {
initial_items: deserialise(response)?, initial_items: deserialise(response)?,
@ -121,7 +118,7 @@ impl<'a, T: for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
} }
} }
impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> { impl<'a, T: Clone + for<'de> Deserialize<'de>> Page<'a, T> {
/// Returns an owned version of this struct that doesn't borrow the client /// Returns an owned version of this struct that doesn't borrow the client
/// that created it /// that created it
/// ///
@ -131,7 +128,6 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
/// # extern crate elefren; /// # extern crate elefren;
/// # use elefren::Mastodon; /// # use elefren::Mastodon;
/// # use elefren::page::OwnedPage; /// # use elefren::page::OwnedPage;
/// # use elefren::http_send::HttpSender;
/// # use elefren::entities::status::Status; /// # use elefren::entities::status::Status;
/// # use std::cell::RefCell; /// # use std::cell::RefCell;
/// # use elefren::prelude::*; /// # use elefren::prelude::*;
@ -145,7 +141,7 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
/// # }; /// # };
/// struct HomeTimeline { /// struct HomeTimeline {
/// client: Mastodon, /// client: Mastodon,
/// page: RefCell<Option<OwnedPage<Status, HttpSender>>>, /// page: RefCell<Option<OwnedPage<Status>>>,
/// } /// }
/// let client = Mastodon::from(data); /// let client = Mastodon::from(data);
/// let home = client.get_home_timeline()?.into_owned(); /// let home = client.get_home_timeline()?.into_owned();
@ -156,7 +152,7 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
pub fn into_owned(self) -> OwnedPage<T, H> { pub fn into_owned(self) -> OwnedPage<T> {
OwnedPage::from(self) OwnedPage::from(self)
} }
@ -176,7 +172,7 @@ impl<'a, T: Clone + for<'de> Deserialize<'de>, H: HttpSend> Page<'a, T, H> {
/// # extern crate elefren; /// # extern crate elefren;
/// # use std::error::Error; /// # use std::error::Error;
/// use elefren::prelude::*; /// use elefren::prelude::*;
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// # let data = Data { /// # let data = Data {
/// # base: "".into(), /// # base: "".into(),
/// # client_id: "".into(), /// # client_id: "".into(),

@ -7,7 +7,6 @@ use url::percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use crate::{ use crate::{
apps::{App, AppBuilder}, apps::{App, AppBuilder},
http_send::{HttpSend, HttpSender},
scopes::Scopes, scopes::Scopes,
Data, Data,
Error, Error,
@ -21,12 +20,11 @@ const DEFAULT_REDIRECT_URI: &str = "urn:ietf:wg:oauth:2.0:oob";
/// Handles registering your mastodon app to your instance. It is recommended /// Handles registering your mastodon app to your instance. It is recommended
/// you cache your data struct to avoid registering on every run. /// you cache your data struct to avoid registering on every run.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Registration<'a, H: HttpSend = HttpSender> { pub struct Registration<'a> {
base: String, base: String,
client: Client, client: Client,
app_builder: AppBuilder<'a>, app_builder: AppBuilder<'a>,
force_login: bool, force_login: bool,
http_sender: H,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -46,7 +44,7 @@ struct AccessToken {
access_token: String, access_token: String,
} }
impl<'a> Registration<'a, HttpSender> { impl<'a> Registration<'a> {
/// Construct a new registration process to the instance of the `base` url. /// Construct a new registration process to the instance of the `base` url.
/// ``` /// ```
/// use elefren::prelude::*; /// use elefren::prelude::*;
@ -59,23 +57,11 @@ impl<'a> Registration<'a, HttpSender> {
client: Client::new(), client: Client::new(),
app_builder: AppBuilder::new(), app_builder: AppBuilder::new(),
force_login: false, force_login: false,
http_sender: HttpSender,
} }
} }
} }
impl<'a, H: HttpSend> Registration<'a, H> { impl<'a> Registration<'a> {
#[allow(dead_code)]
pub(crate) fn with_sender<I: Into<String>>(base: I, http_sender: H) -> Self {
Registration {
base: base.into(),
client: Client::new(),
app_builder: AppBuilder::new(),
force_login: false,
http_sender,
}
}
/// Sets the name of this app /// Sets the name of this app
/// ///
/// This is required, and if this isn't set then the AppBuilder::build /// This is required, and if this isn't set then the AppBuilder::build
@ -113,7 +99,8 @@ impl<'a, H: HttpSend> Registration<'a, H> {
} }
fn send(&self, req: RequestBuilder) -> Result<Response> { fn send(&self, req: RequestBuilder) -> Result<Response> {
Ok(self.http_sender.send(&self.client, req)?) let req = req.build()?;
Ok(self.client.execute(req)?)
} }
/// Register the given application /// Register the given application
@ -137,7 +124,7 @@ impl<'a, H: HttpSend> Registration<'a, H> {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
pub fn register<I: TryInto<App>>(&mut self, app: I) -> Result<Registered<H>> pub fn register<I: TryInto<App>>(&mut self, app: I) -> Result<Registered>
where where
Error: From<<I as TryInto<App>>::Err>, Error: From<<I as TryInto<App>>::Err>,
{ {
@ -152,7 +139,6 @@ impl<'a, H: HttpSend> Registration<'a, H> {
redirect: oauth.redirect_uri, redirect: oauth.redirect_uri,
scopes: app.scopes().clone(), scopes: app.scopes().clone(),
force_login: self.force_login, force_login: self.force_login,
http_sender: self.http_sender.clone(),
}) })
} }
@ -176,7 +162,7 @@ impl<'a, H: HttpSend> Registration<'a, H> {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
pub fn build(&mut self) -> Result<Registered<H>> { pub fn build(&mut self) -> Result<Registered> {
let app: App = self.app_builder.clone().build()?; let app: App = self.app_builder.clone().build()?;
let oauth = self.send_app(&app)?; let oauth = self.send_app(&app)?;
@ -188,7 +174,6 @@ impl<'a, H: HttpSend> Registration<'a, H> {
redirect: oauth.redirect_uri, redirect: oauth.redirect_uri,
scopes: app.scopes().clone(), scopes: app.scopes().clone(),
force_login: self.force_login, force_login: self.force_login,
http_sender: self.http_sender.clone(),
}) })
} }
@ -198,7 +183,7 @@ impl<'a, H: HttpSend> Registration<'a, H> {
} }
} }
impl Registered<HttpSender> { impl Registered {
/// Skip having to retrieve the client id and secret from the server by /// Skip having to retrieve the client id and secret from the server by
/// creating a `Registered` struct directly /// creating a `Registered` struct directly
/// ///
@ -234,7 +219,7 @@ impl Registered<HttpSender> {
redirect: &str, redirect: &str,
scopes: Scopes, scopes: Scopes,
force_login: bool, force_login: bool,
) -> Registered<HttpSender> { ) -> Registered {
Registered { Registered {
base: base.to_string(), base: base.to_string(),
client: Client::new(), client: Client::new(),
@ -243,14 +228,14 @@ impl Registered<HttpSender> {
redirect: redirect.to_string(), redirect: redirect.to_string(),
scopes, scopes,
force_login, force_login,
http_sender: HttpSender,
} }
} }
} }
impl<H: HttpSend> Registered<H> { impl Registered {
fn send(&self, req: RequestBuilder) -> Result<Response> { fn send(&self, req: RequestBuilder) -> Result<Response> {
Ok(self.http_sender.send(&self.client, req)?) let req = req.build()?;
Ok(self.client.execute(req)?)
} }
/// Returns the parts of the `Registered` struct that can be used to /// Returns the parts of the `Registered` struct that can be used to
@ -324,7 +309,7 @@ impl<H: HttpSend> Registered<H> {
/// Create an access token from the client id, client secret, and code /// Create an access token from the client id, client secret, and code
/// provided by the authorisation url. /// provided by the authorisation url.
pub fn complete(&self, code: &str) -> Result<Mastodon<H>> { pub fn complete(&self, code: &str) -> Result<Mastodon> {
let url = format!( let url = format!(
"{}/oauth/token?client_id={}&client_secret={}&code={}&grant_type=authorization_code&\ "{}/oauth/token?client_id={}&client_secret={}&code={}&grant_type=authorization_code&\
redirect_uri={}", redirect_uri={}",
@ -341,7 +326,7 @@ impl<H: HttpSend> Registered<H> {
token: token.access_token.into(), token: token.access_token.into(),
}; };
let mut builder = MastodonBuilder::new(self.http_sender.clone()); let mut builder = MastodonBuilder::new();
builder.client(self.client.clone()).data(data); builder.client(self.client.clone()).data(data);
Ok(builder.build()?) Ok(builder.build()?)
} }
@ -350,7 +335,7 @@ impl<H: HttpSend> Registered<H> {
/// Represents the state of the auth flow when the app has been registered but /// Represents the state of the auth flow when the app has been registered but
/// the user is not authenticated /// the user is not authenticated
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Registered<H: HttpSend> { pub struct Registered {
base: String, base: String,
client: Client, client: Client,
client_id: String, client_id: String,
@ -358,7 +343,6 @@ pub struct Registered<H: HttpSend> {
redirect: String, redirect: String,
scopes: Scopes, scopes: Scopes,
force_login: bool, force_login: bool,
http_sender: H,
} }
#[cfg(test)] #[cfg(test)]
@ -370,15 +354,13 @@ mod tests {
let r = Registration::new("https://example.com"); let r = Registration::new("https://example.com");
assert_eq!(r.base, "https://example.com".to_string()); assert_eq!(r.base, "https://example.com".to_string());
assert_eq!(r.app_builder, AppBuilder::new()); assert_eq!(r.app_builder, AppBuilder::new());
assert_eq!(r.http_sender, HttpSender);
} }
#[test] #[test]
fn test_registration_with_sender() { fn test_registration_with_sender() {
let r = Registration::with_sender("https://example.com", HttpSender); let r = Registration::new("https://example.com");
assert_eq!(r.base, "https://example.com".to_string()); assert_eq!(r.base, "https://example.com".to_string());
assert_eq!(r.app_builder, AppBuilder::new()); assert_eq!(r.app_builder, AppBuilder::new());
assert_eq!(r.http_sender, HttpSender);
} }
#[test] #[test]

@ -10,7 +10,7 @@ use std::time::Duration;
/// # extern crate elefren; /// # extern crate elefren;
/// # use std::error::Error; /// # use std::error::Error;
/// use elefren::{entities::filter::FilterContext, requests::AddFilterRequest}; /// use elefren::{entities::filter::FilterContext, requests::AddFilterRequest};
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let request = AddFilterRequest::new("foo", FilterContext::Home); /// let request = AddFilterRequest::new("foo", FilterContext::Home);
/// # Ok(()) /// # Ok(())
/// # } /// # }

@ -90,7 +90,7 @@ impl Scopes {
/// # use std::error::Error; /// # use std::error::Error;
/// use elefren::scopes::Scopes; /// use elefren::scopes::Scopes;
/// ///
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::all(); /// let scope = Scopes::all();
/// assert_eq!(&format!("{}", scope), "read write follow push"); /// assert_eq!(&format!("{}", scope), "read write follow push");
/// # Ok(()) /// # Ok(())
@ -107,7 +107,7 @@ impl Scopes {
/// # use std::error::Error; /// # use std::error::Error;
/// use elefren::scopes::Scopes; /// use elefren::scopes::Scopes;
/// ///
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::read_all(); /// let scope = Scopes::read_all();
/// assert_eq!(&format!("{}", scope), "read"); /// assert_eq!(&format!("{}", scope), "read");
/// # Ok(()) /// # Ok(())
@ -124,7 +124,7 @@ impl Scopes {
/// # use std::error::Error; /// # use std::error::Error;
/// use elefren::scopes::{Read, Scopes}; /// use elefren::scopes::{Read, Scopes};
/// ///
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::read(Read::Accounts); /// let scope = Scopes::read(Read::Accounts);
/// assert_eq!(&format!("{}", scope), "read:accounts"); /// assert_eq!(&format!("{}", scope), "read:accounts");
/// # Ok(()) /// # Ok(())
@ -141,7 +141,7 @@ impl Scopes {
/// # use std::error::Error; /// # use std::error::Error;
/// use elefren::scopes::Scopes; /// use elefren::scopes::Scopes;
/// ///
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::write_all(); /// let scope = Scopes::write_all();
/// assert_eq!(&format!("{}", scope), "write"); /// assert_eq!(&format!("{}", scope), "write");
/// # Ok(()) /// # Ok(())
@ -158,7 +158,7 @@ impl Scopes {
/// # use std::error::Error; /// # use std::error::Error;
/// use elefren::scopes::{Scopes, Write}; /// use elefren::scopes::{Scopes, Write};
/// ///
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::write(Write::Accounts); /// let scope = Scopes::write(Write::Accounts);
/// assert_eq!(&format!("{}", scope), "write:accounts"); /// assert_eq!(&format!("{}", scope), "write:accounts");
/// # Ok(()) /// # Ok(())
@ -175,7 +175,7 @@ impl Scopes {
/// # use std::error::Error; /// # use std::error::Error;
/// use elefren::scopes::Scopes; /// use elefren::scopes::Scopes;
/// ///
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::follow(); /// let scope = Scopes::follow();
/// assert_eq!(&format!("{}", scope), "follow"); /// assert_eq!(&format!("{}", scope), "follow");
/// # Ok(()) /// # Ok(())
@ -192,7 +192,7 @@ impl Scopes {
/// # use std::error::Error; /// # use std::error::Error;
/// use elefren::scopes::Scopes; /// use elefren::scopes::Scopes;
/// ///
/// # fn main() -> Result<(), Box<Error>> { /// # fn main() -> Result<(), Box<dyn Error>> {
/// let scope = Scopes::push(); /// let scope = Scopes::push();
/// assert_eq!(&format!("{}", scope), "push"); /// assert_eq!(&format!("{}", scope), "push");
/// # Ok(()) /// # Ok(())

Loading…
Cancel
Save