angellist_api 1.0.1 → 1.0.2

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.
Files changed (94) hide show
  1. data/CHANGELOG.md +15 -0
  2. data/README.md +11 -6
  3. data/Rakefile +9 -0
  4. data/lib/angellist_api.rb +1 -3
  5. data/lib/angellist_api/api.rb +2 -4
  6. data/lib/angellist_api/authentication.rb +0 -1
  7. data/lib/angellist_api/client.rb +9 -1
  8. data/lib/angellist_api/client/activity_feeds.rb +29 -8
  9. data/lib/angellist_api/client/follows.rb +105 -63
  10. data/lib/angellist_api/client/jobs.rb +72 -0
  11. data/lib/angellist_api/client/reviews.rb +17 -6
  12. data/lib/angellist_api/client/search.rb +31 -0
  13. data/lib/angellist_api/client/startup_roles.rb +23 -8
  14. data/lib/angellist_api/client/startups.rb +49 -13
  15. data/lib/angellist_api/client/status_updates.rb +45 -24
  16. data/lib/angellist_api/client/tags.rb +52 -30
  17. data/lib/angellist_api/client/users.rb +39 -17
  18. data/lib/angellist_api/configuration.rb +24 -29
  19. data/lib/angellist_api/connection.rb +27 -29
  20. data/lib/angellist_api/core_ext/hash.rb +19 -0
  21. data/lib/angellist_api/error.rb +9 -32
  22. data/lib/angellist_api/error/bad_gateway.rb +7 -0
  23. data/lib/angellist_api/error/bad_request.rb +7 -0
  24. data/lib/angellist_api/error/enhance_your_calm.rb +13 -0
  25. data/lib/angellist_api/error/forbidden.rb +7 -0
  26. data/lib/angellist_api/error/internal_server_error.rb +7 -0
  27. data/lib/angellist_api/error/not_acceptable.rb +7 -0
  28. data/lib/angellist_api/error/not_found.rb +7 -0
  29. data/lib/angellist_api/error/service_unavailable.rb +7 -0
  30. data/lib/angellist_api/error/unauthorized.rb +7 -0
  31. data/lib/angellist_api/request.rb +11 -18
  32. data/lib/angellist_api/request/angellist_api_oauth.rb +16 -0
  33. data/lib/angellist_api/request/gateway.rb +18 -0
  34. data/lib/angellist_api/request/multipart_with_file.rb +36 -0
  35. data/lib/angellist_api/response/raise_client_error.rb +51 -0
  36. data/lib/angellist_api/response/raise_server_error.rb +27 -0
  37. data/lib/angellist_api/version.rb +1 -1
  38. data/spec/fixtures/cassettes/activity_feeds.yml +273 -0
  39. data/spec/fixtures/cassettes/follows.yml +1722 -0
  40. data/spec/fixtures/cassettes/jobs.yml +2052 -0
  41. data/spec/fixtures/cassettes/reviews.yml +93 -0
  42. data/spec/fixtures/cassettes/search.yml +169 -0
  43. data/spec/fixtures/cassettes/startup_roles.yml +1481 -0
  44. data/spec/fixtures/cassettes/startups.yml +532 -0
  45. data/spec/fixtures/cassettes/status_updates.yml +125 -0
  46. data/spec/fixtures/cassettes/tags.yml +762 -0
  47. data/spec/fixtures/cassettes/users.yml +275 -0
  48. data/spec/integration/activity_feeds_spec.rb +29 -0
  49. data/spec/integration/follows_spec.rb +60 -0
  50. data/spec/integration/jobs_spec.rb +36 -0
  51. data/spec/integration/reviews_spec.rb +15 -0
  52. data/spec/integration/search_spec.rb +27 -0
  53. data/spec/integration/startup_roles_spec.rb +25 -0
  54. data/spec/integration/startups_spec.rb +36 -0
  55. data/spec/integration/status_updates_spec.rb +18 -0
  56. data/spec/integration/tags_spec.rb +29 -0
  57. data/spec/integration/users_spec.rb +23 -0
  58. data/spec/spec_helper.rb +5 -2
  59. data/spec/support/vcr.rb +12 -0
  60. data/spec/{lib → unit/lib}/angellist_api/api_spec.rb +13 -15
  61. data/spec/unit/lib/angellist_api/authentication_spec.rb +49 -0
  62. data/spec/unit/lib/angellist_api/client/activity_feeds_spec.rb +22 -0
  63. data/spec/unit/lib/angellist_api/client/follows_spec.rb +82 -0
  64. data/spec/unit/lib/angellist_api/client/jobs_spec.rb +39 -0
  65. data/spec/unit/lib/angellist_api/client/reviews_spec.rb +14 -0
  66. data/spec/unit/lib/angellist_api/client/search_spec.rb +15 -0
  67. data/spec/unit/lib/angellist_api/client/startup_roles_spec.rb +14 -0
  68. data/spec/unit/lib/angellist_api/client/startups_spec.rb +40 -0
  69. data/spec/unit/lib/angellist_api/client/status_updates_spec.rb +30 -0
  70. data/spec/unit/lib/angellist_api/client/tags_spec.rb +39 -0
  71. data/spec/unit/lib/angellist_api/client/users_spec.rb +39 -0
  72. data/spec/{lib → unit/lib}/angellist_api/configuration_spec.rb +12 -11
  73. data/spec/unit/lib/angellist_api/error_spec.rb +124 -0
  74. data/spec/unit/lib/angellist_api/request_spec.rb +32 -0
  75. data/spec/unit/lib/angellist_api_spec.rb +42 -0
  76. metadata +128 -71
  77. data/lib/faraday/request/angellist_api_oauth.rb +0 -14
  78. data/lib/faraday/request/gateway.rb +0 -18
  79. data/lib/faraday/request/multipart_with_file.rb +0 -36
  80. data/lib/faraday/request/phoenix.rb +0 -18
  81. data/lib/faraday/response/raise_http_4xx.rb +0 -45
  82. data/lib/faraday/response/raise_http_5xx.rb +0 -24
  83. data/spec/lib/angellist_api/authentication_spec.rb +0 -53
  84. data/spec/lib/angellist_api/client/activity_feeds_spec.rb +0 -16
  85. data/spec/lib/angellist_api/client/follows_spec.rb +0 -74
  86. data/spec/lib/angellist_api/client/reviews_spec.rb +0 -16
  87. data/spec/lib/angellist_api/client/startup_roles_spec.rb +0 -16
  88. data/spec/lib/angellist_api/client/startups_spec.rb +0 -23
  89. data/spec/lib/angellist_api/client/status_updates_spec.rb +0 -32
  90. data/spec/lib/angellist_api/client/tags_spec.rb +0 -40
  91. data/spec/lib/angellist_api/client/users_spec.rb +0 -30
  92. data/spec/lib/angellist_api/error_spec.rb +0 -126
  93. data/spec/lib/angellist_api/request_spec.rb +0 -51
  94. data/spec/lib/angellist_api_spec.rb +0 -38
@@ -3,42 +3,38 @@ require 'angellist_api/version'
3
3
  module AngellistApi
4
4
  # Defines constants and methods related to configuration
5
5
  module Configuration
6
- # An array of valid keys in the options hash when configuring a {AngellistApi::API}
7
- VALID_OPTIONS_KEYS = [
8
- :adapter,
9
- :endpoint,
10
- :format,
11
- :gateway,
12
- :access_token,
13
- :proxy,
14
- :user_agent,
15
- :faraday_options].freeze
6
+ # The access token if none is set
7
+ DEFAULT_ACCESS_TOKEN = nil
16
8
 
17
- # The adapter that will be used to connect if none is set
9
+ # The HTTP connection adapter that will be used to connect if none is set
18
10
  DEFAULT_ADAPTER = :net_http
19
11
 
20
- # The endpoint that will be used to connect if none is set
21
- DEFAULT_ENDPOINT = "https://api.angel.co/".freeze
12
+ # The Faraday connection options if none are set
13
+ DEFAULT_CONNECTION_OPTIONS = {}
22
14
 
23
- # The response format appended to the path and sent in the 'Accept' header if none is set
24
- #
25
- # @note JSON is preferred over XML because it is more concise and faster to parse.
26
- DEFAULT_FORMAT = :json
15
+ # The endpoint that will be used to connect if none is set
16
+ DEFAULT_ENDPOINT = "https://api.angel.co/"
27
17
 
28
- # By default, don't set a user oauth access token
29
- DEFAULT_ACCESS_TOKEN = nil
18
+ # The gateway server if none is set
19
+ DEFAULT_GATEWAY = nil
30
20
 
31
- # By default, don't use a proxy server
21
+ # The proxy server if none is set
32
22
  DEFAULT_PROXY = nil
33
23
 
34
24
  # The value sent in the 'User-Agent' header if none is set
35
- DEFAULT_USER_AGENT = "AngellistApi Ruby Gem #{AngellistApi::VERSION}".freeze
25
+ DEFAULT_USER_AGENT = "AngellistApi Ruby Gem #{AngellistApi::VERSION}"
36
26
 
37
- DEFAULT_GATEWAY = nil
38
-
39
- DEFAULT_FARADAY_OPTIONS = {}.freeze
27
+ # An array of valid keys in the options hash when configuring a {AngellistApi::API}
28
+ VALID_OPTIONS_KEYS = [
29
+ :adapter,
30
+ :connection_options,
31
+ :endpoint,
32
+ :gateway,
33
+ :access_token,
34
+ :proxy,
35
+ :user_agent
36
+ ]
40
37
 
41
- # @private
42
38
  attr_accessor *VALID_OPTIONS_KEYS
43
39
 
44
40
  # When this module is extended, set all configuration options to their default values
@@ -60,14 +56,13 @@ module AngellistApi
60
56
 
61
57
  # Reset all configuration options to defaults
62
58
  def reset
59
+ self.access_token = DEFAULT_ACCESS_TOKEN
63
60
  self.adapter = DEFAULT_ADAPTER
61
+ self.connection_options = DEFAULT_CONNECTION_OPTIONS
64
62
  self.endpoint = DEFAULT_ENDPOINT
65
- self.format = DEFAULT_FORMAT
66
- self.access_token = DEFAULT_ACCESS_TOKEN
63
+ self.gateway = DEFAULT_GATEWAY
67
64
  self.proxy = DEFAULT_PROXY
68
65
  self.user_agent = DEFAULT_USER_AGENT
69
- self.gateway = DEFAULT_GATEWAY
70
- self.faraday_options = DEFAULT_FARADAY_OPTIONS
71
66
  self
72
67
  end
73
68
  end
@@ -1,48 +1,46 @@
1
+ require 'faraday'
1
2
  require 'faraday_middleware'
2
- require 'faraday/request/phoenix'
3
- require 'faraday/request/multipart_with_file'
4
- require 'faraday/request/gateway'
5
- require 'faraday/request/angellist_api_oauth'
6
- require 'faraday/response/raise_http_4xx'
7
- require 'faraday/response/raise_http_5xx'
3
+ require 'angellist_api/core_ext/hash'
4
+ require 'angellist_api/request/multipart_with_file'
5
+ require 'angellist_api/request/gateway'
6
+ require 'angellist_api/request/angellist_api_oauth'
7
+ require 'angellist_api/response/raise_client_error'
8
+ require 'angellist_api/response/raise_server_error'
8
9
 
9
10
  module AngellistApi
10
- # @private
11
11
  module Connection
12
12
  private
13
13
 
14
+ # Returns a Faraday::Connection object
15
+ #
16
+ # @param options [Hash] A hash of options
17
+ # @return [Faraday::Connection]
14
18
  def connection(options={})
15
- merged_options = faraday_options.merge({
19
+ default_options = {
16
20
  :headers => {
17
- 'Accept' => "application/#{format}",
18
- 'User-Agent' => user_agent
21
+ :accept => 'application/json',
22
+ :user_agent => user_agent
19
23
  },
20
24
  :proxy => proxy,
21
25
  :ssl => {:verify => false},
22
26
  :url => options.fetch(:endpoint, api_endpoint)
23
- })
24
-
25
- Faraday.new(merged_options) do |builder|
26
- builder.use Faraday::Request::Phoenix if options[:phoenix]
27
- builder.use Faraday::Request::MultipartWithFile
28
- builder.use Faraday::Request::AngellistApiOAuth, authentication if authenticated?
27
+ }
28
+
29
+ @connection ||= Faraday.new(connection_options.deep_merge(default_options)) do |builder|
30
+ builder.use AngellistApi::Request::MultipartWithFile
31
+ builder.use AngellistApi::Request::AngellistApiOAuth, authentication if authenticated?
29
32
  builder.use Faraday::Request::Multipart
30
33
  builder.use Faraday::Request::UrlEncoded
31
- builder.use Faraday::Request::Gateway, gateway if gateway
32
- builder.use Faraday::Response::RaiseHttp4xx
33
- unless options[:raw]
34
- case options.fetch(:format, format).to_s.downcase
35
- when 'json', 'phoenix'
36
- builder.use Faraday::Response::Mashify
37
- builder.use Faraday::Response::ParseJson
38
- when 'xml'
39
- builder.use Faraday::Response::Mashify
40
- builder.use Faraday::Response::ParseXml
41
- end
42
- end
43
- builder.use Faraday::Response::RaiseHttp5xx
34
+ builder.use AngellistApi::Request::Gateway, gateway if gateway
35
+ builder.use AngellistApi::Response::RaiseClientError
36
+ builder.use Faraday::Response::Mashify
37
+ builder.use Faraday::Response::ParseJson
38
+ builder.use AngellistApi::Response::RaiseServerError
44
39
  builder.adapter(adapter)
45
40
  end
41
+
42
+ @connection
46
43
  end
47
44
  end
48
45
  end
46
+
@@ -0,0 +1,19 @@
1
+ class Hash
2
+
3
+ # Merges self with another hash, recursively
4
+ #
5
+ # @param hash [Hash] The hash to merge
6
+ # @return [Hash]
7
+ def deep_merge(hash)
8
+ target = self.dup
9
+ hash.keys.each do |key|
10
+ if hash[key].is_a?(Hash) && self[key].is_a?(Hash)
11
+ target[key] = target[key].deep_merge(hash[key])
12
+ next
13
+ end
14
+ target[key] = hash[key]
15
+ end
16
+ target
17
+ end
18
+ end
19
+
@@ -3,57 +3,34 @@ module AngellistApi
3
3
  class Error < StandardError
4
4
  attr_reader :http_headers
5
5
 
6
+ # Initializes new Error object
7
+ #
8
+ # @param [String] message
9
+ # @param [Hash] http_headers
10
+ # @return [AngellistApi::Error]
6
11
  def initialize(message, http_headers)
7
12
  @http_headers = Hash[http_headers]
8
13
  super message
9
14
  end
10
15
 
16
+ # @return [Time]
11
17
  def ratelimit_reset
12
18
  Time.at(@http_headers.values_at('x-ratelimit-reset', 'X-RateLimit-Reset').detect{|value| value}.to_i)
13
19
  end
14
20
 
21
+ # @return [Integer]
15
22
  def ratelimit_limit
16
23
  @http_headers.values_at('x-ratelimit-limit', 'X-RateLimit-Limit').detect{|value| value}.to_i
17
24
  end
18
25
 
26
+ # @return [Integer]
19
27
  def ratelimit_remaining
20
28
  @http_headers.values_at('x-ratelimit-remaining', 'X-RateLimit-Remaining').detect{|value| value}.to_i
21
29
  end
22
30
 
31
+ # @return [Integer]
23
32
  def retry_after
24
33
  [(ratelimit_reset - Time.now).ceil, 0].max
25
34
  end
26
35
  end
27
-
28
- # Raised when AngellistApi returns the HTTP status code 400
29
- class BadRequest < Error; end
30
-
31
- # Raised when AngellistApi returns the HTTP status code 401
32
- class Unauthorized < Error; end
33
-
34
- # Raised when AngellistApi returns the HTTP status code 403
35
- class Forbidden < Error; end
36
-
37
- # Raised when AngellistApi returns the HTTP status code 404
38
- class NotFound < Error; end
39
-
40
- # Raised when AngellistApi returns the HTTP status code 406
41
- class NotAcceptable < Error; end
42
-
43
- # Raised when AngellistApi returns the HTTP status code 420
44
- class EnhanceYourCalm < Error
45
- # The number of seconds your application should wait before requesting date from the API again
46
- def retry_after
47
- @http_headers.values_at('retry-after', 'Retry-After').detect {|value| value }.to_i
48
- end
49
- end
50
-
51
- # Raised when AngellistApi returns the HTTP status code 500
52
- class InternalServerError < Error; end
53
-
54
- # Raised when AngellistApi returns the HTTP status code 502
55
- class BadGateway < Error; end
56
-
57
- # Raised when AngellistApi returns the HTTP status code 503
58
- class ServiceUnavailable < Error; end
59
36
  end
@@ -0,0 +1,7 @@
1
+ require 'angellist_api/error'
2
+
3
+ module AngellistApi
4
+ # Raised when AngellistApi returns the HTTP status code 502
5
+ class Error::BadGateway < AngellistApi::Error; end
6
+ end
7
+
@@ -0,0 +1,7 @@
1
+ require 'angellist_api/error'
2
+
3
+ module AngellistApi
4
+ # Raised when AngellistApi returns the HTTP status code 400
5
+ class Error::BadRequest < AngellistApi::Error; end
6
+ end
7
+
@@ -0,0 +1,13 @@
1
+ require 'angellist_api/error'
2
+
3
+ module AngellistApi
4
+ # Raised when AngellistApi returns the HTTP status code 420
5
+ class Error::EnhanceYourCalm < AngellistApi::Error
6
+ # The number of seconds your application should wait before requesting date
7
+ # from the API again
8
+ def retry_after
9
+ @http_headers.values_at('retry-after', 'Retry-After').detect {|value| value }.to_i
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,7 @@
1
+ require 'angellist_api/error'
2
+
3
+ module AngellistApi
4
+ # Raised when AngellistApi returns the HTTP status code 403
5
+ class Error::Forbidden < AngellistApi::Error; end
6
+ end
7
+
@@ -0,0 +1,7 @@
1
+ require 'angellist_api/error'
2
+
3
+ module AngellistApi
4
+ # Raised when AngellistApi returns the HTTP status code 500
5
+ class Error::InternalServerError < AngellistApi::Error; end
6
+ end
7
+
@@ -0,0 +1,7 @@
1
+ require 'angellist_api/error'
2
+
3
+ module AngellistApi
4
+ # Raised when AngellistApi returns the HTTP status code 406
5
+ class Error::NotAcceptable < AngellistApi::Error; end
6
+ end
7
+
@@ -0,0 +1,7 @@
1
+ require 'angellist_api/error'
2
+
3
+ module AngellistApi
4
+ # Raised when AngellistApi returns the HTTP status code 404
5
+ class Error::NotFound < AngellistApi::Error; end
6
+ end
7
+
@@ -0,0 +1,7 @@
1
+ require 'angellist_api/error'
2
+
3
+ module AngellistApi
4
+ # Raised when AngellistApi returns the HTTP status code 503
5
+ class Error::ServiceUnavailable < AngellistApi::Error; end
6
+ end
7
+
@@ -0,0 +1,7 @@
1
+ require 'angellist_api/error'
2
+
3
+ module AngellistApi
4
+ # Raised when AngellistApi returns the HTTP status code 401
5
+ class Error::Unauthorized < AngellistApi::Error; end
6
+ end
7
+
@@ -1,6 +1,11 @@
1
1
  module AngellistApi
2
2
  # Defines HTTP request methods
3
3
  module Request
4
+ # Perform an HTTP DELETE request
5
+ def delete(path, params={}, options={})
6
+ request(:delete, path, params, options)
7
+ end
8
+
4
9
  # Perform an HTTP GET request
5
10
  def get(path, params={}, options={})
6
11
  request(:get, path, params, options)
@@ -10,34 +15,22 @@ module AngellistApi
10
15
  request(:post, path, params, options)
11
16
  end
12
17
 
13
- # Perform an HTTP PUT request
14
- def put(path, params={}, options={})
15
- request(:put, path, params, options)
16
- end
17
-
18
- # Perform an HTTP DELETE request
19
- def delete(path, params={}, options={})
20
- request(:delete, path, params, options)
21
- end
22
-
23
18
  private
24
19
 
25
20
  # Perform an HTTP request
26
21
  def request(method, path, params, options)
27
- response = connection(options).send(method) do |request|
22
+ response = connection(options).run_request(method, nil, nil, nil) do |request|
23
+ request.options[:raw] = true if options[:raw]
28
24
  case method.to_sym
29
- when :get, :delete
30
- request.url(formatted_path(path, options), params)
31
- when :post, :put
32
- request.path = formatted_path(path, options)
25
+ when :delete, :get
26
+ request.url(path, params)
27
+ when :post
28
+ request.path = path
33
29
  request.body = params unless params.empty?
34
30
  end
35
31
  end
36
32
  options[:raw] ? response : response.body
37
33
  end
38
34
 
39
- def formatted_path(path, options={})
40
- path
41
- end
42
35
  end
43
36
  end
@@ -0,0 +1,16 @@
1
+ require 'faraday'
2
+
3
+ module AngellistApi
4
+ module Request
5
+ class AngellistApiOAuth < Faraday::Middleware
6
+ def call(env)
7
+ env[:request_headers]['Authorization'] = "Bearer #{@options[:access_token]}" if @options[:access_token]
8
+ @app.call(env)
9
+ end
10
+
11
+ def initialize(app, options)
12
+ @app, @options = app, options
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ require 'faraday'
2
+
3
+ module AngellistApi
4
+ module Request
5
+ class Gateway < Faraday::Middleware
6
+ def call(env)
7
+ url = env[:url].dup
8
+ url.host = @gateway
9
+ env[:url] = url
10
+ @app.call(env)
11
+ end
12
+
13
+ def initialize(app, gateway)
14
+ @app, @gateway = app, gateway
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ require 'faraday'
2
+
3
+ module AngellistApi
4
+ module Request
5
+ class MultipartWithFile < Faraday::Middleware
6
+ def call(env)
7
+ if env[:body].is_a?(Hash)
8
+ env[:body].each do |key, value|
9
+ if value.is_a?(File)
10
+ env[:body][key] = Faraday::UploadIO.new(value, mime_type(value.path), value.path)
11
+ elsif value.is_a?(Hash) && (value['io'].is_a?(IO) || value['io'].is_a?(StringIO))
12
+ env[:body][key] = Faraday::UploadIO.new(value['io'], mime_type('.'+value['type']), '')
13
+ end
14
+ end
15
+ end
16
+
17
+ @app.call(env)
18
+ end
19
+
20
+ private
21
+
22
+ def mime_type(path)
23
+ case path
24
+ when /\.jpe?g/i
25
+ 'image/jpeg'
26
+ when /\.gif$/i
27
+ 'image/gif'
28
+ when /\.png$/i
29
+ 'image/png'
30
+ else
31
+ 'application/octet-stream'
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end