From 2ffe40ca2c3d778528d03a5e278d5b03fe8e9b2a Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Sun, 1 Apr 2018 20:58:04 +0700 Subject: [PATCH] restructure package & add support to categories --- example/main.dart | 10 +++++ lib/client.dart | 6 +-- lib/domain/rss_category.dart | 16 +++++++ lib/domain/{channel.dart => rss_feed.dart} | 40 +++++++++-------- lib/domain/{image.dart => rss_image.dart} | 8 ++-- lib/domain/{item.dart => rss_item.dart} | 15 +++++-- test/rss_test.dart | 50 +++++++++++++--------- test/{examples => xml}/Invalid.xml | 0 test/{examples => xml}/RSS.xml | 4 ++ 9 files changed, 99 insertions(+), 50 deletions(-) create mode 100644 example/main.dart create mode 100644 lib/domain/rss_category.dart rename lib/domain/{channel.dart => rss_feed.dart} (55%) rename lib/domain/{image.dart => rss_image.dart} (74%) rename lib/domain/{item.dart => rss_item.dart} (56%) rename test/{examples => xml}/Invalid.xml (100%) rename test/{examples => xml}/RSS.xml (87%) diff --git a/example/main.dart b/example/main.dart new file mode 100644 index 0000000..57099a6 --- /dev/null +++ b/example/main.dart @@ -0,0 +1,10 @@ +import 'package:webfeedclient/client.dart'; + +void main() { + var client = new WebFeedClient(); + client.fetch("https://developer.apple.com/news/releases/rss/releases.rss").then((channel) { + print(channel); + }).catchError((error) { + print(error); + }); +} diff --git a/lib/client.dart b/lib/client.dart index fba07b9..beba28c 100644 --- a/lib/client.dart +++ b/lib/client.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:http/http.dart' as http; -import 'package:webfeedclient/domain/channel.dart'; +import 'package:webfeedclient/domain/rss_feed.dart'; import 'package:xml/xml.dart' as xml; class WebFeedClient { @@ -11,14 +11,14 @@ class WebFeedClient { client = new http.Client(); } - Future fetch(String url) { + Future fetch(String url) { return client.get(url).then((response) { print("Response Status Code: ${response.statusCode}"); print("Response Body: ${response.body}"); return response.body; }).then((bodyString) { var document = xml.parse(bodyString); - var channel = new Channel.parse(document); + var channel = new RssFeed.parse(document); return channel; }); } diff --git a/lib/domain/rss_category.dart b/lib/domain/rss_category.dart new file mode 100644 index 0000000..f170f87 --- /dev/null +++ b/lib/domain/rss_category.dart @@ -0,0 +1,16 @@ +import 'package:xml/xml.dart'; + +class RssCategory { + + String domain; + String value; + + RssCategory(this.domain, this.value); + + factory RssCategory.parse(XmlElement node) { + String domain = node.getAttribute("domain"); + String value = node.text; + + return new RssCategory(domain, value); + } +} \ No newline at end of file diff --git a/lib/domain/channel.dart b/lib/domain/rss_feed.dart similarity index 55% rename from lib/domain/channel.dart rename to lib/domain/rss_feed.dart index 80f0e3d..24f4768 100644 --- a/lib/domain/channel.dart +++ b/lib/domain/rss_feed.dart @@ -1,32 +1,32 @@ import 'dart:core'; -import 'package:webfeedclient/domain/item.dart'; +import 'package:webfeedclient/domain/rss_category.dart'; +import 'package:webfeedclient/domain/rss_item.dart'; import 'package:webfeedclient/util/helpers.dart'; import 'package:xml/xml.dart'; -import 'image.dart'; +import 'package:webfeedclient/domain/rss_image.dart'; -class Channel { +class RssFeed { final String title; final String description; final String link; - final List items; + final List items; - final Image image; + final RssImage image; + final List categories; final String lastBuildDate; final String language; final String generator; final String copyright; - Channel(this.title, this.description, this.link, this.items, - {this.image, this.lastBuildDate, this.language, this.generator, this.copyright}); + RssFeed(this.title, this.description, this.link, this.items, + {this.image, this.categories, this.lastBuildDate, this.language, this.generator, this.copyright}); - factory Channel.parse(XmlDocument document) { + factory RssFeed.parse(XmlDocument document) { XmlElement channelElement; try { - channelElement = document - .findAllElements("channel") - .first; + channelElement = document.findAllElements("channel").first; } on StateError { throw new ArgumentError("channel not found"); } @@ -34,23 +34,27 @@ class Channel { var description = xmlGetString(channelElement, "description"); var link = xmlGetString(channelElement, "link"); - var feeds = channelElement.findAllElements("item").map((XmlElement element) { - return new Item.parse(element); + List feeds = channelElement.findElements("item").map((element) { + return new RssItem.parse(element); }).toList(); - Image image; + RssImage image; try { - image = new Image.parse(channelElement - .findElements("image") - .first); + image = new RssImage.parse(channelElement.findElements("image").first); } on StateError {} + List categories = channelElement.findElements("category").map((element) { + return new RssCategory.parse(element); + }).toList(); + var lastBuildDate = xmlGetString(channelElement, "lastBuildDate", strict: false); var language = xmlGetString(channelElement, "language", strict: false); var generator = xmlGetString(channelElement, "generator", strict: false); var copyright = xmlGetString(channelElement, "copyright", strict: false); - return new Channel(title, description, link, feeds, image: image, + return new RssFeed(title, description, link, feeds, + image: image, + categories: categories, lastBuildDate: lastBuildDate, language: language, generator: generator, diff --git a/lib/domain/image.dart b/lib/domain/rss_image.dart similarity index 74% rename from lib/domain/image.dart rename to lib/domain/rss_image.dart index 8b31723..3b1d199 100644 --- a/lib/domain/image.dart +++ b/lib/domain/rss_image.dart @@ -1,19 +1,19 @@ import 'package:webfeedclient/util/helpers.dart'; import 'package:xml/xml.dart'; -class Image { +class RssImage { final String title; final String url; final String link; - Image(this.title, this.url, this.link); + RssImage(this.title, this.url, this.link); - factory Image.parse(XmlElement element) { + factory RssImage.parse(XmlElement element) { var title = xmlGetString(element, "title", strict: false); var url = xmlGetString(element, "url", strict: false); var link = xmlGetString(element, "link", strict: false); - return new Image(title, url, link); + return new RssImage(title, url, link); } @override diff --git a/lib/domain/item.dart b/lib/domain/rss_item.dart similarity index 56% rename from lib/domain/item.dart rename to lib/domain/rss_item.dart index 9363f85..b4a8275 100644 --- a/lib/domain/item.dart +++ b/lib/domain/rss_item.dart @@ -1,24 +1,31 @@ +import 'package:webfeedclient/domain/rss_category.dart'; import 'package:webfeedclient/util/helpers.dart'; import 'package:xml/xml.dart'; -class Item { +class RssItem { final String title; final String description; final String link; + + final List categories; final String guid; final String pubDate; - Item(this.title, this.description, this.link, {this.guid, this.pubDate}); + RssItem(this.title, this.description, this.link, {this.categories, this.guid, this.pubDate}); - factory Item.parse(XmlElement element) { + factory RssItem.parse(XmlElement element) { var title = xmlGetString(element, "title"); var description = xmlGetString(element, "description"); var link = xmlGetString(element, "link"); + List categories = element.findElements("category").map((element) { + return new RssCategory.parse(element); + }).toList(); + var guid = xmlGetString(element, "guid", strict: false); var pubDate = xmlGetString(element, "pubDate", strict: false); - return new Item(title, description, link, guid: guid, pubDate: pubDate); + return new RssItem(title, description, link, categories: categories, guid: guid, pubDate: pubDate); } @override diff --git a/test/rss_test.dart b/test/rss_test.dart index 6d6cd6c..69ebf33 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -1,43 +1,51 @@ import 'dart:io'; import 'dart:core'; import 'package:test/test.dart'; -import 'package:webfeedclient/domain/channel.dart'; +import 'package:webfeedclient/domain/rss_feed.dart'; import 'package:xml/xml.dart' as xml; void main() { test("parsing Invalid.xml", () { - var xmlString = new File("test/examples/Invalid.xml").readAsStringSync(); + var xmlString = new File("test/xml/Invalid.xml").readAsStringSync(); var doc = xml.parse(xmlString); try { - new Channel.parse(doc); + new RssFeed.parse(doc); fail("Should throw Argument Error"); } on ArgumentError {} }); test("parsing RSS.xml", () { - var xmlString = new File("test/examples/RSS.xml").readAsStringSync(); + var xmlString = new File("test/xml/RSS.xml").readAsStringSync(); var doc = xml.parse(xmlString); - var channel = new Channel.parse(doc); + var feed = new RssFeed.parse(doc); - expect(channel.title, "News - Foo bar News"); - expect(channel.description, "Foo bar News and Updates feed provided by Foo bar, Inc."); - expect(channel.link, "https://foo.bar.news/"); - expect(channel.language, "en-US"); - expect(channel.lastBuildDate, "Mon, 26 Mar 2018 14:00:00 PDT"); - expect(channel.generator, "Custom"); - expect(channel.copyright, "Copyright 2018, Foo bar Inc."); + expect(feed.title, "News - Foo bar News"); + expect(feed.description, "Foo bar News and Updates feed provided by Foo bar, Inc."); + expect(feed.link, "https://foo.bar.news/"); + expect(feed.language, "en-US"); + expect(feed.lastBuildDate, "Mon, 26 Mar 2018 14:00:00 PDT"); + expect(feed.generator, "Custom"); + expect(feed.copyright, "Copyright 2018, Foo bar Inc."); - expect(channel.image.title, "Foo bar News"); - expect(channel.image.url, "https://foo.bar.news/logo.gif"); - expect(channel.image.link, "https://foo.bar.news/"); + expect(feed.image.title, "Foo bar News"); + expect(feed.image.url, "https://foo.bar.news/logo.gif"); + expect(feed.image.link, "https://foo.bar.news/"); - expect(channel.items.length, 2); + expect(feed.categories.length, 2); + expect(feed.categories[0].domain, null); + expect(feed.categories[0].value, "Ipsum"); + expect(feed.categories[1].domain, "news"); + expect(feed.categories[1].value, "Lorem Ipsum"); - expect(channel.items.first.title, "The standard Lorem Ipsum passage, used since the 1500s"); - expect(channel.items.first.description, "Lorem ipsum dolor sit amet, consectetur adipiscing elit"); - expect(channel.items.first.link, "https://foo.bar.news/1"); - expect(channel.items.first.guid, "https://foo.bar.news/1?guid"); - expect(channel.items.first.pubDate, "Mon, 26 Mar 2018 14:00:00 PDT"); + expect(feed.items.length, 2); + + expect(feed.items.first.title, "The standard Lorem Ipsum passage, used since the 1500s"); + expect(feed.items.first.description, "Lorem ipsum dolor sit amet, consectetur adipiscing elit"); + expect(feed.items.first.link, "https://foo.bar.news/1"); + expect(feed.items.first.guid, "https://foo.bar.news/1?guid"); + expect(feed.items.first.pubDate, "Mon, 26 Mar 2018 14:00:00 PDT"); + expect(feed.items.first.categories.first.domain, "news"); + expect(feed.items.first.categories.first.value, "Lorem"); }); } diff --git a/test/examples/Invalid.xml b/test/xml/Invalid.xml similarity index 100% rename from test/examples/Invalid.xml rename to test/xml/Invalid.xml diff --git a/test/examples/RSS.xml b/test/xml/RSS.xml similarity index 87% rename from test/examples/RSS.xml rename to test/xml/RSS.xml index 97a6496..f3bff1c 100644 --- a/test/examples/RSS.xml +++ b/test/xml/RSS.xml @@ -9,6 +9,8 @@ Foo bar News https://foo.bar.news/ + Ipsum + Lorem Ipsum en-US Mon, 26 Mar 2018 14:00:00 PDT Custom @@ -18,6 +20,7 @@ https://foo.bar.news/1 https://foo.bar.news/1?guid Lorem ipsum dolor sit amet, consectetur adipiscing elit + Lorem Mon, 26 Mar 2018 14:00:00 PDT @@ -25,6 +28,7 @@ https://foo.bar.news/2 https://foo.bar.news/2?guid Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium + Ipsum Tue, 20 Mar 2018 10:00:00 PDT