social_net 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +11 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +94 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +264 -0
  7. data/Rakefile +2 -0
  8. data/coverage/.last_run.json +5 -0
  9. data/coverage/.resultset.json +847 -0
  10. data/coverage/.resultset.json.lock +0 -0
  11. data/coverage/assets/0.9.0/application.css +799 -0
  12. data/coverage/assets/0.9.0/application.js +1707 -0
  13. data/coverage/assets/0.9.0/colorbox/border.png +0 -0
  14. data/coverage/assets/0.9.0/colorbox/controls.png +0 -0
  15. data/coverage/assets/0.9.0/colorbox/loading.gif +0 -0
  16. data/coverage/assets/0.9.0/colorbox/loading_background.png +0 -0
  17. data/coverage/assets/0.9.0/favicon_green.png +0 -0
  18. data/coverage/assets/0.9.0/favicon_red.png +0 -0
  19. data/coverage/assets/0.9.0/favicon_yellow.png +0 -0
  20. data/coverage/assets/0.9.0/loading.gif +0 -0
  21. data/coverage/assets/0.9.0/magnify.png +0 -0
  22. data/coverage/assets/0.9.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  23. data/coverage/assets/0.9.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  24. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  25. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  26. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  27. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  28. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  29. data/coverage/assets/0.9.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  30. data/coverage/assets/0.9.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  31. data/coverage/assets/0.9.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  32. data/coverage/assets/0.9.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  33. data/coverage/assets/0.9.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  34. data/coverage/assets/0.9.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  35. data/coverage/index.html +5624 -0
  36. data/lib/social_net/facebook/api/configuration.rb +14 -0
  37. data/lib/social_net/facebook/api/request.rb +66 -0
  38. data/lib/social_net/facebook/config.rb +16 -0
  39. data/lib/social_net/facebook/errors/response_error.rb +14 -0
  40. data/lib/social_net/facebook/errors/unknown_user.rb +11 -0
  41. data/lib/social_net/facebook/errors.rb +2 -0
  42. data/lib/social_net/facebook/models/page.rb +49 -0
  43. data/lib/social_net/facebook/models/user.rb +66 -0
  44. data/lib/social_net/facebook/models.rb +2 -0
  45. data/lib/social_net/facebook.rb +11 -0
  46. data/lib/social_net/instagram/api/configuration.rb +13 -0
  47. data/lib/social_net/instagram/api/request.rb +63 -0
  48. data/lib/social_net/instagram/config.rb +16 -0
  49. data/lib/social_net/instagram/errors/response_error.rb +14 -0
  50. data/lib/social_net/instagram/errors/unknown_user.rb +11 -0
  51. data/lib/social_net/instagram/errors.rb +2 -0
  52. data/lib/social_net/instagram/models/user.rb +70 -0
  53. data/lib/social_net/instagram/models.rb +1 -0
  54. data/lib/social_net/instagram.rb +10 -0
  55. data/lib/social_net/twitter/api/configuration.rb +16 -0
  56. data/lib/social_net/twitter/api/request.rb +121 -0
  57. data/lib/social_net/twitter/config.rb +15 -0
  58. data/lib/social_net/twitter/errors/response_error.rb +14 -0
  59. data/lib/social_net/twitter/errors/suspended_user.rb +11 -0
  60. data/lib/social_net/twitter/errors/too_many_users.rb +11 -0
  61. data/lib/social_net/twitter/errors/unknown_user.rb +11 -0
  62. data/lib/social_net/twitter/errors.rb +4 -0
  63. data/lib/social_net/twitter/models/user.rb +81 -0
  64. data/lib/social_net/twitter/models.rb +1 -0
  65. data/lib/social_net/twitter.rb +11 -0
  66. data/lib/social_net/version.rb +3 -0
  67. data/lib/social_net.rb +7 -0
  68. data/social_net-0.1.0.gem +0 -0
  69. data/social_net.gemspec +30 -0
  70. data/spec/social_net/facebook/models/pages_spec.rb +42 -0
  71. data/spec/social_net/facebook/models/users_spec.rb +44 -0
  72. data/spec/social_net/instagram/models/user_spec.rb +50 -0
  73. data/spec/social_net/twitter/models/user_spec.rb +98 -0
  74. data/spec/spec_helper.rb +11 -0
  75. data/spec/support/cassettes/SocialNet_Instagram_Models_User/_find_by/given_an_existing_case-insensitive_username/returns_an_object_representing_that_user.yml +106 -0
  76. data/spec/support/cassettes/SocialNet_Instagram_Models_User/_find_by/given_an_unknown_username/.yml +51 -0
  77. data/spec/support/cassettes/SocialNet_Instagram_Models_User/_find_by_/given_an_existing_case-insensitive_username/returns_an_object_representing_that_user.yml +106 -0
  78. data/spec/support/cassettes/SocialNet_Instagram_Models_User/_find_by_/given_an_unknown_username/.yml +51 -0
  79. data/spec/support/vcr.rb +22 -0
  80. metadata +245 -0
@@ -0,0 +1,14 @@
1
+ module SocialNet
2
+ module Facebook
3
+ module Api
4
+ class Configuration
5
+ attr_accessor :client_id, :client_secret
6
+
7
+ def initialize
8
+ @client_id = ENV['FACEBOOK_CLIENT_ID']
9
+ @client_secret = ENV['FACEBOOK_CLIENT_SECRET']
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,66 @@
1
+ require 'social_net/facebook/errors/response_error'
2
+ require 'active_support'
3
+ require 'active_support/core_ext'
4
+
5
+ module SocialNet
6
+ module Facebook
7
+ module Api
8
+ class Request
9
+ def initialize(attrs = {})
10
+ @host = 'graph.facebook.com'
11
+ @query = attrs[:username] if attrs[:username]
12
+ @access_token = attrs[:access_token] if attrs[:access_token]
13
+ @path = attrs.fetch :path, "/v2.3/#{@query}"
14
+ @method = attrs.fetch :method, :get
15
+ end
16
+
17
+ def run
18
+ #print "#{as_curl}\n"
19
+ case response = run_http_request
20
+ when Net::HTTPOK
21
+ JSON.parse(response.body)
22
+ else
23
+ raise Errors::ResponseError, response
24
+ end
25
+ end
26
+
27
+ private
28
+ def run_http_request
29
+ Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
30
+ http.request http_request
31
+ end
32
+ end
33
+
34
+ def http_request
35
+ http_class = "Net::HTTP::#{@method.capitalize}".constantize
36
+ @http_request ||= http_class.new(uri.request_uri)
37
+ end
38
+
39
+ def uri
40
+ @uri ||= URI::HTTPS.build host: @host, path: @path, query: access_token
41
+ end
42
+
43
+ def access_token
44
+ @access_token ? { access_token: @access_token }.to_param : fb_app_key_params
45
+ end
46
+
47
+ def fb_app_key_params
48
+ {}.tap do |keys|
49
+ keys.merge! access_token: "#{SocialNet::Facebook.configuration.client_id}|#{SocialNet::Facebook.configuration.client_secret}"
50
+ end.to_param
51
+ end
52
+
53
+ def as_curl
54
+ 'curl'.tap do |curl|
55
+ curl << " -X #{http_request.method}"
56
+ http_request.each_header do |name, value|
57
+ curl << %Q{ -H "#{name}: #{value}"}
58
+ end
59
+ curl << %Q{ -d '#{http_request.body}'} if http_request.body
60
+ curl << %Q{ "#{@uri.to_s}"}
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,16 @@
1
+ require 'social_net/facebook/api/configuration'
2
+
3
+ module SocialNet
4
+ module Facebook
5
+ module Config
6
+ def configure
7
+ yield configuration if block_given?
8
+ end
9
+
10
+ def configuration
11
+ @configuration ||= Api::Configuration.new
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,14 @@
1
+ module SocialNet
2
+ module Facebook
3
+ module Errors
4
+ class ResponseError < StandardError
5
+ attr_reader :response
6
+
7
+ def initialize(response = {})
8
+ @response = response
9
+ super response
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module SocialNet
2
+ module Facebook
3
+ module Errors
4
+ class UnknownUser < StandardError
5
+ def message
6
+ 'Unknown user'
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ require 'social_net/facebook/errors/response_error'
2
+ require 'social_net/facebook/errors/unknown_user'
@@ -0,0 +1,49 @@
1
+ require 'social_net/facebook/api/request'
2
+ require 'social_net/facebook/errors'
3
+
4
+ module SocialNet
5
+ module Facebook
6
+ module Models
7
+ class Page
8
+ attr_reader :username, :likes
9
+
10
+ def initialize(attrs = {})
11
+ @username = attrs['username']
12
+ @likes = attrs['likes']
13
+ end
14
+
15
+
16
+ # Returns the existing Facebook page matching the provided attributes or
17
+ # nil when the page is not found.
18
+ #
19
+ # @return [SocialNet::Facebook::Models::Page] the Facebook page.
20
+ # @ return [nil] when the page cannot be found.
21
+ # @param [Hash] params the attributes to find a page by.
22
+ # @option params [String] :username The Facebook page’s username
23
+ # (case-insensitive).
24
+ def self.find_by(params = {})
25
+ find_by! params
26
+ rescue Errors::UnknownUser
27
+ nil
28
+ end
29
+
30
+ # Returns the existing Facebook page matching the provided attributes or
31
+ # raises an error when the page is not found.
32
+ #
33
+ # @return [SocialNet::Facebook::Models::Page] the Facebook page.
34
+ # @param [Hash] params the attributes to find a page by.
35
+ # @option params [String] :username The Facebook page’s username
36
+ # (case-insensitive).
37
+ # @raise [SocialNet::Errors::UnknownUser] if the page cannot be found.
38
+ def self.find_by!(params = {})
39
+ request = Api::Request.new params
40
+ new request.run
41
+ rescue Errors::ResponseError => error
42
+ case error.response
43
+ when Net::HTTPNotFound then raise Errors::UnknownUser
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,66 @@
1
+ require 'social_net/facebook/api/request'
2
+ require 'social_net/facebook/errors'
3
+
4
+ module SocialNet
5
+ module Facebook
6
+ module Models
7
+ class User
8
+ attr_reader :id, :email, :gender, :first_name, :last_name, :access_token
9
+
10
+ def initialize(attrs = {})
11
+ @id = attrs['id']
12
+ @email = attrs['email']
13
+ @gender = attrs['gender']
14
+ @first_name = attrs['first_name']
15
+ @last_name = attrs['last_name']
16
+ @access_token = attrs['access_token']
17
+ end
18
+
19
+ def pages
20
+ request = Api::Request.new access_token: @access_token, path: "/v2.3/#{@id}/accounts"
21
+ page_json = request.run
22
+ page_json['data'].map { |h| h.slice("name", "id") } if page_json['data'].any?
23
+ end
24
+
25
+ # Returns the existing Facebook user matching the provided attributes or
26
+ # nil when the user is not found.
27
+ #
28
+ # @return [SocialNet::Facebook::Models::User] the Facebook user.
29
+ # @ return [nil] when the user cannot be found.
30
+ # @param [Hash] params the attributes to find a user by.
31
+ # @option params [String] :username The Facebook user's username
32
+ # (case-insensitive).
33
+ # @option params [String] :access_token The Facebook user's access_token
34
+ # (case-insensitive).
35
+ def self.find_by(params = {})
36
+ find_by! params
37
+ rescue Errors::UnknownUser
38
+ nil
39
+ end
40
+
41
+ # Returns the existing Facebook user matching the provided attributes or
42
+ # raises an error when the user is not found.
43
+ #
44
+ # @return [SocialNet::Facebook::Models::User] the Facebook user.
45
+ # @param [Hash] params the attributes to find a user by.
46
+ # @option params [String] :username The Facebook user's username
47
+ # (case-insensitive).
48
+ # @option params [String] :access_token The Facebook user's access_token
49
+ # (case-insensitive).
50
+ # @raise [SocialNet::Errors::UnknownUser] if the user cannot be found.
51
+ def self.find_by!(params = {})
52
+ request = Api::Request.new params
53
+ if params[:access_token]
54
+ new request.run.merge!({"access_token" => params[:access_token]})
55
+ else
56
+ new request.run
57
+ end
58
+ rescue Errors::ResponseError => error
59
+ case error.response
60
+ when Net::HTTPNotFound then raise Errors::UnknownUser
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,2 @@
1
+ require 'social_net/facebook/models/page'
2
+ require 'social_net/facebook/models/user'
@@ -0,0 +1,11 @@
1
+ require 'social_net/facebook/config'
2
+ require 'social_net/facebook/models'
3
+ require 'social_net/facebook/errors'
4
+
5
+ module SocialNet
6
+ module Facebook
7
+ extend Config
8
+ include Errors
9
+ include Models
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module SocialNet
2
+ module Instagram
3
+ module Api
4
+ class Configuration
5
+ attr_accessor :access_token
6
+
7
+ def initialize
8
+ @access_token = ENV['INSTAGRAM_ACCESS_TOKEN']
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,63 @@
1
+ require 'social_net/instagram/errors/response_error'
2
+ require 'social_net/instagram/errors/unknown_user'
3
+ require 'active_support'
4
+ require 'active_support/core_ext'
5
+
6
+ module SocialNet
7
+ module Instagram
8
+ module Api
9
+ class Request
10
+ def initialize(attrs = {})
11
+ @host = 'api.instagram.com'
12
+ @path = attrs.fetch :path, "/v1/#{attrs[:endpoint]}"
13
+ @query = attrs[:params] if attrs[:params]
14
+ @method = attrs.fetch :method, :get
15
+ end
16
+
17
+ def run
18
+ #print "#{as_curl}\n"
19
+ case response = run_http_request
20
+ when Net::HTTPOK
21
+ JSON(response.body)['data']
22
+ else
23
+ raise Errors::ResponseError, response
24
+ end
25
+ end
26
+
27
+ private
28
+ def run_http_request
29
+ Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
30
+ http.request http_request
31
+ end
32
+ end
33
+
34
+ def http_request
35
+ http_class = "Net::HTTP::#{@method.capitalize}".constantize
36
+ @http_request ||= http_class.new(uri.request_uri)
37
+ end
38
+
39
+ def uri
40
+ @uri ||= URI::HTTPS.build host: @host, path: @path, query: query
41
+ end
42
+
43
+ def query
44
+ {}.tap do |query|
45
+ query.merge! @query if @query
46
+ query.merge! access_token: SocialNet::Instagram.configuration.access_token
47
+ end.to_param
48
+ end
49
+
50
+ def as_curl
51
+ 'curl'.tap do |curl|
52
+ curl << " -X #{http_request.method}"
53
+ http_request.each_header do |name, value|
54
+ curl << %Q{ -H "#{name}: #{value}"}
55
+ end
56
+ curl << %Q{ -d '#{http_request.body}'} if http_request.body
57
+ curl << %Q{ "#{@uri.to_s}"}
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,16 @@
1
+ require 'social_net/instagram/api/configuration'
2
+
3
+ module SocialNet
4
+ module Instagram
5
+ module Config
6
+ def configure
7
+ yield configuration if block_given?
8
+ end
9
+
10
+ def configuration
11
+ @configuration ||= Api::Configuration.new
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,14 @@
1
+ module SocialNet
2
+ module Instagram
3
+ module Errors
4
+ class ResponseError < StandardError
5
+ attr_reader :response
6
+
7
+ def initialize(response = {})
8
+ @response = response
9
+ super response
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module SocialNet
2
+ module Instagram
3
+ module Errors
4
+ class UnknownUser < StandardError
5
+ def message
6
+ 'Unknown user'
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ require 'social_net/instagram/errors/response_error'
2
+ require 'social_net/instagram/errors/unknown_user'
@@ -0,0 +1,70 @@
1
+ require 'social_net/instagram/api/request'
2
+ require 'social_net/instagram/errors'
3
+
4
+ module SocialNet
5
+ module Instagram
6
+ module Models
7
+ class User
8
+ attr_reader :username, :follower_count
9
+
10
+ def initialize(attrs = {})
11
+ @username = attrs['username']
12
+ @follower_count = attrs['counts']['followed_by']
13
+ end
14
+
15
+ # Returns the existing Instagram user matching the provided attributes or
16
+ # nil when the user is not found.
17
+ #
18
+ # @return [SocialNet::Instagram::Models::User] when the user is found.
19
+ # @return [nil] when the user is not found or has a private account.
20
+ # @param [Hash] params the attributes to find a user by.
21
+ # @option params [String] :username The Instagram user’s username
22
+ # (case-insensitive).
23
+ def self.find_by(params = {})
24
+ find_by! params
25
+ rescue Errors::UnknownUser
26
+ nil
27
+ end
28
+
29
+ # Returns the existing Instagram user matching the provided attributes or
30
+ # nil when the user is not found, and raises an error when the user account is private.
31
+ #
32
+ # @return [SocialNet::Instagram::Models::User] the Instagram user.
33
+ # @param [Hash] params the attributes to find a user by.
34
+ # @option params [String] :username The Instagram user’s username
35
+ # (case-insensitive).
36
+ # @option params [String] :id The Instagram user’s id
37
+ # (case-insensitive).
38
+ # @raise [SocialNet::Errors::PrivateUser] if the user account is private.
39
+ def self.find_by!(params = {})
40
+ if params[:username]
41
+ find_by_username! params[:username]
42
+ elsif params[:id]
43
+ find_by_id! params[:id]
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def self.find_by_username!(username)
50
+ request = Api::Request.new endpoint: "users/search", params: {q: username}
51
+ users = Array.wrap request.run
52
+ if user = users.find{|u| u['username'].casecmp(username).zero?}
53
+ find_by_id! user['id']
54
+ else
55
+ raise Errors::UnknownUser
56
+ end
57
+ end
58
+
59
+ def self.find_by_id!(id)
60
+ request = Api::Request.new endpoint: "users/#{id}"
61
+ new request.run
62
+ rescue Errors::ResponseError => error
63
+ case error.response
64
+ when Net::HTTPBadRequest then raise Errors::PrivateUser
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1 @@
1
+ require 'social_net/instagram/models/user'
@@ -0,0 +1,10 @@
1
+ require 'social_net/instagram/config'
2
+ require 'social_net/instagram/models'
3
+
4
+ module SocialNet
5
+ module Instagram
6
+ extend Config
7
+ include Errors
8
+ include Models
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ module SocialNet
2
+ module Twitter
3
+ module Api
4
+ class Configuration
5
+ attr_accessor :apps
6
+
7
+ def initialize
8
+ @apps = []
9
+ env_key = ENV['TWITTER_API_KEY']
10
+ env_secret = ENV['TWITTER_API_SECRET']
11
+ @apps.push key: env_key, secret: env_secret if env_key && env_secret
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,121 @@
1
+ require 'social_net/twitter/errors/response_error'
2
+ require 'active_support'
3
+ require 'active_support/core_ext'
4
+
5
+ module SocialNet
6
+ module Twitter
7
+ module Api
8
+ class Request
9
+ def initialize(attrs = {})
10
+ @host = 'api.twitter.com'
11
+ @path = attrs.fetch :path, "/1.1/#{attrs[:endpoint]}.json"
12
+ @query = attrs[:params].to_param if attrs[:params]
13
+ @block = attrs.fetch :block, -> (request) {add_access_token! request}
14
+ @method = attrs.fetch :method, :get
15
+ end
16
+
17
+ def run
18
+ #print "#{as_curl}\n"
19
+
20
+ case response = run_http_request
21
+ when Net::HTTPOK
22
+ JSON response.body
23
+ when Net::HTTPTooManyRequests
24
+ store_rate_limit_reset response.header["x-rate-limit-reset"].to_i
25
+ run
26
+ else
27
+ raise Errors::ResponseError, response
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def run_http_request
34
+ Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
35
+ http.request http_request
36
+ end
37
+ end
38
+
39
+ def http_request
40
+ http_class = "Net::HTTP::#{@method.capitalize}".constantize
41
+ @http_request ||= http_class.new(uri.request_uri).tap do |request|
42
+ @block.call request
43
+ end
44
+ end
45
+
46
+ def uri
47
+ @uri ||= URI::HTTPS.build host: @host, path: @path, query: @query
48
+ end
49
+
50
+ def add_access_token!(request)
51
+ request.add_field 'Authorization', "Bearer #{access_token}"
52
+ end
53
+
54
+ def access_token
55
+ @@access_token ||= fetch_access_token
56
+ end
57
+
58
+ def fetch_access_token
59
+ path = '/oauth2/token'
60
+ block = -> (request) {add_client_credentials! request}
61
+ request = Request.new path: path, method: :post, block: block
62
+ authentication_data = request.run
63
+ authentication_data['access_token']
64
+ # rescue Errors::Suspended
65
+ # require 'pry'; binding.pry; true;
66
+ end
67
+
68
+ def add_client_credentials!(request)
69
+ request.initialize_http_header client_credentials_headers
70
+ request.add_field 'Authorization', "Basic #{credentials}"
71
+ request.set_form_data grant_type: 'client_credentials'
72
+ end
73
+
74
+ def client_credentials_headers
75
+ content_type = 'application/x-www-form-urlencoded;charset=UTF-8'
76
+ {}.tap{|headers| headers['Content-Type'] = content_type}
77
+ end
78
+
79
+ def credentials
80
+ @@app = apps.find(next_available_app) do |app|
81
+ app[:limit_reset].to_i < Time.now.to_i
82
+ end
83
+ Base64.strict_encode64 "#{@@app[:key]}:#{@@app[:secret]}"
84
+ end
85
+
86
+ def next_available_app
87
+ Proc.new do
88
+ next_limit_reset = @@apps.map{|app| app[:limit_reset]}.min
89
+ sleep_time = next_limit_reset - Time.now.to_i
90
+ puts "Sleeping for #{sleep_time}s\n"
91
+ sleep sleep_time
92
+ puts "Waking up\n"
93
+ @@apps.find{|app| app[:limit_reset] == next_limit_reset}
94
+ end
95
+ end
96
+
97
+ def store_rate_limit_reset(limit_reset)
98
+ @@app[:limit_reset] = limit_reset
99
+ @@access_token, @@app, @http_request = nil, nil, nil
100
+ end
101
+
102
+ def apps
103
+ @@apps ||= SocialNet::Twitter.configuration.apps.map do |app|
104
+ app.tap{app[:limit_reset] = nil}
105
+ end
106
+ end
107
+
108
+ def as_curl
109
+ 'curl'.tap do |curl|
110
+ curl << " -X #{http_request.method}"
111
+ http_request.each_header do |name, value|
112
+ curl << %Q{ -H "#{name}: #{value}"}
113
+ end
114
+ curl << %Q{ -d '#{http_request.body}'} if http_request.body
115
+ curl << %Q{ "#{@uri.to_s}"}
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,15 @@
1
+ require 'social_net/twitter/api/configuration'
2
+
3
+ module SocialNet
4
+ module Twitter
5
+ module Config
6
+ def configure
7
+ yield configuration if block_given?
8
+ end
9
+
10
+ def configuration
11
+ @configuration ||= Api::Configuration.new
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module SocialNet
2
+ module Twitter
3
+ module Errors
4
+ class ResponseError < StandardError
5
+ attr_reader :response
6
+
7
+ def initialize(response = {})
8
+ @response = response
9
+ super response
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module SocialNet
2
+ module Twitter
3
+ module Errors
4
+ class SuspendedUser < StandardError
5
+ def message
6
+ 'Suspended user'
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module SocialNet
2
+ module Twitter
3
+ module Errors
4
+ class TooManyUsers < StandardError
5
+ def message
6
+ 'Too many users in the request'
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module SocialNet
2
+ module Twitter
3
+ module Errors
4
+ class UnknownUser < StandardError
5
+ def message
6
+ 'Unknown user'
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end