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
@@ -1,7 +1,7 @@
|
|
1
|
-
|
2
1
|
module Popularity
|
3
2
|
class RedditShare < Crawler
|
4
3
|
include Popularity::ContainerMethods
|
4
|
+
stats :comments, :score, :posts
|
5
5
|
|
6
6
|
def initialize(*args)
|
7
7
|
super(*args)
|
@@ -19,20 +19,6 @@ module Popularity
|
|
19
19
|
self
|
20
20
|
end
|
21
21
|
|
22
|
-
def to_json(options ={})
|
23
|
-
total = {"comments" => 0, "posts" => 0, "score" => 0}
|
24
|
-
return total unless @results
|
25
|
-
|
26
|
-
@results.collect(&:to_json).each do |json|
|
27
|
-
json.each do |key, value|
|
28
|
-
total[key] ||= 0
|
29
|
-
total[key] += value
|
30
|
-
end
|
31
|
-
end
|
32
|
-
total["posts"] = posts
|
33
|
-
total
|
34
|
-
end
|
35
|
-
|
36
22
|
def posts
|
37
23
|
@results.size rescue 0
|
38
24
|
end
|
@@ -45,4 +31,4 @@ module Popularity
|
|
45
31
|
"http://www.reddit.com/r/search/search.json?q=url:#{@url}"
|
46
32
|
end
|
47
33
|
end
|
48
|
-
end
|
34
|
+
end
|
@@ -1,17 +1,11 @@
|
|
1
1
|
module Popularity
|
2
2
|
class Rubygems < Crawler
|
3
|
+
stats :downloads
|
4
|
+
|
3
5
|
def downloads
|
4
6
|
response_json["downloads"]
|
5
7
|
end
|
6
8
|
|
7
|
-
def as_json(options = {})
|
8
|
-
{"downloads" => downloads}
|
9
|
-
end
|
10
|
-
|
11
|
-
def total
|
12
|
-
downloads
|
13
|
-
end
|
14
|
-
|
15
9
|
def valid?
|
16
10
|
host == 'rubygems.org' && @url =~ /\/gems\//
|
17
11
|
end
|
@@ -26,4 +20,4 @@ module Popularity
|
|
26
20
|
"https://rubygems.org/api/v1/gems/#{gem_name}.json"
|
27
21
|
end
|
28
22
|
end
|
29
|
-
end
|
23
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Popularity
|
2
2
|
class Soundcloud < Crawler
|
3
|
+
stats :plays, :likes, :comments, :downloads
|
4
|
+
|
3
5
|
def plays
|
4
6
|
response.scan(/\"soundcloud:play_count\" content=\"([0-9]*)\"/).flatten.first.to_f.to_i
|
5
7
|
end
|
@@ -16,17 +18,6 @@ module Popularity
|
|
16
18
|
response.scan(/\"soundcloud:download_count\" content=\"([0-9]*)\"/).flatten.first.to_f.to_i
|
17
19
|
end
|
18
20
|
|
19
|
-
def as_json(options = {})
|
20
|
-
{"plays" => plays,
|
21
|
-
"likes" => likes,
|
22
|
-
"comments" => comments,
|
23
|
-
"downloads" => downloads }
|
24
|
-
end
|
25
|
-
|
26
|
-
def total
|
27
|
-
plays + likes + downloads + comments
|
28
|
-
end
|
29
|
-
|
30
21
|
def valid?
|
31
22
|
host == 'soundcloud.com'
|
32
23
|
end
|
@@ -41,4 +32,4 @@ module Popularity
|
|
41
32
|
@url
|
42
33
|
end
|
43
34
|
end
|
44
|
-
end
|
35
|
+
end
|
@@ -1,21 +1,15 @@
|
|
1
1
|
module Popularity
|
2
2
|
class Twitter < Crawler
|
3
|
+
stats :tweets
|
4
|
+
|
3
5
|
def tweets
|
4
6
|
response_json['count'].to_i if has_response?
|
5
7
|
end
|
6
8
|
|
7
|
-
def total
|
8
|
-
tweets
|
9
|
-
end
|
10
|
-
|
11
|
-
def as_json(options = {})
|
12
|
-
{"tweets" => tweets}
|
13
|
-
end
|
14
|
-
|
15
9
|
protected
|
16
10
|
|
17
11
|
def request_url
|
18
12
|
"https://cdn.api.twitter.com/1/urls/count.json?url=#{@url}"
|
19
13
|
end
|
20
14
|
end
|
21
|
-
end
|
15
|
+
end
|
@@ -1,10 +1,9 @@
|
|
1
|
-
|
2
1
|
module Popularity
|
3
2
|
module ContainerMethods
|
4
3
|
def self.included(base)
|
5
4
|
base.class_eval do
|
6
5
|
def results
|
7
|
-
@results
|
6
|
+
@results || []
|
8
7
|
end
|
9
8
|
|
10
9
|
def add_result(result)
|
@@ -22,32 +21,42 @@ module Popularity
|
|
22
21
|
end
|
23
22
|
end
|
24
23
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
json.each do |key, value|
|
33
|
-
next if key == "total"
|
34
|
-
|
35
|
-
if value.is_a?(Hash)
|
36
|
-
# RedditShare breaks out into separate results for each reddit link
|
37
|
-
# I'm not a big fan of this hacky stuff here
|
38
|
-
value.each do |k,v|
|
39
|
-
total[k] ||= 0
|
40
|
-
total[k] += v
|
41
|
-
end
|
42
|
-
else
|
43
|
-
total[key] ||= 0
|
44
|
-
total[key] += value
|
45
|
-
end
|
24
|
+
def as_json(options = {})
|
25
|
+
result_property_names = []
|
26
|
+
results_json = self.results.collect do |r|
|
27
|
+
json = {}
|
28
|
+
|
29
|
+
r.class.property_names.each do |name|
|
30
|
+
json[name.to_s] = r.send(name.to_sym)
|
46
31
|
end
|
32
|
+
|
33
|
+
json["total"] = r.total
|
34
|
+
|
35
|
+
{r.url => json}
|
47
36
|
end
|
48
37
|
|
49
|
-
|
50
|
-
|
38
|
+
json = aggregate_json
|
39
|
+
json["_results"] = results_json
|
40
|
+
|
41
|
+
json
|
42
|
+
end
|
43
|
+
|
44
|
+
def aggregate_json
|
45
|
+
json = {}
|
46
|
+
|
47
|
+
names = if self.class.respond_to?(:property_names)
|
48
|
+
self.class.property_names
|
49
|
+
else
|
50
|
+
self.results.first.class.property_names
|
51
|
+
end
|
52
|
+
|
53
|
+
names.each do |name|
|
54
|
+
json[name.to_s] = self.send(name.to_sym)
|
55
|
+
end
|
56
|
+
|
57
|
+
json["total"] = self.total
|
58
|
+
|
59
|
+
json
|
51
60
|
end
|
52
61
|
|
53
62
|
def method_missing(method_sym, *arguments, &block)
|
@@ -57,7 +66,9 @@ module Popularity
|
|
57
66
|
end
|
58
67
|
|
59
68
|
if collection.all? { |t| t.is_a?(Fixnum) }
|
60
|
-
collection.reduce(:+)
|
69
|
+
collection.reduce(:+)
|
70
|
+
else
|
71
|
+
collection.flatten
|
61
72
|
end
|
62
73
|
end
|
63
74
|
end
|
data/lib/popularity/search.rb
CHANGED
@@ -3,7 +3,6 @@ module Popularity
|
|
3
3
|
attr_accessor :info
|
4
4
|
attr_accessor :results
|
5
5
|
attr_accessor :sources
|
6
|
-
attr_reader :total
|
7
6
|
attr_reader :url
|
8
7
|
|
9
8
|
def initialize(url)
|
@@ -14,10 +13,8 @@ module Popularity
|
|
14
13
|
selected_types.each do |network|
|
15
14
|
network.fetch_async do |code, body|
|
16
15
|
add_result(network)
|
17
|
-
begin
|
18
|
-
|
19
|
-
total_score << network.total
|
20
|
-
end
|
16
|
+
begin
|
17
|
+
|
21
18
|
rescue Exception => e
|
22
19
|
puts "#{network.name} had an accident"
|
23
20
|
puts e.message
|
@@ -26,24 +23,22 @@ module Popularity
|
|
26
23
|
end
|
27
24
|
end
|
28
25
|
|
29
|
-
loop do
|
30
|
-
# we want the requests to be asyncronous, but we don't
|
26
|
+
loop do
|
27
|
+
# we want the requests to be asyncronous, but we don't
|
31
28
|
# want gem users to have to deal with async code
|
32
|
-
#
|
29
|
+
#
|
33
30
|
break if selected_types.all? { |network| network.async_done? }
|
34
31
|
end
|
35
|
-
|
36
|
-
@total = total_score.reduce(:+)
|
37
32
|
end
|
38
33
|
|
39
|
-
def
|
34
|
+
def as_json(options ={})
|
40
35
|
json = {}
|
41
36
|
self.results.collect do |result|
|
42
|
-
json[result.name.to_s] = result.
|
37
|
+
json[result.name.to_s] = result.as_json
|
43
38
|
end
|
44
39
|
|
45
40
|
self.sources.collect do |source|
|
46
|
-
json[source.to_s] = self.send(source.to_sym).
|
41
|
+
json[source.to_s] = self.send(source.to_sym).as_json
|
47
42
|
end
|
48
43
|
|
49
44
|
json["total"] = total
|
@@ -51,6 +46,10 @@ module Popularity
|
|
51
46
|
json
|
52
47
|
end
|
53
48
|
|
49
|
+
def total
|
50
|
+
self.results.collect(&:total).compact.reduce(:+)
|
51
|
+
end
|
52
|
+
|
54
53
|
protected
|
55
54
|
|
56
55
|
def selected_types
|
@@ -69,6 +68,8 @@ module Popularity
|
|
69
68
|
|
70
69
|
self.instance_variable_set "@#{result.name}", result
|
71
70
|
|
71
|
+
# if there's a facebook result, this class will
|
72
|
+
# have a facebook method returning it
|
72
73
|
self.define_singleton_method(result.name.to_sym) { result }
|
73
74
|
end
|
74
75
|
|
data/popularity.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: popularity 0.
|
5
|
+
# stub: popularity 0.2.1 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "popularity"
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.2.1"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Jeff Keen"]
|
14
|
-
s.date = "2015-
|
14
|
+
s.date = "2015-05-22"
|
15
15
|
s.description = "Supports Facebook, Twitter, Pinterest, Reddit (Links, Posts, and Comments), Github, Soundcloud, Medium, and Rubygems"
|
16
16
|
s.email = "jeff@keen.me"
|
17
17
|
s.extra_rdoc_files = [
|
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.files = [
|
22
22
|
".document",
|
23
23
|
".rspec",
|
24
|
+
".travis.yml",
|
24
25
|
"Gemfile",
|
25
26
|
"Gemfile.lock",
|
26
27
|
"LICENSE.txt",
|
@@ -73,13 +74,7 @@ Gem::Specification.new do |s|
|
|
73
74
|
"spec/search_spec.rb",
|
74
75
|
"spec/soundcloud_spec.rb",
|
75
76
|
"spec/spec_helper.rb",
|
76
|
-
"spec/twitter_spec.rb"
|
77
|
-
"test/facebook_test.rb",
|
78
|
-
"test/fixtures/vcr_cassettes/facebook.yml",
|
79
|
-
"test/fixtures/vcr_cassettes/google.yml",
|
80
|
-
"test/helper.rb",
|
81
|
-
"test/test_non_specific.rb",
|
82
|
-
"test/test_twitter.rb"
|
77
|
+
"spec/twitter_spec.rb"
|
83
78
|
]
|
84
79
|
s.homepage = "http://github.com/jkeen/popularity"
|
85
80
|
s.licenses = ["MIT"]
|
@@ -93,7 +88,7 @@ Gem::Specification.new do |s|
|
|
93
88
|
s.add_runtime_dependency(%q<open_uri_redirections>, ["~> 0"])
|
94
89
|
s.add_runtime_dependency(%q<json>, ["~> 1.8"])
|
95
90
|
s.add_runtime_dependency(%q<unirest>, ["~> 1"])
|
96
|
-
s.
|
91
|
+
s.add_runtime_dependency(%q<pry>, [">= 0"])
|
97
92
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
98
93
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
99
94
|
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
@@ -104,7 +99,7 @@ Gem::Specification.new do |s|
|
|
104
99
|
s.add_dependency(%q<open_uri_redirections>, ["~> 0"])
|
105
100
|
s.add_dependency(%q<json>, ["~> 1.8"])
|
106
101
|
s.add_dependency(%q<unirest>, ["~> 1"])
|
107
|
-
s.add_dependency(%q<pry>, ["
|
102
|
+
s.add_dependency(%q<pry>, [">= 0"])
|
108
103
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
109
104
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
110
105
|
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
@@ -116,7 +111,7 @@ Gem::Specification.new do |s|
|
|
116
111
|
s.add_dependency(%q<open_uri_redirections>, ["~> 0"])
|
117
112
|
s.add_dependency(%q<json>, ["~> 1.8"])
|
118
113
|
s.add_dependency(%q<unirest>, ["~> 1"])
|
119
|
-
s.add_dependency(%q<pry>, ["
|
114
|
+
s.add_dependency(%q<pry>, [">= 0"])
|
120
115
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
121
116
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
122
117
|
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
data/spec/google_plus_spec.rb
CHANGED
@@ -17,11 +17,11 @@ describe Popularity::GooglePlus do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
context "json" do
|
20
|
-
let(:json) { subject.
|
20
|
+
let(:json) { subject.as_json }
|
21
21
|
|
22
|
-
it "should have required attributes in json" do
|
22
|
+
it "should have required attributes in json" do
|
23
23
|
expect(subject.plus_ones).to eq(json["plus_ones"])
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
|
-
end
|
27
|
+
end
|
data/spec/medium_spec.rb
CHANGED
@@ -37,11 +37,11 @@ describe Popularity::Medium do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
context "json" do
|
40
|
-
let(:json) { subject.
|
40
|
+
let(:json) { subject.as_json }
|
41
41
|
|
42
|
-
it "should have required attributes in json" do
|
42
|
+
it "should have required attributes in json" do
|
43
43
|
expect(subject.recommends).to eq(json["recommends"])
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
47
|
-
end
|
47
|
+
end
|
data/spec/pinterest_spec.rb
CHANGED
@@ -17,11 +17,11 @@ describe Popularity::Pinterest do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
context "json" do
|
20
|
-
let(:json) { subject.
|
20
|
+
let(:json) { subject.as_json }
|
21
21
|
|
22
|
-
it "should have required attributes in json" do
|
22
|
+
it "should have required attributes in json" do
|
23
23
|
expect(subject.pins).to eq(json["pins"])
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
|
-
end
|
27
|
+
end
|
data/spec/reddit_post_spec.rb
CHANGED
data/spec/reddit_spec.rb
CHANGED
@@ -27,19 +27,48 @@ describe Popularity::RedditShare do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
context "json" do
|
30
|
-
let(:json) { subject.
|
30
|
+
let(:json) { subject.as_json }
|
31
31
|
|
32
|
-
it "should include post count in json" do
|
33
|
-
expect(
|
32
|
+
it "should include post count in json" do
|
33
|
+
expect(json["posts"]).to eq(25)
|
34
34
|
end
|
35
35
|
|
36
|
-
it "should comments in json" do
|
36
|
+
it "should have comments in json" do
|
37
37
|
expect(json["comments"]).to_not be_nil
|
38
38
|
end
|
39
39
|
|
40
|
-
it "should score in json" do
|
40
|
+
it "should have score in json" do
|
41
41
|
expect(json["score"]).to_not be_nil
|
42
42
|
end
|
43
|
+
|
44
|
+
it "should have _results in json" do
|
45
|
+
expect(json["_results"]).to_not be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
context "results" do
|
49
|
+
let(:json_results) { subject.as_json["_results"] }
|
50
|
+
|
51
|
+
it "should equal number of results" do
|
52
|
+
expect(subject.results.size).to eq(json_results.size)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should contain the result urls" do
|
56
|
+
subject.results.each_with_index do |result, index|
|
57
|
+
json_result = json_results[index]
|
58
|
+
|
59
|
+
expect(json_result.keys.first).to eq(result.url)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should contain the correct values" do
|
64
|
+
subject.results.each_with_index do |result, index|
|
65
|
+
json_result = json_results[index]
|
66
|
+
expect(json_result.values.first["score"]).to eq(result.score)
|
67
|
+
expect(json_result.values.first["comments"]).to eq(result.comments)
|
68
|
+
expect(json_result.values.first["total"]).to eq(result.total)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
43
72
|
end
|
44
73
|
|
45
74
|
context "unknown url" do
|
@@ -65,25 +94,25 @@ describe Popularity::RedditShare do
|
|
65
94
|
end
|
66
95
|
|
67
96
|
it "should have correct total" do
|
68
|
-
expect(subject.total).to eq(subject.score + subject.comments)
|
97
|
+
expect(subject.total).to eq(subject.score + subject.comments + subject.posts)
|
69
98
|
end
|
70
99
|
|
71
100
|
context "json" do
|
72
|
-
let(:json) { subject.
|
101
|
+
let(:json) { subject.as_json }
|
73
102
|
|
74
|
-
it "should include post count in json" do
|
103
|
+
it "should include post count in json" do
|
75
104
|
expect(0).to eq(json["posts"])
|
76
105
|
end
|
77
106
|
|
78
|
-
it "should comments in json" do
|
107
|
+
it "should comments in json" do
|
79
108
|
expect(0).to eq(json["comments"])
|
80
109
|
end
|
81
110
|
|
82
|
-
it "should score in json" do
|
111
|
+
it "should score in json" do
|
83
112
|
expect(0).to eq(json["score"])
|
84
113
|
end
|
85
114
|
|
86
115
|
end
|
87
116
|
end
|
88
117
|
end
|
89
|
-
end
|
118
|
+
end
|