popularity 0.1.1 → 0.2.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 +4 -4
- data/.travis.yml +5 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/Rakefile +6 -9
- data/VERSION +1 -1
- data/lib/popularity.rb +10 -17
- data/lib/popularity/crawler.rb +30 -7
- data/lib/popularity/networks/facebook.rb +6 -13
- data/lib/popularity/networks/github.rb +3 -9
- data/lib/popularity/networks/google_plus.rb +4 -10
- data/lib/popularity/networks/medium.rb +3 -9
- data/lib/popularity/networks/pinterest.rb +3 -9
- data/lib/popularity/networks/reddit_comment.rb +4 -10
- data/lib/popularity/networks/reddit_post.rb +13 -15
- data/lib/popularity/networks/reddit_share.rb +2 -16
- data/lib/popularity/networks/rubygems.rb +3 -9
- data/lib/popularity/networks/soundcloud.rb +3 -12
- data/lib/popularity/networks/twitter.rb +3 -9
- data/lib/popularity/results_container.rb +37 -26
- data/lib/popularity/search.rb +14 -13
- data/popularity.gemspec +8 -13
- data/spec/google_plus_spec.rb +3 -3
- data/spec/medium_spec.rb +3 -3
- data/spec/pinterest_spec.rb +3 -3
- data/spec/reddit_post_spec.rb +1 -1
- data/spec/reddit_spec.rb +40 -11
- data/spec/results_container_spec.rb +4 -4
- data/spec/rubygems_spec.rb +3 -3
- data/spec/search_spec.rb +9 -9
- data/spec/soundcloud_spec.rb +3 -3
- data/spec/spec_helper.rb +4 -1
- metadata +8 -13
- data/test/facebook_test.rb +0 -28
- data/test/fixtures/vcr_cassettes/facebook.yml +0 -50
- data/test/fixtures/vcr_cassettes/google.yml +0 -425
- data/test/helper.rb +0 -34
- data/test/test_non_specific.rb +0 -27
- data/test/test_twitter.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c17e6a773a83fc813ffd30d5c14c2f72691c9e5
|
4
|
+
data.tar.gz: cd24795291873364d6383a473d94d191b21e83c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 473ced1189eab299c44f58b6fe32025c89e37c88b37311894adb3696ef9511ac282fbc8518d070a593692084ec281d1130106fbaed0459078a27e29598924f61
|
7
|
+
data.tar.gz: 01bfbee1959f78f8887da8dd1070ab31389ae7ac5537a2efc25d9cb3e4d2bca0abd2e59e4f46d86cd7f012e439978e4ce9317706711a17b8cd17be43f3dbea8f
|
data/Gemfile
CHANGED
@@ -3,9 +3,10 @@ source "http://rubygems.org"
|
|
3
3
|
gem 'open_uri_redirections', '~> 0'
|
4
4
|
gem 'json', '~> 1.8'
|
5
5
|
gem 'unirest', '~> 1'
|
6
|
+
gem 'pry'
|
6
7
|
|
7
8
|
group :development, :test do
|
8
|
-
gem "pry", '~> 0.10'
|
9
|
+
# gem "pry", '~> 0.10'
|
9
10
|
gem "shoulda", ">= 0"
|
10
11
|
gem "rdoc", "~> 3.12"
|
11
12
|
gem "bundler", "~> 1.0"
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -25,20 +25,17 @@ Jeweler::Tasks.new do |gem|
|
|
25
25
|
end
|
26
26
|
Jeweler::RubygemsDotOrgTasks.new
|
27
27
|
|
28
|
-
require 'rake/testtask'
|
29
|
-
Rake::TestTask.new(:test) do |test|
|
30
|
-
test.libs << 'lib' << 'test'
|
31
|
-
test.pattern = 'test/**/test_*.rb'
|
32
|
-
test.verbose = true
|
33
|
-
end
|
34
|
-
|
35
28
|
desc "Code coverage detail"
|
36
29
|
task :simplecov do
|
37
30
|
ENV['COVERAGE'] = "true"
|
38
|
-
Rake::Task['
|
31
|
+
Rake::Task['spec'].execute
|
39
32
|
end
|
40
33
|
|
41
|
-
task :default => :
|
34
|
+
task :default => [:spec]
|
35
|
+
desc 'run Rspec specs'
|
36
|
+
task :spec do
|
37
|
+
sh 'rspec spec'
|
38
|
+
end
|
42
39
|
|
43
40
|
require 'rdoc/task'
|
44
41
|
Rake::RDocTask.new do |rdoc|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.1
|
data/lib/popularity.rb
CHANGED
@@ -7,7 +7,7 @@ module Popularity
|
|
7
7
|
TYPES = []
|
8
8
|
end
|
9
9
|
|
10
|
-
Gem.find_files("popularity/networks/*.rb").each { |path|
|
10
|
+
Gem.find_files("popularity/networks/*.rb").each { |path|
|
11
11
|
require path
|
12
12
|
file_name = path.split('/').last.split('.').first
|
13
13
|
class_name = file_name.gsub(/_[a-z]|^[a-z]/, &:upcase).gsub('_', '')
|
@@ -18,8 +18,6 @@ Gem.find_files("popularity/networks/*.rb").each { |path|
|
|
18
18
|
|
19
19
|
module Popularity
|
20
20
|
def self.search(*urls)
|
21
|
-
response = {}
|
22
|
-
|
23
21
|
MultiSearch.new(:urls => urls)
|
24
22
|
end
|
25
23
|
|
@@ -43,20 +41,20 @@ module Popularity
|
|
43
41
|
add_search_result(result)
|
44
42
|
end
|
45
43
|
end
|
46
|
-
end
|
44
|
+
end
|
47
45
|
|
48
46
|
def results
|
49
47
|
searches.collect(&:results).reduce(:+)
|
50
48
|
end
|
51
49
|
|
52
|
-
def
|
50
|
+
def as_json(options = {})
|
53
51
|
json = {}
|
54
52
|
self.searches.collect do |search|
|
55
|
-
json[search.url] = search.
|
53
|
+
json[search.url] = search.as_json
|
56
54
|
end
|
57
55
|
|
58
56
|
self.sources.collect do |source|
|
59
|
-
json[source.to_s] = self.send(source.to_sym).
|
57
|
+
json[source.to_s] = self.send(source.to_sym).as_json
|
60
58
|
end
|
61
59
|
|
62
60
|
json["total"] = total
|
@@ -65,22 +63,17 @@ module Popularity
|
|
65
63
|
end
|
66
64
|
|
67
65
|
def total
|
68
|
-
total
|
69
|
-
self.searches.each do |a|
|
70
|
-
total += a.total
|
71
|
-
end
|
72
|
-
|
73
|
-
total
|
66
|
+
self.searches.collect(&:total).compact.reduce(:+)
|
74
67
|
end
|
75
68
|
|
76
69
|
protected
|
77
70
|
|
78
71
|
def add_search_result(result)
|
79
|
-
container = self.instance_variable_get("@#{result.name}")
|
72
|
+
container = self.instance_variable_get("@#{result.name}")
|
80
73
|
|
81
74
|
unless container
|
82
|
-
@sources ||= []
|
83
|
-
@sources << result.name.to_sym
|
75
|
+
@sources ||= []
|
76
|
+
@sources << result.name.to_sym
|
84
77
|
container = Popularity::ResultsContainer.new
|
85
78
|
self.instance_variable_set "@#{result.name}", container
|
86
79
|
self.define_singleton_method(result.name.to_sym) { container }
|
@@ -90,4 +83,4 @@ module Popularity
|
|
90
83
|
end
|
91
84
|
|
92
85
|
end
|
93
|
-
end
|
86
|
+
end
|
data/lib/popularity/crawler.rb
CHANGED
@@ -2,11 +2,27 @@ require 'open-uri'
|
|
2
2
|
require 'open_uri_redirections'
|
3
3
|
require 'json'
|
4
4
|
require 'unirest'
|
5
|
+
require 'pry'
|
5
6
|
|
6
7
|
module Popularity
|
7
8
|
class Crawler
|
8
9
|
attr_reader :url
|
9
10
|
|
11
|
+
def self.stats(*args)
|
12
|
+
@property_names ||= []
|
13
|
+
args.each do |name|
|
14
|
+
@property_names << name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.property_names
|
19
|
+
@property_names
|
20
|
+
end
|
21
|
+
|
22
|
+
def total
|
23
|
+
self.class.property_names.uniq.collect { |n| self.send(n.to_sym) }.select { |t| t.class == Fixnum }.compact.reduce(:+)
|
24
|
+
end
|
25
|
+
|
10
26
|
def initialize(url)
|
11
27
|
@url = url
|
12
28
|
end
|
@@ -22,13 +38,13 @@ module Popularity
|
|
22
38
|
def has_response?
|
23
39
|
response #fetch it
|
24
40
|
|
25
|
-
return false if response.nil?
|
41
|
+
return false if response.nil?
|
26
42
|
return false if response.empty?
|
27
43
|
|
28
44
|
true
|
29
45
|
end
|
30
46
|
|
31
|
-
def valid?
|
47
|
+
def valid?
|
32
48
|
true # to be overridden in subclasses
|
33
49
|
end
|
34
50
|
|
@@ -48,8 +64,15 @@ module Popularity
|
|
48
64
|
self.class.to_s.split('::').last.gsub(/(.)([A-Z])/,'\1_\2').downcase
|
49
65
|
end
|
50
66
|
|
51
|
-
def
|
52
|
-
|
67
|
+
def as_json(options = {})
|
68
|
+
json = {}
|
69
|
+
|
70
|
+
self.class.property_names.each do |name|
|
71
|
+
json[name.to_s] = self.send(name.to_sym)
|
72
|
+
end
|
73
|
+
|
74
|
+
json["total"] = total
|
75
|
+
json
|
53
76
|
end
|
54
77
|
|
55
78
|
def fetch_async(&block)
|
@@ -58,13 +81,13 @@ module Popularity
|
|
58
81
|
Unirest.get(request_url) do |response|
|
59
82
|
@async_done = true
|
60
83
|
@response = response.raw_body
|
61
|
-
block.call(response.code, response.raw_body) if block_given?
|
84
|
+
block.call(response.code, response.raw_body) if block_given?
|
62
85
|
end
|
63
86
|
end
|
64
87
|
|
65
88
|
def fetch
|
66
89
|
return false unless valid?
|
67
|
-
|
90
|
+
|
68
91
|
begin
|
69
92
|
response = Unirest.get(request_url)
|
70
93
|
@response = response.raw_body
|
@@ -73,4 +96,4 @@ module Popularity
|
|
73
96
|
end
|
74
97
|
end
|
75
98
|
end
|
76
|
-
end
|
99
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Popularity
|
2
2
|
class Facebook < Crawler
|
3
|
+
stats :shares, :comments
|
4
|
+
|
3
5
|
def shares
|
4
6
|
response_json['shares'].to_f.to_i
|
5
7
|
end
|
@@ -8,19 +10,10 @@ module Popularity
|
|
8
10
|
response_json['comments'].to_f.to_i
|
9
11
|
end
|
10
12
|
|
11
|
-
def as_json(options = {})
|
12
|
-
{ "shares" => shares,
|
13
|
-
"comments" => comments }
|
14
|
-
end
|
15
|
-
|
16
|
-
def total
|
17
|
-
shares + comments
|
18
|
-
end
|
19
|
-
|
20
13
|
protected
|
21
14
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
15
|
+
def request_url
|
16
|
+
"http://graph.facebook.com/?id=#{@url}"
|
17
|
+
end
|
18
|
+
end
|
26
19
|
end
|
@@ -1,14 +1,8 @@
|
|
1
1
|
module Popularity
|
2
2
|
class Github < Crawler
|
3
|
-
|
4
|
-
response_json.size
|
5
|
-
end
|
3
|
+
stats :stars
|
6
4
|
|
7
|
-
def
|
8
|
-
{ "stars" => stars }
|
9
|
-
end
|
10
|
-
|
11
|
-
def total
|
5
|
+
def stars
|
12
6
|
response_json.size
|
13
7
|
end
|
14
8
|
|
@@ -25,4 +19,4 @@ module Popularity
|
|
25
19
|
"https://api.github.com/repos/#{owner}/#{repo}/stargazers"
|
26
20
|
end
|
27
21
|
end
|
28
|
-
end
|
22
|
+
end
|
@@ -1,22 +1,16 @@
|
|
1
1
|
module Popularity
|
2
2
|
class GooglePlus < Crawler
|
3
|
+
stats :plus_ones
|
4
|
+
|
3
5
|
def plus_ones
|
4
|
-
matches = response.scan(/window.__SSR = {c\: (\d+.\d+E?\d+)/)
|
6
|
+
matches = response.scan(/window.__SSR = {c\: (\d+.\d+E?\d+)/)
|
5
7
|
matches.flatten.first.to_f.to_i
|
6
8
|
end
|
7
9
|
|
8
|
-
def as_json(options = {})
|
9
|
-
{"plus_ones" => plus_ones}
|
10
|
-
end
|
11
|
-
|
12
|
-
def total
|
13
|
-
plus_ones
|
14
|
-
end
|
15
|
-
|
16
10
|
protected
|
17
11
|
|
18
12
|
def request_url
|
19
13
|
"https://plusone.google.com/_/+1/fastbutton?url=#{URI::encode(@url)}"
|
20
14
|
end
|
21
15
|
end
|
22
|
-
end
|
16
|
+
end
|
@@ -1,17 +1,11 @@
|
|
1
1
|
module Popularity
|
2
2
|
class Medium < Crawler
|
3
|
+
stats :recommends
|
4
|
+
|
3
5
|
def recommends
|
4
6
|
response_json["payload"]["value"]["count"]
|
5
7
|
end
|
6
8
|
|
7
|
-
def as_json(options = {})
|
8
|
-
{"recommends" => recommends}
|
9
|
-
end
|
10
|
-
|
11
|
-
def total
|
12
|
-
recommends
|
13
|
-
end
|
14
|
-
|
15
9
|
def valid?
|
16
10
|
host == 'medium.com'
|
17
11
|
end
|
@@ -30,4 +24,4 @@ module Popularity
|
|
30
24
|
JSON.parse(response.sub("])}while(1);</x>", ""))
|
31
25
|
end
|
32
26
|
end
|
33
|
-
end
|
27
|
+
end
|
@@ -1,21 +1,15 @@
|
|
1
1
|
module Popularity
|
2
2
|
class Pinterest < Crawler
|
3
|
+
stats :pins
|
4
|
+
|
3
5
|
def pins
|
4
6
|
JSON.parse(response.gsub('receiveCount(','').gsub(')',''))['count'].to_f.to_i
|
5
7
|
end
|
6
8
|
|
7
|
-
def as_json(options = {})
|
8
|
-
{"pins" => pins}
|
9
|
-
end
|
10
|
-
|
11
|
-
def total
|
12
|
-
pins
|
13
|
-
end
|
14
|
-
|
15
9
|
protected
|
16
10
|
|
17
11
|
def request_url
|
18
12
|
"http://api.pinterest.com/v1/urls/count.json?url=#{@url}"
|
19
13
|
end
|
20
14
|
end
|
21
|
-
end
|
15
|
+
end
|
@@ -1,20 +1,14 @@
|
|
1
1
|
module Popularity
|
2
2
|
class RedditComment < Crawler
|
3
|
-
|
4
|
-
response_json[1]["data"]["children"][0]["data"]["score"]
|
5
|
-
end
|
6
|
-
|
7
|
-
def as_json(options = {})
|
8
|
-
{"score" => score}
|
9
|
-
end
|
3
|
+
stats :score
|
10
4
|
|
11
|
-
def
|
12
|
-
score
|
5
|
+
def score
|
6
|
+
response_json[1]["data"]["children"][0]["data"]["score"]
|
13
7
|
end
|
14
8
|
|
15
9
|
def valid?
|
16
10
|
return false unless host == 'reddit.com'
|
17
|
-
|
11
|
+
|
18
12
|
path = URI.parse(@url).path
|
19
13
|
path.split('/').delete_if { |a| a.empty? }.size == 6
|
20
14
|
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
module Popularity
|
2
2
|
class RedditPost < Crawler
|
3
|
+
stats :score, :comments
|
4
|
+
|
3
5
|
def score
|
4
6
|
begin
|
5
|
-
response_json[0]["data"]["children"][0]["data"]["score"]
|
7
|
+
response_json[0]["data"]["children"][0]["data"]["score"]
|
6
8
|
rescue
|
7
9
|
0
|
8
10
|
end
|
@@ -10,26 +12,15 @@ module Popularity
|
|
10
12
|
|
11
13
|
def comments
|
12
14
|
begin
|
13
|
-
response_json[0]["data"]["children"][0]["data"]["num_comments"]
|
15
|
+
response_json[0]["data"]["children"][0]["data"]["num_comments"]
|
14
16
|
rescue
|
15
17
|
0
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
|
-
def as_json(options = {})
|
20
|
-
{
|
21
|
-
"comments" => comments,
|
22
|
-
"score" => score
|
23
|
-
}
|
24
|
-
end
|
25
|
-
|
26
|
-
def total
|
27
|
-
comments + score
|
28
|
-
end
|
29
|
-
|
30
21
|
def valid?
|
31
22
|
return false unless host == 'reddit.com'
|
32
|
-
|
23
|
+
|
33
24
|
path = URI.parse(@url).path
|
34
25
|
path.split('/').delete_if { |a| a.empty? }.size < 6
|
35
26
|
end
|
@@ -46,11 +37,14 @@ module Popularity
|
|
46
37
|
end
|
47
38
|
|
48
39
|
class RedditResult < RedditPost
|
49
|
-
# A stubbed out version of a RedditPost so RedditShare can
|
40
|
+
# A stubbed out version of a RedditPost so RedditShare can
|
50
41
|
# stub in the json response it already has
|
51
42
|
|
43
|
+
stats :score, :comments
|
44
|
+
|
52
45
|
def initialize(url, r)
|
53
46
|
super(url)
|
47
|
+
@url = url
|
54
48
|
@response = r
|
55
49
|
|
56
50
|
self
|
@@ -60,6 +54,10 @@ module Popularity
|
|
60
54
|
true
|
61
55
|
end
|
62
56
|
|
57
|
+
def reddit_url
|
58
|
+
@url
|
59
|
+
end
|
60
|
+
|
63
61
|
def valid?
|
64
62
|
URI.parse(@url).host
|
65
63
|
end
|