virility 0.0.6 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +83 -17
- data/lib/virility.rb +35 -3
- data/lib/virility/exceptions.rb +5 -0
- data/lib/virility/excitation.rb +26 -40
- data/lib/virility/strategies/delicious.rb +7 -8
- data/lib/virility/strategies/facebook.rb +12 -5
- data/lib/virility/strategies/pinterest.rb +8 -9
- data/lib/virility/strategies/plus_one.rb +4 -5
- data/lib/virility/strategies/stumble_upon.rb +4 -5
- data/lib/virility/strategies/twitter.rb +4 -5
- data/lib/virility/strategy.rb +98 -0
- data/lib/virility/supporter.rb +55 -0
- data/lib/virility/version.rb +1 -1
- data/spec/excitation_spec.rb +58 -33
- data/spec/spec_helper.rb +27 -0
- data/spec/strategies/delicious_spec.rb +66 -0
- data/spec/strategies/facebook_spec.rb +98 -0
- data/spec/strategies/pinterest_spec.rb +66 -0
- data/spec/strategies/plus_one_spec.rb +66 -0
- data/spec/strategies/stumble_upon_spec.rb +66 -0
- data/spec/strategies/twitter_spec.rb +66 -0
- data/spec/strategy_spec.rb +102 -0
- data/spec/virility_spec.rb +70 -1
- data/virility.gemspec +1 -1
- metadata +22 -8
- data/lib/virility/context.rb +0 -18
- data/spec/context_spec.rb +0 -31
data/README.md
CHANGED
@@ -16,18 +16,23 @@ Or install it yourself as:
|
|
16
16
|
|
17
17
|
$ gem install virility
|
18
18
|
|
19
|
-
## Usage
|
19
|
+
## Basic Usage
|
20
20
|
|
21
|
-
|
21
|
+
If all you need is the raw shares numbers for a URL, Virility has some very simple methods you can use right out of the box:
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
Virility.poll("http://rubygems.org") # => Returns a hash with the collected results from all of the social network strategies
|
24
|
+
Virility.counts("http://rubygems.org") # => {:delicious=>0, :facebook=>72, :pinterest=>0, :plus_one=>138, :stumble_upon=>1488, :twitter=>2322}
|
25
|
+
Virility.total("http://rubygems.org") # => 4020
|
26
|
+
Virility.url("http://rubygems.org") # => Returns a Virility::Excitation object that you can manipulate
|
27
27
|
|
28
|
-
|
28
|
+
## More Granular Usage
|
29
29
|
|
30
|
-
|
30
|
+
The Virility::Excitation object does the heavy lifting of collecting the data from all of the available strategies.
|
31
|
+
|
32
|
+
virility = Virility::Excitation.new("http://rubygems.org")
|
33
|
+
virility.poll # returns a hash with the collected output of all data sources
|
34
|
+
virility.counts # returns a hash of just the virility counts => {:delicious=>943, :facebook=>72, :pinterest=>0, :plusone=>137, :stumbleupon=>1488, :twitter=>2319}
|
35
|
+
virility.total # returns the sum of all virility counts
|
31
36
|
|
32
37
|
## Individual Strategies
|
33
38
|
|
@@ -39,19 +44,35 @@ Currently there is support for the following social resources:
|
|
39
44
|
* Google Plus One
|
40
45
|
* Stumble Upon
|
41
46
|
|
42
|
-
Each social
|
47
|
+
Each social resource is implemented as a Virility::Strategy and contains at least three methods: poll, results and count. __poll__ does the work of querying the API to get the data and returns the same hash as the results method, __results__ returns the hashed values that were provided by the social network and __count__ pulls out the individual number of shares for that social network.
|
48
|
+
|
49
|
+
#### Strategy Initialization
|
50
|
+
|
51
|
+
There are several ways you can access the object for an individual strategy.
|
52
|
+
|
53
|
+
The Virility object has a __factory__ method that will return the strategy object:
|
54
|
+
|
55
|
+
tweets = Virility.factory(:twitter, "http://rubygems.org") # => returns a Virility::Twitter object with the rubygems url
|
56
|
+
|
57
|
+
You can also instate the Virility::Twitter object directly:
|
58
|
+
|
59
|
+
tweets = Virility::Twitter.new("http://rubygems.org")
|
43
60
|
|
44
|
-
|
45
|
-
_count_ pulls out the individual number of shares for that social
|
61
|
+
#### Individual Usage Example
|
46
62
|
|
47
63
|
Let's say you only need to get the number of tweets for a URL, you could use the Virility::Twitter class by itself:
|
48
64
|
|
49
65
|
tweets = Virility::Twitter.new("http://rubygems.org")
|
50
|
-
tweets.poll
|
51
|
-
tweets.
|
66
|
+
tweets.poll # returns a hash with the collected output from Twitter => {"url"=>"http://rubygems.org/", "count"=>2319}
|
67
|
+
tweets.results # returns a hash with the collected output from Twitter => {"url"=>"http://rubygems.org/", "count"=>2319}
|
68
|
+
tweets.count # returns the number of tweets for that URL => 2319
|
52
69
|
|
53
70
|
## Facebook Usage
|
54
71
|
|
72
|
+
fb = Virility::Facebook.new("http://rubygems.org")
|
73
|
+
fb.poll # returns a hash with the collected output from Facebook
|
74
|
+
fb.count # returns the total_count for that URL
|
75
|
+
|
55
76
|
The Facebook strategy leverages the FQL query against the link_stat table. Because of this, the following data fields are available:
|
56
77
|
* like_count
|
57
78
|
* click_count
|
@@ -59,16 +80,61 @@ The Facebook strategy leverages the FQL query against the link_stat table. Becau
|
|
59
80
|
* comment_count
|
60
81
|
* commentsbox_count
|
61
82
|
* total_count (used as the default count for all Facebook activity)
|
62
|
-
* comments_fbid
|
63
83
|
|
64
|
-
|
65
|
-
|
66
|
-
|
84
|
+
## Dynamic Finders
|
85
|
+
|
86
|
+
#### Virility::Excitation
|
87
|
+
|
88
|
+
If you have a Virility::Excitation object, there are dynamic finders that will return the individual Virility::Strategy object for a social network. Simply call the name of the strategy against the Virility::Excitation object and that strategy will be returned:
|
89
|
+
|
90
|
+
virility = Virility::Excitation.new("http://rubygems.org")
|
91
|
+
facebook = virility.facebook
|
92
|
+
twitter = virility.twitter
|
93
|
+
delicious = virility.delicious
|
94
|
+
pinterest = virility.pinterest
|
95
|
+
plus_one = virility.plus_one
|
96
|
+
stumble_upon = virility.stumble_upon
|
97
|
+
|
98
|
+
#### Virility::Strategy
|
99
|
+
|
100
|
+
If you have a Strategy object, any of the attributes that are commonly returned through the API call will be available as a dynamic finder. This is particularly useful with the Facebook strategy:
|
101
|
+
|
102
|
+
fb = Virility::Facebook.new("http://rubygems.org/")
|
103
|
+
fb.like_count # => 12
|
104
|
+
fb.share_count # => 40
|
105
|
+
fb.comment_count # => 20
|
106
|
+
fb.total_count # => 72
|
107
|
+
|
108
|
+
#### Combined Finders
|
109
|
+
|
110
|
+
Leveraging both sets of dynamic finders allows you to build an Excitation object and get all the way through to an attribute for a specific strategy:
|
111
|
+
|
112
|
+
Virility.url("http://google.com/").facebook.like_count # => 979662
|
113
|
+
Virility.url("http://google.com/").stumble_upon.info_link # => "http://www.stumbleupon.com/url/www.google.com/"
|
67
114
|
|
68
115
|
## Important Notes
|
69
116
|
|
70
117
|
URL's are very specific in the context of a social media. For example, http://rubygems.org will return different results than http://rubygems.org/ with a trailing slash. Also, http vs https will give you different numbers. This actually has a lot to do with why we created this gem. When testing be sure to investigate all of the URL variations in order to get the most complete picture of your data.
|
71
118
|
|
119
|
+
#### Case Study
|
120
|
+
|
121
|
+
Compare the total count results for http://ruby-lang.org/en. One has the trailing slash and one does not.
|
122
|
+
|
123
|
+
Virility::Excitation.new("http://www.ruby-lang.org/en").total # => 247695
|
124
|
+
Virility::Excitation.new("http://www.ruby-lang.org/en/").total # => 253190
|
125
|
+
|
126
|
+
On this particular day, there was a 5,495 count difference between the two values. Inspecting the actual results shows you which of the social networks takes the varying forms of the urls into account:
|
127
|
+
|
128
|
+
Virility::Excitation.new("http://www.ruby-lang.org/en").counts
|
129
|
+
# => {:delicious=>37, :facebook=>3, :pinterest=>0, :plusone=>20, :stumbleupon=>246937, :twitter=>698}
|
130
|
+
|
131
|
+
Virility::Excitation.new("http://www.ruby-lang.org/en/").counts
|
132
|
+
# => {:delicious=>4314, :facebook=>813, :pinterest=>22, :plusone=>406, :stumbleupon=>246937, :twitter=>698}
|
133
|
+
|
134
|
+
Stumbleupon and Twitter are consistent while Delicious, Facebook, Pinterest and Google Plus One return different results. Depending on your needs, you could craft an algorithm that takes all of this into account and attempts to deliver an accurate number by combining the data sets that are different and trusting the ones that are the same.
|
135
|
+
|
136
|
+
Based on this logic, it is possible to consider that the true total share count is closer to _253,250_. Not only is this an opinionated number, it's accuracy is questionable based on assumptions, however if you are just trying to get a ballpark feeling of the virility of your content, this number should suffice.
|
137
|
+
|
72
138
|
## Contributing
|
73
139
|
|
74
140
|
1. Fork it
|
data/lib/virility.rb
CHANGED
@@ -1,11 +1,43 @@
|
|
1
1
|
require 'cgi'
|
2
2
|
require 'httparty'
|
3
3
|
|
4
|
-
require
|
4
|
+
require 'virility/version'
|
5
|
+
require 'virility/supporter'
|
5
6
|
require 'virility/excitation'
|
6
|
-
require 'virility/
|
7
|
+
require 'virility/strategy'
|
8
|
+
require 'virility/exceptions'
|
9
|
+
|
7
10
|
Dir["#{File.dirname(__FILE__)}/virility/strategies/**/*.rb"].each {|f| require f}
|
8
11
|
|
9
12
|
module Virility
|
10
|
-
|
13
|
+
|
14
|
+
#
|
15
|
+
# Public API
|
16
|
+
#
|
17
|
+
|
18
|
+
def self.counts(url)
|
19
|
+
Virility::Excitation.new(url).counts
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.total(url)
|
23
|
+
Virility::Excitation.new(url).total
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.poll(url)
|
27
|
+
Virility::Excitation.new(url).poll
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.url(url)
|
31
|
+
virility = Virility::Excitation.new(url)
|
32
|
+
virility.poll
|
33
|
+
virility
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Factory
|
38
|
+
#
|
39
|
+
|
40
|
+
def self.factory(strategy, url)
|
41
|
+
Virility::Excitation.new(url).send(strategy)
|
42
|
+
end
|
11
43
|
end
|
data/lib/virility/excitation.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Virility
|
2
2
|
class Excitation
|
3
|
+
include Virility::Supporter
|
4
|
+
|
3
5
|
attr_accessor :url, :results, :strategies, :counts
|
4
6
|
|
5
7
|
#
|
@@ -7,7 +9,7 @@ module Virility
|
|
7
9
|
#
|
8
10
|
|
9
11
|
def initialize url
|
10
|
-
@url =
|
12
|
+
@url = url
|
11
13
|
@strategies = {}
|
12
14
|
@results = {}
|
13
15
|
@counts = {}
|
@@ -19,7 +21,7 @@ module Virility
|
|
19
21
|
#
|
20
22
|
|
21
23
|
def poll
|
22
|
-
if @results.empty?
|
24
|
+
if @results.empty?
|
23
25
|
@strategies.each do |name, strategy|
|
24
26
|
begin
|
25
27
|
@results[symbolize_for_key(strategy)] = strategy.poll
|
@@ -34,14 +36,14 @@ module Virility
|
|
34
36
|
def get_response(strategy)
|
35
37
|
@strategies[strategy].response if @strategies[strategy]
|
36
38
|
end
|
37
|
-
|
39
|
+
|
38
40
|
#
|
39
41
|
# Return Collected Counts as a Hash
|
40
42
|
#
|
41
|
-
|
43
|
+
|
42
44
|
def counts
|
43
45
|
poll
|
44
|
-
if @counts.empty?
|
46
|
+
if @counts.empty?
|
45
47
|
@strategies.each do |name, strategy|
|
46
48
|
begin
|
47
49
|
@counts[symbolize_for_key(strategy)] = strategy.count.to_i
|
@@ -52,7 +54,7 @@ module Virility
|
|
52
54
|
end
|
53
55
|
@counts
|
54
56
|
end
|
55
|
-
|
57
|
+
|
56
58
|
def total_virility
|
57
59
|
counts.values.inject(0) { |result, count| result + count }
|
58
60
|
end
|
@@ -67,51 +69,35 @@ module Virility
|
|
67
69
|
end
|
68
70
|
|
69
71
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
|
73
|
-
def encode url
|
74
|
-
CGI.escape url
|
75
|
-
end
|
76
|
-
|
77
|
-
def url
|
78
|
-
CGI.unescape @url
|
79
|
-
end
|
80
|
-
|
81
|
-
def escaped_url
|
82
|
-
@url
|
83
|
-
end
|
84
|
-
|
85
|
-
#
|
86
|
-
# Camelize
|
72
|
+
# Reflection
|
87
73
|
#
|
88
74
|
|
89
|
-
def
|
90
|
-
|
91
|
-
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
|
92
|
-
else
|
93
|
-
lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
|
94
|
-
end
|
75
|
+
def attributes
|
76
|
+
{:url => @url, :available_strategies => @strategies.keys}
|
95
77
|
end
|
96
78
|
|
97
79
|
#
|
98
|
-
#
|
80
|
+
# Dynamic Methods
|
99
81
|
#
|
100
82
|
|
101
|
-
def
|
102
|
-
|
83
|
+
def get_strategy strategy
|
84
|
+
if strategy_exists?(strategy)
|
85
|
+
@strategies[strategy.to_sym]
|
86
|
+
else
|
87
|
+
raise UnknownStrategy, "#{strategy} Is Not A Known Strategy"
|
88
|
+
end
|
103
89
|
end
|
104
90
|
|
105
|
-
def
|
106
|
-
|
91
|
+
def strategy_exists? strategy
|
92
|
+
!@strategies[strategy.to_sym].nil?
|
107
93
|
end
|
108
94
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
95
|
+
def method_missing(name, *args, &block)
|
96
|
+
if strategy_exists?(name)
|
97
|
+
get_strategy(name)
|
98
|
+
else
|
99
|
+
raise UnknownStrategy, "#{name} Is Not A Known Strategy"
|
100
|
+
end
|
115
101
|
end
|
116
102
|
|
117
103
|
end
|
@@ -1,14 +1,13 @@
|
|
1
1
|
module Virility
|
2
|
-
class Delicious <
|
3
|
-
|
4
|
-
def
|
5
|
-
|
6
|
-
@results = @response.parsed_response.empty? ? {"total_posts" => 0} : @response.parsed_response.first
|
2
|
+
class Delicious < Strategy
|
3
|
+
|
4
|
+
def census
|
5
|
+
self.class.get("http://feeds.delicious.com/v2/json/urlinfo/data?url=#{@url}")
|
7
6
|
end
|
8
|
-
|
7
|
+
|
9
8
|
def count
|
10
|
-
|
9
|
+
results["total_posts"] || 0
|
11
10
|
end
|
12
|
-
|
11
|
+
|
13
12
|
end
|
14
13
|
end
|
@@ -1,14 +1,21 @@
|
|
1
1
|
module Virility
|
2
|
-
class Facebook <
|
3
|
-
BASE_URL = "https://api.facebook.com/method/fql.query?query=SELECT+
|
2
|
+
class Facebook < Strategy
|
3
|
+
BASE_URL = "https://api.facebook.com/method/fql.query?query=SELECT+share_count%2C+like_count%2C+comment_count%2C+total_count%2C+commentsbox_count%2C+click_count+FROM+link_stat+WHERE+url%3D"
|
4
4
|
|
5
5
|
def poll
|
6
6
|
@response = self.class.get("#{BASE_URL}%22#{@url}%22")
|
7
|
-
@results = @response.parsed_response["fql_query_response"]["link_stat"]
|
7
|
+
@results = valid_response_test ? @response.parsed_response["fql_query_response"]["link_stat"] : {"total_count" => 0}
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def count
|
11
|
-
|
11
|
+
results["total_count"] || 0
|
12
12
|
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def valid_response_test
|
17
|
+
@response.respond_to?(:parsed_response) and @response.parsed_response.is_a?(Hash) and !@response.parsed_response["fql_query_response"].nil? and !@response.parsed_response["fql_query_response"]["link_stat"].nil?
|
18
|
+
end
|
19
|
+
|
13
20
|
end
|
14
21
|
end
|
@@ -1,20 +1,19 @@
|
|
1
1
|
module Virility
|
2
|
-
class Pinterest <
|
3
|
-
|
2
|
+
class Pinterest < Strategy
|
3
|
+
|
4
4
|
parser(
|
5
5
|
Proc.new do |body, format|
|
6
6
|
MultiJson.decode(body.scan(/(\{.+\})/).flatten.first)
|
7
7
|
end
|
8
8
|
)
|
9
|
-
|
10
|
-
def
|
11
|
-
|
12
|
-
@results = @response.parsed_response
|
9
|
+
|
10
|
+
def census
|
11
|
+
self.class.get("http://api.pinterest.com/v1/urls/count.json?url=#{@url}")
|
13
12
|
end
|
14
|
-
|
13
|
+
|
15
14
|
def count
|
16
|
-
|
15
|
+
results["count"] || 0
|
17
16
|
end
|
18
|
-
|
17
|
+
|
19
18
|
end
|
20
19
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# http://stackoverflow.com/questions/7403553/how-do-i-get-the-counter-of-a-google-plus-1-button
|
2
2
|
module Virility
|
3
|
-
class PlusOne <
|
3
|
+
class PlusOne < Strategy
|
4
4
|
|
5
5
|
parser(
|
6
6
|
Proc.new do |body, format|
|
@@ -8,13 +8,12 @@ module Virility
|
|
8
8
|
end
|
9
9
|
)
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
@results = @response.parsed_response
|
11
|
+
def census
|
12
|
+
self.class.get("https://plusone.google.com/_/+1/fastbutton?url=#{@url}")
|
14
13
|
end
|
15
14
|
|
16
15
|
def count
|
17
|
-
|
16
|
+
results["shares"].to_i || 0
|
18
17
|
end
|
19
18
|
|
20
19
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Virility
|
2
|
-
class StumbleUpon <
|
2
|
+
class StumbleUpon < Strategy
|
3
3
|
|
4
4
|
parser(
|
5
5
|
Proc.new do |body, format|
|
@@ -7,13 +7,12 @@ module Virility
|
|
7
7
|
end
|
8
8
|
)
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
@results = @response.parsed_response
|
10
|
+
def census
|
11
|
+
self.class.get("http://www.stumbleupon.com/services/1.01/badge.getinfo?url=#{@url}")
|
13
12
|
end
|
14
13
|
|
15
14
|
def count
|
16
|
-
|
15
|
+
results["views"] || 0
|
17
16
|
end
|
18
17
|
|
19
18
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module Virility
|
2
|
-
class Twitter <
|
2
|
+
class Twitter < Strategy
|
3
3
|
|
4
|
-
def
|
5
|
-
|
6
|
-
@results = @response.parsed_response
|
4
|
+
def census
|
5
|
+
self.class.get("http://urls.api.twitter.com/1/urls/count.json?url=#{@url}")
|
7
6
|
end
|
8
7
|
|
9
8
|
def count
|
10
|
-
|
9
|
+
results["count"] || 0
|
11
10
|
end
|
12
11
|
|
13
12
|
end
|