popularity 0.1.1 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|