share_counts 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  pkg/*
2
2
  *.gem
3
3
  .bundle
4
+ check.rb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- share_counts (0.0.1)
4
+ share_counts (0.0.2)
5
5
  json
6
6
  nokogiri
7
7
  redis
@@ -1,110 +1,112 @@
1
- module ShareCountsCaching
2
-
3
- #
4
- #
5
- # Returns true if the Redis
6
- # cache store has been initialised
7
- #
8
- #
9
- def cache_enabled?
10
- !$share_counts_cache.nil?
11
- end
1
+ module ShareCounts
2
+ module Caching
12
3
 
4
+ #
5
+ #
6
+ # Returns true if the Redis
7
+ # cache store has been initialised
8
+ #
9
+ #
10
+ def cache_enabled?
11
+ !$share_counts_cache.nil?
12
+ end
13
13
 
14
14
 
15
- #
16
- #
17
- # Removes from Redis cache store all the keys
18
- # used by ShareCounts.
19
- #
20
- #
21
- def clear_cache
22
- ($share_counts_cache || {}).keys.select{|cache_key| cache_key =~ /^ShareCounts/ }.each{|cache_key|
23
- $share_counts_cache.del cache_key}
24
- end
25
-
26
-
27
- #
28
- #
29
- # Returns the cached share counts available for each URL, in the format
30
- #
31
- # {
32
- # "URL 1": {
33
- # :reddit => N,
34
- # :digg => N,
35
- # :twitter => N,
36
- # :facebook => N,
37
- # :fblike => N,
38
- # :linkedin => N,
39
- # :googlebuzz => N,
40
- # :stumbleupon => N
41
- # },
42
- #
43
- # "URL 2": {
44
- # ...
45
- # }
46
- # }
47
- #
48
- #
49
- def cached
50
- urls = ($share_counts_cache || {}).keys.select{|k| k =~ /^ShareCounts/ }.inject({}) do |result, key|
51
- data = key.split("||"); network = data[1]; url = data[2];
52
- count = from_redis("ShareCounts||#{network}||#{url}")
53
- (result[url] ||= {})[network.to_sym] = count unless ["all", "fball"].include? network
54
- result
15
+
16
+ #
17
+ #
18
+ # Removes from Redis cache store all the keys
19
+ # used by ShareCounts.
20
+ #
21
+ #
22
+ def clear_cache
23
+ ($share_counts_cache || {}).keys.select{|cache_key| cache_key =~ /^ShareCounts/ }.each{|cache_key|
24
+ $share_counts_cache.del cache_key}
55
25
  end
56
- urls
57
- end
58
-
59
- #
60
- #
61
- # Enables caching with Redis.
62
- #
63
- # By default, it connects to 127.0.0.1:6379, but it is also
64
- # possible to specify in the arguments :host, :port the
65
- # connection details.
66
- #
67
- # If the application using this gem is already using Redis too,
68
- # with the "redis" gem, it is possible to use the existing
69
- # instance of Redis by either setting the :redist_store argument
70
- # or by setting the global variable $share_counts_cache first.
71
- #
72
- #
73
- def use_cache *args
74
- arguments = args.inject({}) { |r, c| r.merge(c) }
75
- $share_counts_cache ||= arguments[:redis_store] ||
76
- Redis.new(:host => arguments[:host] || "127.0.0.1", :port => arguments[:port] || "6379")
77
- end
78
26
 
79
27
 
80
- private
81
-
82
- #
83
- #
84
- # Caches the given value in Redis under the key specified.
85
- # By default the value is cached for two minutes, but it
86
- # is also possible to override this expiration time by
87
- # setting the global variable $share_counts_cache_expire
88
- # to a number of seconds.
89
- #
90
- #
91
- def to_redis(cache_key, value)
92
- $share_counts_cache.set cache_key, Marshal.dump(value)
93
- $share_counts_cache.expire cache_key, $share_counts_cache_expire || 120
94
- value
95
- end
28
+ #
29
+ #
30
+ # Returns the cached share counts available for each URL, in the format
31
+ #
32
+ # {
33
+ # "URL 1": {
34
+ # :reddit => N,
35
+ # :digg => N,
36
+ # :twitter => N,
37
+ # :facebook => N,
38
+ # :fblike => N,
39
+ # :linkedin => N,
40
+ # :googlebuzz => N,
41
+ # :stumbleupon => N
42
+ # },
43
+ #
44
+ # "URL 2": {
45
+ # ...
46
+ # }
47
+ # }
48
+ #
49
+ #
50
+ def cached
51
+ urls = ($share_counts_cache || {}).keys.select{|k| k =~ /^ShareCounts/ }.inject({}) do |result, key|
52
+ data = key.split("||"); network = data[1]; url = data[2];
53
+ count = from_redis("ShareCounts||#{network}||#{url}")
54
+ (result[url] ||= {})[network.to_sym] = count unless ["all", "fball"].include? network
55
+ result
56
+ end
57
+ urls
58
+ end
59
+
60
+ #
61
+ #
62
+ # Enables caching with Redis.
63
+ #
64
+ # By default, it connects to 127.0.0.1:6379, but it is also
65
+ # possible to specify in the arguments :host, :port the
66
+ # connection details.
67
+ #
68
+ # If the application using this gem is already using Redis too,
69
+ # with the "redis" gem, it is possible to use the existing
70
+ # instance of Redis by either setting the :redist_store argument
71
+ # or by setting the global variable $share_counts_cache first.
72
+ #
73
+ #
74
+ def use_cache *args
75
+ arguments = args.inject({}) { |r, c| r.merge(c) }
76
+ $share_counts_cache ||= arguments[:redis_store] ||
77
+ Redis.new(:host => arguments[:host] || "127.0.0.1", :port => arguments[:port] || "6379")
78
+ end
79
+
80
+
81
+ private
82
+
83
+ #
84
+ #
85
+ # Caches the given value in Redis under the key specified.
86
+ # By default the value is cached for two minutes, but it
87
+ # is also possible to override this expiration time by
88
+ # setting the global variable $share_counts_cache_expire
89
+ # to a number of seconds.
90
+ #
91
+ #
92
+ def to_redis(cache_key, value)
93
+ $share_counts_cache.set cache_key, Marshal.dump(value)
94
+ $share_counts_cache.expire cache_key, $share_counts_cache_expire || 120
95
+ value
96
+ end
97
+
98
+
99
+ #
100
+ #
101
+ # Retrieves the value stores in Redis under
102
+ # the given key.
103
+ #
104
+ #
105
+ def from_redis(cache_key)
106
+ value = $share_counts_cache.get(cache_key)
107
+ return if value.nil?
108
+ Marshal.load value
109
+ end
96
110
 
97
-
98
- #
99
- #
100
- # Retrieves the value stores in Redis under
101
- # the given key.
102
- #
103
- #
104
- def from_redis(cache_key)
105
- value = $share_counts_cache.get(cache_key)
106
- return if value.nil?
107
- Marshal.load value
108
111
  end
109
-
110
- end
112
+ end
@@ -1,106 +1,108 @@
1
- module ShareCountsCommon
1
+ module ShareCounts
2
+ module Common
2
3
 
3
- private
4
-
5
- #
6
- #
7
- # Given the name of one of the supported social networks and a URL,
8
- # attempts the execution of the given block to fetch the relevant share count.
9
- #
10
- # If caching with Redis is enabled, it will first try to
11
- # fetch the share count from cache instead, if there is a valid
12
- # cached value for the combination of network/URL. When a share count is
13
- # instead retrieved with an HTTP request to the network's API and
14
- # the caching with Redis is enabled, the value fetched is also cached.
15
- #
16
- # NOTE: caching will be skipped if the block fails.
17
- #
18
- #
19
- def try service, url, &block
20
- cache_key = "ShareCounts||#{service}||#{url}"
21
- if cache_enabled?
22
- if result = from_redis(cache_key)
23
- puts "Loaded #{service} count from cache"
24
- result
4
+ private
5
+
6
+ #
7
+ #
8
+ # Given the name of one of the supported social networks and a URL,
9
+ # attempts the execution of the given block to fetch the relevant share count.
10
+ #
11
+ # If caching with Redis is enabled, it will first try to
12
+ # fetch the share count from cache instead, if there is a valid
13
+ # cached value for the combination of network/URL. When a share count is
14
+ # instead retrieved with an HTTP request to the network's API and
15
+ # the caching with Redis is enabled, the value fetched is also cached.
16
+ #
17
+ # NOTE: caching will be skipped if the block fails.
18
+ #
19
+ #
20
+ def try service, url, &block
21
+ cache_key = "ShareCounts||#{service}||#{url}"
22
+ if cache_enabled?
23
+ if result = from_redis(cache_key)
24
+ puts "Loaded #{service} count from cache"
25
+ result
26
+ else
27
+ puts "Making request to #{service}..."
28
+ to_redis(cache_key, yield)
29
+ end
25
30
  else
26
- puts "Making request to #{service}..."
27
- to_redis(cache_key, yield)
31
+ puts "Redis caching is disabled - Making request to #{service}..."
32
+ yield
28
33
  end
29
- else
30
- puts "Redis caching is disabled - Making request to #{service}..."
31
- yield
34
+ rescue Exception => e
35
+ puts "Something went wrong with #{service}: #{e}"
32
36
  end
33
- rescue Exception => e
34
- puts "Something went wrong with #{service}: #{e}"
35
- end
36
37
 
37
38
 
38
- #
39
- #
40
- # Performs an HTTP request to the given API URL with the specified params
41
- # and within 2 seconds, and max 3 attempts
42
- #
43
- # If a :callback param is also specified, then it is assumed that the API
44
- # returns a JSON text wrapped in a call to a method by that callback name,
45
- # therefore in this case it manipulates the response to extract only
46
- # the JSON data required.
47
- #
48
- def make_request *args
49
- result = nil
50
- attempts = 1
39
+ #
40
+ #
41
+ # Performs an HTTP request to the given API URL with the specified params
42
+ # and within 2 seconds, and max 3 attempts
43
+ #
44
+ # If a :callback param is also specified, then it is assumed that the API
45
+ # returns a JSON text wrapped in a call to a method by that callback name,
46
+ # therefore in this case it manipulates the response to extract only
47
+ # the JSON data required.
48
+ #
49
+ def make_request *args
50
+ result = nil
51
+ attempts = 1
51
52
 
52
- begin
53
- timeout(2) do
54
- url = args.shift
55
- params = args.inject({}) { |r, c| r.merge! c }
56
- response = RestClient.get url, { :params => params }
53
+ begin
54
+ timeout(2) do
55
+ url = args.shift
56
+ params = args.inject({}) { |r, c| r.merge! c }
57
+ response = RestClient.get url, { :params => params }
57
58
 
58
59
 
59
- # if a callback is specified, the expected response is in the format "callback_name(JSON data)";
60
- # with the response ending with ";" and, in some cases, "\n"
61
- result = params.keys.include?(:callback) \
62
- ? response.gsub(/^(.*);+\n*$/, "\\1").gsub(/^#{params[:callback]}\((.*)\)$/, "\\1") \
63
- : response
60
+ # if a callback is specified, the expected response is in the format "callback_name(JSON data)";
61
+ # with the response ending with ";" and, in some cases, "\n"
62
+ result = params.keys.include?(:callback) \
63
+ ? response.gsub(/^(.*);+\n*$/, "\\1").gsub(/^#{params[:callback]}\((.*)\)$/, "\\1") \
64
+ : response
65
+ end
66
+
67
+ rescue Exception => e
68
+ puts "Failed #{attempts} attempt(s)"
69
+ attempts += 1
70
+ retry if attempts <= 3
64
71
  end
65
-
66
- rescue Exception => e
67
- puts "Failed #{attempts} attempt(s)"
68
- attempts += 1
69
- retry if attempts <= 3
72
+
73
+ result
70
74
  end
71
-
72
- result
73
- end
74
75
 
75
76
 
76
- #
77
- #
78
- # Makes an HTTP request with the given URL and params, and assumes
79
- # that the response is in JSON format, therefore it returns
80
- # the parsed JSON.
81
- #
82
- #
83
- def from_json *args
84
- JSON.parse make_request *args
85
- end
77
+ #
78
+ #
79
+ # Makes an HTTP request with the given URL and params, and assumes
80
+ # that the response is in JSON format, therefore it returns
81
+ # the parsed JSON.
82
+ #
83
+ #
84
+ def from_json *args
85
+ JSON.parse make_request *args
86
+ end
86
87
 
87
- #
88
- #
89
- # Most social networks' APIs returns normal JSON data;
90
- # this method simply extracts directly the share count from
91
- # the given JSON data, by following a pattern common to the
92
- # structure of most JSON responses.
93
- #
94
- # It also requires a :selector argument that determines how
95
- # to "query" the JSON data in a way that emulates XPATH,
96
- # so to extract the share count.
97
- #
98
- #
99
- def extract_count *args
100
- json = args.shift
101
- result = args.first.flatten.last.split("/").inject( json.is_a?(Array) ? json.first : json ) {
102
- |r, c| r[c].is_a?(Array) ? r[c].first : r[c]
103
- }
104
- end
88
+ #
89
+ #
90
+ # Most social networks' APIs returns normal JSON data;
91
+ # this method simply extracts directly the share count from
92
+ # the given JSON data, by following a pattern common to the
93
+ # structure of most JSON responses.
94
+ #
95
+ # It also requires a :selector argument that determines how
96
+ # to "query" the JSON data in a way that emulates XPATH,
97
+ # so to extract the share count.
98
+ #
99
+ #
100
+ def extract_count *args
101
+ json = args.shift
102
+ result = args.first.flatten.last.split("/").inject( json.is_a?(Array) ? json.first : json ) {
103
+ |r, c| r[c].is_a?(Array) ? r[c].first : r[c]
104
+ }
105
+ end
105
106
 
106
- end
107
+ end
108
+ end
data/lib/share_counts.rb CHANGED
@@ -5,8 +5,8 @@ require File.expand_path(File.dirname(__FILE__) + "/share_counts/caching")
5
5
 
6
6
  module ShareCounts
7
7
 
8
- extend ShareCountsCommon
9
- extend ShareCountsCaching
8
+ extend Common
9
+ extend Caching
10
10
 
11
11
  def self.supported_networks
12
12
  %w(reddit digg twitter facebook fblike linkedin googlebuzz stumbleupon)
data/share_counts.gemspec CHANGED
@@ -4,7 +4,7 @@ $:.push File.expand_path("../lib/share_counts", __FILE__)
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "share_counts"
7
- s.version = "0.0.2"
7
+ s.version = "0.0.3"
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Vito Botta"]
10
10
  s.email = ["vito@botta.name"]
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 2
9
- version: 0.0.2
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Vito Botta
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-01-30 00:00:00 +00:00
17
+ date: 2011-01-31 00:00:00 +00:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency