rssable 0.0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cd99535f844b27a604a0ae97f648807976045c7350dc536312a50f77ed438446
4
+ data.tar.gz: 0a6d02f9f66a54959f41d3e912c40e7ee7b91b73039113cdcde1707e1b9be682
5
+ SHA512:
6
+ metadata.gz: 9a19230d6acf341655b659f49b8bc0d8421a2e2f487174877db6e56fc587fc9303c559d3bd0be4c8a33033592dfc1d55d51d30e15dc47e22f4d9b2897f256be0
7
+ data.tar.gz: 77af58376a4f40ad9fdfadcf4ec2a9f78c01336bf97940945b10cf5086e5929a94763b0209c0463d37b1970c23c3342b484872915a970cd0e4486d5a6f273976
@@ -0,0 +1,47 @@
1
+ module RSSable
2
+ module Detection
3
+ class EngineDetector
4
+ MAPPINGS = {
5
+ blogger: /\/feeds\/posts\/default\?alt\=rss$/,
6
+ wordpress: /\/feed\/$/,
7
+ medium: /medium\.com\/feed\//
8
+ }
9
+
10
+ # It returns array of RSS feed link and the driver
11
+ # If feed link is not found it returns blank array
12
+ # If the provider is not detected it returns :default
13
+ #
14
+ # @return [Array]
15
+ def self.call(urls:, source_url:)
16
+ result = nil
17
+
18
+ urls.each do |url|
19
+ result = if url.match(MAPPINGS[:blogger])
20
+ [url, :blogger]
21
+ elsif url.match(MAPPINGS[:wordpress]) && url.match(/\/comments\//).nil?
22
+ [url, :wordpress]
23
+ elsif url.match(MAPPINGS[:medium])
24
+ [url, :medium]
25
+ elsif url == "/feed.xml"
26
+ parsed_url = URI.join(source_url, "/feed.xml")
27
+ [parsed_url.to_s, :jekyll]
28
+ end
29
+
30
+ break unless result.nil?
31
+ end
32
+
33
+ return result unless result.nil?
34
+
35
+ if urls.size != 0
36
+ [urls.first, :default]
37
+ else
38
+ []
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :urls
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,15 @@
1
+ module RSSable
2
+ module Detection
3
+ class FeedFinder
4
+ # It returns array of RSS feed links for given URL
5
+ #
6
+ # @return [Array<String>]
7
+ def self.call(url:)
8
+ response = RestClient.get(url)
9
+ html = Nokogiri::HTML(response.body)
10
+
11
+ html.css("link[type='application/rss+xml']").map { |node| node[:href] }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ module RSSable
2
+ module Parsers
3
+ class Channel
4
+
5
+ def initialize(feed:, driver:)
6
+ @feed = feed
7
+ @driver = driver
8
+ end
9
+
10
+ # Returns the RSS feed title
11
+ #
12
+ # @return [String]
13
+ def title
14
+ xml.xpath("//channel").at("title").text
15
+ end
16
+
17
+ # Returns the RSS feed description
18
+ #
19
+ # @return [String]
20
+ def description
21
+ xml.xpath("//channel").at("description").text
22
+ end
23
+
24
+ # Returns the website link
25
+ #
26
+ # @return [String]
27
+ def link
28
+ xml.xpath("//channel").at("link").text
29
+ end
30
+
31
+ # Returns a collection of the RSS feed items
32
+ #
33
+ # @return [Array]
34
+ def items
35
+ xml.css("item").map { |node| item_class.new(node) }
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :feed, :driver
41
+
42
+ def xml
43
+ @xml ||= Nokogiri::XML(feed)
44
+ end
45
+
46
+ def item_class
47
+ @item_class ||= ::RSSable::Parsers::ItemClassBuilder.call(
48
+ driver: driver
49
+ )
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,21 @@
1
+ module RSSable
2
+ module Parsers
3
+ class ItemClassBuilder
4
+ # Returns the parser class for the given driver
5
+ #
6
+ # @return [Class]
7
+ def self.call(driver:)
8
+ case driver
9
+ when :wordpress
10
+ RSSable::Parsers::Items::Wordpress
11
+ when :blogger
12
+ RSSable::Parsers::Items::Blogger
13
+ when :medium
14
+ RSSable::Parsers::Items::Medium
15
+ else
16
+ RSSable::Parsers::Items::Base
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,66 @@
1
+ module RSSable
2
+ module Parsers
3
+ module Items
4
+ class Base
5
+ def initialize(node)
6
+ @node = node
7
+ end
8
+
9
+ # Returns the item title
10
+ #
11
+ # @return [String]
12
+ def title
13
+ node_text(node.at("title"))
14
+ end
15
+
16
+ # Returns the item link
17
+ #
18
+ # @return [String]
19
+ def link
20
+ node_text(node.at("link"))
21
+ end
22
+
23
+ # Returns the item publication date
24
+ #
25
+ # @return [String]
26
+ def published_at
27
+ node_text(node.at("pubDate"))
28
+ end
29
+
30
+ # Returns the item description
31
+ #
32
+ # @return [String]
33
+ def description
34
+ node_text(node.at("description"))
35
+ end
36
+
37
+ # Returns an array of the item categories
38
+ #
39
+ # @return [Array<String>]
40
+ def tags
41
+ node.css("category").map(&:text)
42
+ end
43
+
44
+ # Returns the article author
45
+ #
46
+ # @return [String]
47
+ def author
48
+ node_text(node.at("author"))
49
+ end
50
+
51
+ # Returns nil by the default
52
+ #
53
+ # @return [NilClass]
54
+ def comments_count; end
55
+
56
+ private
57
+
58
+ attr_reader :node
59
+
60
+ def node_text(node)
61
+ node.text unless node.nil?
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,18 @@
1
+ module RSSable
2
+ module Parsers
3
+ module Items
4
+ class Blogger < RSSable::Parsers::Items::Base
5
+
6
+ # Returns the comments count
7
+ # If the comments count node does not exist it returns nil
8
+ #
9
+ # @return [Integer]
10
+ def comments_count
11
+ count = node_text(node.at_xpath("//thr:total"))
12
+ count.to_i unless count.nil?
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ module RSSable
2
+ module Parsers
3
+ module Items
4
+ class Medium < RSSable::Parsers::Items::Base
5
+
6
+ # Returns the article author
7
+ #
8
+ # @return [String]
9
+ def author
10
+ creator_node = node.elements.find { |c| c.name == "creator" }
11
+ node_text(creator_node)
12
+ end
13
+
14
+ # Returns the article description
15
+ #
16
+ # @return [String]
17
+ def description
18
+ node_text(node.at_xpath("//content:encoded"))
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ module RSSable
2
+ module Parsers
3
+ module Items
4
+ class Wordpress < RSSable::Parsers::Items::Base
5
+
6
+ # Returns the article author
7
+ #
8
+ # @return [String]
9
+ def author
10
+ creator_node = node.elements.find { |c| c.name == "creator" }
11
+ node_text(creator_node)
12
+ end
13
+
14
+ # Returns the comments count
15
+ # If the comments count node does not exist it returns nil
16
+ #
17
+ # @return [Integer]
18
+ def comments_count
19
+ count = node_text(node.at_xpath("//slash:comments"))
20
+ count.to_i unless count.nil?
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ module RSSable
2
+ class Processor
3
+ def self.call(url:)
4
+ # Returns the RSSable::Parsers::Channel instance
5
+ # If the feed URL is not detected it returns nil
6
+ #
7
+ # @return [RSSable::Parsers::Channel]
8
+ urls = RSSable::Detection::FeedFinder.call(url: url)
9
+ feed_url, driver = RSSable::Detection::EngineDetector.call(
10
+ urls: urls, source_url: url
11
+ )
12
+
13
+ return if feed_url.nil?
14
+
15
+ response = RestClient.get(feed_url)
16
+
17
+ RSSable::Parsers::Channel.new(
18
+ feed: response.body, driver: driver
19
+ )
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ module RSSable
2
+ module Version
3
+ module_function
4
+
5
+ # Gem current version
6
+ #
7
+ # @return [String]
8
+ def to_s
9
+ "0.0.0.1"
10
+ end
11
+ end
12
+ end
data/lib/rssable.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'nokogiri'
2
+ require 'rest-client'
3
+ require 'URI'
4
+ require 'rssable/detection/feed_finder'
5
+ require 'rssable/detection/engine_detector'
6
+ require 'rssable/parsers/items/base'
7
+ require 'rssable/parsers/items/wordpress'
8
+ require 'rssable/parsers/items/blogger'
9
+ require 'rssable/parsers/items/medium'
10
+ require 'rssable/parsers/item_class_builder'
11
+ require 'rssable/parsers/channel'
12
+ require 'rssable/processor'
13
+
14
+ module RSSable
15
+ # Returns the channel driver instance
16
+ #
17
+ # @return [RSSable::Parsers::Channel]
18
+ def self.subscribe(url)
19
+ RSSable::Processor.call(
20
+ url: url
21
+ )
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rssable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Paweł Dąbrowski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.8.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Access the RSS channel of any webiste without worrying about the engine
56
+ email: dziamber@gmail.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - lib/rssable.rb
62
+ - lib/rssable/detection/engine_detector.rb
63
+ - lib/rssable/detection/feed_finder.rb
64
+ - lib/rssable/parsers/channel.rb
65
+ - lib/rssable/parsers/item_class_builder.rb
66
+ - lib/rssable/parsers/items/base.rb
67
+ - lib/rssable/parsers/items/blogger.rb
68
+ - lib/rssable/parsers/items/medium.rb
69
+ - lib/rssable/parsers/items/wordpress.rb
70
+ - lib/rssable/processor.rb
71
+ - lib/rssable/version.rb
72
+ homepage: http://github.com/rubyhero/rssable
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 2.0.0
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.7.3
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Access the RSS channel of any webiste without worrying about the engine
96
+ test_files: []