aboutsummaryrefslogtreecommitdiff
path: root/lib/jsonfeed/src/feed.rs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/jsonfeed/src/feed.rs')
-rw-r--r--lib/jsonfeed/src/feed.rs296
1 files changed, 296 insertions, 0 deletions
diff --git a/lib/jsonfeed/src/feed.rs b/lib/jsonfeed/src/feed.rs
new file mode 100644
index 0000000..8b5b5ce
--- /dev/null
+++ b/lib/jsonfeed/src/feed.rs
@@ -0,0 +1,296 @@
+use std::default::Default;
+
+use item::Item;
+use builder::Builder;
+
+const VERSION_1: &'static str = "https://jsonfeed.org/version/1";
+
+/// Represents a single feed
+///
+/// # Examples
+///
+/// ```rust
+/// // Serialize a feed object to a JSON string
+///
+/// # extern crate jsonfeed;
+/// # use std::default::Default;
+/// # use jsonfeed::Feed;
+/// # fn main() {
+/// let feed: Feed = Feed::default();
+/// assert_eq!(
+/// jsonfeed::to_string(&feed).unwrap(),
+/// "{\"version\":\"https://jsonfeed.org/version/1\",\"title\":\"\",\"items\":[]}"
+/// );
+/// # }
+/// ```
+///
+/// ```rust
+/// // Deserialize a feed objects from a JSON String
+///
+/// # extern crate jsonfeed;
+/// # use jsonfeed::Feed;
+/// # fn main() {
+/// let json = "{\"version\":\"https://jsonfeed.org/version/1\",\"title\":\"\",\"items\":[]}";
+/// let feed: Feed = jsonfeed::from_str(&json).unwrap();
+/// assert_eq!(
+/// feed,
+/// Feed::default()
+/// );
+/// # }
+/// ```
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
+pub struct Feed {
+ pub version: String,
+ pub title: String,
+ pub items: Vec<Item>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub home_page_url: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub feed_url: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub description: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub user_comment: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub next_url: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub icon: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub favicon: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub author: Option<Author>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub expired: Option<bool>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub hubs: Option<Vec<Hub>>,
+}
+
+impl Feed {
+ /// Used to construct a Feed object
+ pub fn builder() -> Builder {
+ Builder::new()
+ }
+}
+
+impl Default for Feed {
+ fn default() -> Feed {
+ Feed {
+ version: VERSION_1.to_string(),
+ title: "".to_string(),
+ items: vec![],
+ home_page_url: None,
+ feed_url: None,
+ description: None,
+ user_comment: None,
+ next_url: None,
+ icon: None,
+ favicon: None,
+ author: None,
+ expired: None,
+ hubs: None,
+ }
+ }
+}
+
+/// Represents an `attachment` for an item
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
+pub struct Attachment {
+ url: String,
+ mime_type: String,
+ title: Option<String>,
+ size_in_bytes: Option<u64>,
+ duration_in_seconds: Option<u64>,
+}
+
+/// Represents an `author` in both a feed and a feed item
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
+pub struct Author {
+ name: Option<String>,
+ url: Option<String>,
+ avatar: Option<String>,
+}
+
+impl Author {
+ pub fn new() -> Author {
+ Author {
+ name: None,
+ url: None,
+ avatar: None,
+ }
+ }
+
+ pub fn name<I: Into<String>>(mut self, name: I) -> Self {
+ self.name = Some(name.into());
+ self
+ }
+
+ pub fn url<I: Into<String>>(mut self, url: I) -> Self {
+ self.url = Some(url.into());
+ self
+ }
+
+ pub fn avatar<I: Into<String>>(mut self, avatar: I) -> Self {
+ self.avatar = Some(avatar.into());
+ self
+ }
+}
+
+/// Represents a `hub` for a feed
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
+pub struct Hub {
+ #[serde(rename = "type")]
+ type_: String,
+ url: String,
+}
+
+#[cfg(test)]
+mod tests {
+ use serde_json;
+ use std::default::Default;
+ use super::*;
+
+ #[test]
+ fn serialize_feed() {
+ let feed = Feed {
+ version: "https://jsonfeed.org/version/1".to_string(),
+ title: "some title".to_string(),
+ items: vec![],
+ home_page_url: None,
+ description: None,
+ expired: Some(true),
+ ..Default::default()
+ };
+ assert_eq!(
+ serde_json::to_string(&feed).unwrap(),
+ r#"{"version":"https://jsonfeed.org/version/1","title":"some title","items":[],"expired":true}"#
+ );
+ }
+
+ #[test]
+ fn deserialize_feed() {
+ let json = r#"{"version":"https://jsonfeed.org/version/1","title":"some title","items":[]}"#;
+ let feed: Feed = serde_json::from_str(&json).unwrap();
+ let expected = Feed {
+ version: "https://jsonfeed.org/version/1".to_string(),
+ title: "some title".to_string(),
+ items: vec![],
+ ..Default::default()
+ };
+ assert_eq!(
+ feed,
+ expected
+ );
+ }
+
+ #[test]
+ fn serialize_attachment() {
+ let attachment = Attachment {
+ url: "http://example.com".to_string(),
+ mime_type: "application/json".to_string(),
+ title: Some("some title".to_string()),
+ size_in_bytes: Some(1),
+ duration_in_seconds: Some(1),
+ };
+ assert_eq!(
+ serde_json::to_string(&attachment).unwrap(),
+ r#"{"url":"http://example.com","mime_type":"application/json","title":"some title","size_in_bytes":1,"duration_in_seconds":1}"#
+ );
+ }
+
+ #[test]
+ fn deserialize_attachment() {
+ let json = r#"{"url":"http://example.com","mime_type":"application/json","title":"some title","size_in_bytes":1,"duration_in_seconds":1}"#;
+ let attachment: Attachment = serde_json::from_str(&json).unwrap();
+ let expected = Attachment {
+ url: "http://example.com".to_string(),
+ mime_type: "application/json".to_string(),
+ title: Some("some title".to_string()),
+ size_in_bytes: Some(1),
+ duration_in_seconds: Some(1),
+ };
+ assert_eq!(
+ attachment,
+ expected
+ );
+ }
+
+ #[test]
+ fn serialize_author() {
+ let author = Author {
+ name: Some("bob jones".to_string()),
+ url: Some("http://example.com".to_string()),
+ avatar: Some("http://img.com/blah".to_string()),
+ };
+ assert_eq!(
+ serde_json::to_string(&author).unwrap(),
+ r#"{"name":"bob jones","url":"http://example.com","avatar":"http://img.com/blah"}"#
+ );
+ }
+
+ #[test]
+ fn deserialize_author() {
+ let json = r#"{"name":"bob jones","url":"http://example.com","avatar":"http://img.com/blah"}"#;
+ let author: Author = serde_json::from_str(&json).unwrap();
+ let expected = Author {
+ name: Some("bob jones".to_string()),
+ url: Some("http://example.com".to_string()),
+ avatar: Some("http://img.com/blah".to_string()),
+ };
+ assert_eq!(
+ author,
+ expected
+ );
+ }
+
+ #[test]
+ fn serialize_hub() {
+ let hub = Hub {
+ type_: "some-type".to_string(),
+ url: "http://example.com".to_string(),
+ };
+ assert_eq!(
+ serde_json::to_string(&hub).unwrap(),
+ r#"{"type":"some-type","url":"http://example.com"}"#
+ )
+ }
+
+ #[test]
+ fn deserialize_hub() {
+ let json = r#"{"type":"some-type","url":"http://example.com"}"#;
+ let hub: Hub = serde_json::from_str(&json).unwrap();
+ let expected = Hub {
+ type_: "some-type".to_string(),
+ url: "http://example.com".to_string(),
+ };
+ assert_eq!(
+ hub,
+ expected
+ );
+ }
+
+ #[test]
+ fn deser_podcast() {
+ let json = r#"{
+ "version": "https://jsonfeed.org/version/1",
+ "title": "Timetable",
+ "home_page_url": "http://timetable.manton.org/",
+ "items": [
+ {
+ "id": "http://timetable.manton.org/2017/04/episode-45-launch-week/",
+ "url": "http://timetable.manton.org/2017/04/episode-45-launch-week/",
+ "title": "Episode 45: Launch week",
+ "content_html": "I’m rolling out early access to Micro.blog this week. I talk about how the first 2 days have gone, mistakes with TestFlight, and what to do next.",
+ "date_published": "2017-04-26T01:09:45+00:00",
+ "attachments": [
+ {
+ "url": "http://timetable.manton.org/podcast-download/139/episode-45-launch-week.mp3",
+ "mime_type": "audio/mpeg",
+ "size_in_bytes": 5236920
+ }
+ ]
+ }
+ ]
+}"#;
+ serde_json::from_str::<Feed>(&json).expect("Failed to deserialize podcast feed");
+ }
+}