ohanakapa 1.0.0

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 (46) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ohanakapa.rb +33 -0
  3. data/lib/ohanakapa/arguments.rb +14 -0
  4. data/lib/ohanakapa/authentication.rb +25 -0
  5. data/lib/ohanakapa/client.rb +226 -0
  6. data/lib/ohanakapa/client/categories.rb +42 -0
  7. data/lib/ohanakapa/client/keywords.rb +24 -0
  8. data/lib/ohanakapa/client/locations.rb +67 -0
  9. data/lib/ohanakapa/client/organizations.rb +43 -0
  10. data/lib/ohanakapa/client/rate_limit.rb +34 -0
  11. data/lib/ohanakapa/client/search.rb +23 -0
  12. data/lib/ohanakapa/configurable.rb +78 -0
  13. data/lib/ohanakapa/default.rb +88 -0
  14. data/lib/ohanakapa/error.rb +130 -0
  15. data/lib/ohanakapa/rate_limit.rb +31 -0
  16. data/lib/ohanakapa/response/raise_error.rb +21 -0
  17. data/lib/ohanakapa/version.rb +6 -0
  18. data/spec/cassettes/Ohanakapa_Client/_get/handles_query_params.json +1 -0
  19. data/spec/cassettes/Ohanakapa_Client/_head/handles_query_params.json +1 -0
  20. data/spec/cassettes/Ohanakapa_Client/_last_response/caches_the_last_agent_response.json +1 -0
  21. data/spec/cassettes/Ohanakapa_Client/auto_pagination/fetches_all_the_pages.json +1 -0
  22. data/spec/cassettes/Ohanakapa_Client_Categories/_add_keywords_to_a_service/adds_keywords_to_a_given_service.json +1 -0
  23. data/spec/cassettes/Ohanakapa_Client_Categories/_categories/returns_all_categories.json +1 -0
  24. data/spec/cassettes/Ohanakapa_Client_Categories/_replace_all_categories/replaces_all_categories_for_a_service.json +1 -0
  25. data/spec/cassettes/Ohanakapa_Client_Locations/_location/returns_an_location.json +1 -0
  26. data/spec/cassettes/Ohanakapa_Client_Locations/_locations/returns_all_locations.json +1 -0
  27. data/spec/cassettes/Ohanakapa_Client_Locations/_nearby/returns_locations_near_the_queried_location.json +1 -0
  28. data/spec/cassettes/Ohanakapa_Client_Locations/_update_location/updates_a_location_s_attributes.json +1 -0
  29. data/spec/cassettes/Ohanakapa_Client_Organizations/_organization/returns_an_organization.json +1 -0
  30. data/spec/cassettes/Ohanakapa_Client_Organizations/_organizations/returns_all_organizations.json +1 -0
  31. data/spec/cassettes/Ohanakapa_Client_Search/_search/searches_for_keyword_food_and_language_Spanish_.json +1 -0
  32. data/spec/cassettes/Ohanakapa_Client_Search/_search/searches_for_keyword_market_.json +1 -0
  33. data/spec/cassettes/Ohanakapa_Client_Search/_search/searches_for_location_san_mateo_ca_.json +1 -0
  34. data/spec/cassettes/rate_limit.json +1 -0
  35. data/spec/cassettes/root.json +1 -0
  36. data/spec/ohanakapa/client/categories_spec.rb +27 -0
  37. data/spec/ohanakapa/client/keywords_spec.rb +20 -0
  38. data/spec/ohanakapa/client/locations_spec.rb +41 -0
  39. data/spec/ohanakapa/client/organizations_spec.rb +23 -0
  40. data/spec/ohanakapa/client/rate_limit_spec.rb +40 -0
  41. data/spec/ohanakapa/client/search_spec.rb +38 -0
  42. data/spec/ohanakapa/client_spec.rb +363 -0
  43. data/spec/ohanakapa/rate_limit_spec.rb +25 -0
  44. data/spec/ohanakapa_spec.rb +46 -0
  45. data/spec/spec_helper.rb +88 -0
  46. metadata +146 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6afd9df44e4e14d0effab2bd786c6403b0bacb8d
4
+ data.tar.gz: 67e060430cb70d065cb082eecc7fd4d843831417
5
+ SHA512:
6
+ metadata.gz: 6cc26a543d2d073213bebb5d47efeb957670feb0e37c7b4e28dcc6c4bca1d534b402ac5027f8e4fede437ebe5b5f42c947d17ec4645470baa1a4d10ce634f5f6
7
+ data.tar.gz: 89fefdb5dec09c5116a98ba899c6e990e75d04c591b1c9d9caab39265d1c9ba75280a50a15307800911e9b130c8f34cf5df8f9e4f67c6b0a0f836596a6fd25ee
@@ -0,0 +1,33 @@
1
+ require 'ohanakapa/client'
2
+ require 'ohanakapa/default'
3
+
4
+ # Ruby toolkit for the Ohana API
5
+ module Ohanakapa
6
+
7
+ class << self
8
+ include Ohanakapa::Configurable
9
+
10
+ # API client based on configured options {Configurable}
11
+ #
12
+ # @return [Ohanakapa::Client] API wrapper
13
+ def client
14
+ @client = Ohanakapa::Client.new(options) unless defined?(@client) && @client.same_options?(options)
15
+ @client
16
+ end
17
+
18
+ # @private
19
+ def respond_to_missing?(method_name, include_private=false); client.respond_to?(method_name, include_private); end if RUBY_VERSION >= "1.9"
20
+ # @private
21
+ def respond_to?(method_name, include_private=false); client.respond_to?(method_name, include_private) || super; end if RUBY_VERSION < "1.9"
22
+
23
+ private
24
+
25
+ def method_missing(method_name, *args, &block)
26
+ return super unless client.respond_to?(method_name)
27
+ client.send(method_name, *args, &block)
28
+ end
29
+
30
+ end
31
+ end
32
+
33
+ Ohanakapa.setup
@@ -0,0 +1,14 @@
1
+ module Ohanakapa
2
+
3
+ # Extracts options from method arguments
4
+ # @private
5
+ class Arguments < Array
6
+ attr_reader :options
7
+
8
+ def initialize(args)
9
+ @options = args.last.is_a?(::Hash) ? args.pop : {}
10
+ super(args)
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ module Ohanakapa
2
+
3
+ # Authentication methods for {Ohanakapa::Client}
4
+ module Authentication
5
+
6
+ # Indicates if the client has Application
7
+ # api_token credentials to make anonymous
8
+ # requests at a higher rate limit
9
+ #
10
+ # @see http://ohanapi.herokuapp.com/api/docs
11
+ # @return [Boolean]
12
+ def application_authenticated?
13
+ !!application_authentication
14
+ end
15
+
16
+ private
17
+
18
+ def application_authentication
19
+ if @api_token
20
+ { :api_token => @api_token }
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,226 @@
1
+ require 'sawyer'
2
+ require 'ohanakapa/arguments'
3
+ require 'ohanakapa/configurable'
4
+ require 'ohanakapa/authentication'
5
+ require 'ohanakapa/rate_limit'
6
+ require 'ohanakapa/client/organizations'
7
+ require 'ohanakapa/client/locations'
8
+ require 'ohanakapa/client/categories'
9
+ require 'ohanakapa/client/keywords'
10
+ require 'ohanakapa/client/search'
11
+ require 'ohanakapa/client/rate_limit'
12
+
13
+ module Ohanakapa
14
+
15
+ # Client for the Ohana API
16
+ #
17
+ # @see http://ohanapi.herokuapp.com/api/docs
18
+ class Client
19
+
20
+ include Ohanakapa::Authentication
21
+ include Ohanakapa::Configurable
22
+ include Ohanakapa::Client::Organizations
23
+ include Ohanakapa::Client::Locations
24
+ include Ohanakapa::Client::Categories
25
+ include Ohanakapa::Client::Keywords
26
+ include Ohanakapa::Client::Search
27
+ include Ohanakapa::Client::RateLimit
28
+
29
+ # Header keys that can be passed in options hash to {#get},{#head}
30
+ CONVENIENCE_HEADERS = Set.new [:accept]
31
+
32
+ def initialize(options = {})
33
+ # Use options passed in, but fall back to module defaults
34
+ Ohanakapa::Configurable.keys.each do |key|
35
+ instance_variable_set(:"@#{key}", options[key] || Ohanakapa.instance_variable_get(:"@#{key}"))
36
+ end
37
+ end
38
+
39
+ # Compares client options to a Hash of requested options
40
+ #
41
+ # @param opts [Hash] Options to compare with current client options
42
+ # @return [Boolean]
43
+ def same_options?(opts)
44
+ opts.hash == options.hash
45
+ end
46
+
47
+ # Text representation of the client, masking tokens and passwords
48
+ #
49
+ # @return [String]
50
+ def inspect
51
+ inspected = super
52
+
53
+ # Only show last 4 of api token
54
+ if @api_token
55
+ inspected = inspected.gsub! @api_token, "#{'*'*32}#{@api_token[32..-1]}"
56
+ end
57
+
58
+ inspected
59
+ end
60
+
61
+ # Make a HTTP GET request
62
+ #
63
+ # @param url [String] The path, relative to {#api_endpoint}
64
+ # @param options [Hash] Query and header params for request
65
+ # @return [Sawyer::Resource]
66
+ def get(url, options = {})
67
+ request :get, url, parse_query_and_convenience_headers(options)
68
+ end
69
+
70
+ # Make a HTTP POST request
71
+ #
72
+ # @param url [String] The path, relative to {#api_endpoint}
73
+ # @param options [Hash] Body and header params for request
74
+ # @return [Sawyer::Resource]
75
+ def post(url, options = {})
76
+ request :post, url, options
77
+ end
78
+
79
+
80
+ # Make a HTTP PUT request
81
+ #
82
+ # @param url [String] The path, relative to {#api_endpoint}
83
+ # @param options [Hash] Body and header params for request
84
+ # @return [Sawyer::Resource]
85
+ def put(url, options = {})
86
+ request :put, url, options
87
+ end
88
+
89
+ # Make a HTTP PATCH request
90
+ #
91
+ # @param url [String] The path, relative to {#api_endpoint}
92
+ # @param options [Hash] Body and header params for request
93
+ # @return [Sawyer::Resource]
94
+ def patch(url, options = {})
95
+ request :patch, url, options
96
+ end
97
+
98
+ # Make a HTTP DELETE request
99
+ #
100
+ # @param url [String] The path, relative to {#api_endpoint}
101
+ # @param options [Hash] Query and header params for request
102
+ # @return [Sawyer::Resource]
103
+ def delete(url, options = {})
104
+ request :delete, url, options
105
+ end
106
+
107
+ # Make a HTTP HEAD request
108
+ #
109
+ # @param url [String] The path, relative to {#api_endpoint}
110
+ # @param options [Hash] Query and header params for request
111
+ # @return [Sawyer::Resource]
112
+ def head(url, options = {})
113
+ request :head, url, parse_query_and_convenience_headers(options)
114
+ end
115
+
116
+ # Make one or more HTTP GET requests, optionally fetching
117
+ # the next page of results from URL in Link response header based
118
+ # on value in {#auto_paginate}.
119
+ #
120
+ # @param url [String] The path, relative to {#api_endpoint}
121
+ # @param options [Hash] Query and header params for request
122
+ # @return [Sawyer::Resource]
123
+ def paginate(url, options = {})
124
+ opts = parse_query_and_convenience_headers(options.dup)
125
+ # if @auto_paginate
126
+ # opts[:query][:per_page] ||= @per_page || (@auto_paginate ? 100 : nil)
127
+ # end
128
+
129
+ data = request(:get, url, opts)
130
+
131
+ if @auto_paginate && data.is_a?(Array)
132
+ while @last_response.rels[:next] && rate_limit.remaining > 0
133
+ @last_response = @last_response.rels[:next].get
134
+ data.concat(@last_response.data) if @last_response.data.is_a?(Array)
135
+ end
136
+
137
+ end
138
+
139
+ data
140
+ end
141
+
142
+ # Hypermedia agent for the Ohana API
143
+ #
144
+ # @return [Sawyer::Agent]
145
+ def agent
146
+ @agent ||= Sawyer::Agent.new(api_endpoint, sawyer_options) do |http|
147
+ http.headers[:accept] = default_media_type
148
+ http.headers[:user_agent] = user_agent
149
+ if application_authenticated?
150
+ http.headers["X-Api-Token"] = @api_token
151
+ end
152
+ end
153
+ end
154
+
155
+ # Fetch the root resource for the API
156
+ #
157
+ # @return [Sawyer::Resource]
158
+ def root
159
+ agent.start.data
160
+ end
161
+
162
+ # Response for last HTTP request
163
+ #
164
+ # @return [Sawyer::Response]
165
+ def last_response
166
+ @last_response
167
+ end
168
+
169
+ private
170
+
171
+ def request(method, path, data)
172
+ options = {}
173
+ options[:query] = data.delete(:query) || {}
174
+ options[:headers] = data.delete(:headers) || {}
175
+
176
+ if application_authenticated?
177
+ options[:query].merge! application_authentication
178
+ end
179
+ if accept = data.delete(:accept)
180
+ options[:headers][:accept] = accept
181
+ end
182
+
183
+ @last_response = response = agent.call(method, URI.encode(path), data, options)
184
+ response.data
185
+ end
186
+
187
+ # Executes the request, checking if it was successful
188
+ #
189
+ # @return [Boolean] True on success, false otherwise
190
+ def boolean_from_response(method, path, options = {})
191
+ request(method, path, options)
192
+ @last_response.status == 204
193
+ rescue Ohanakapa::NotFound
194
+ false
195
+ end
196
+
197
+
198
+ def sawyer_options
199
+ opts = {
200
+ :links_parser => Sawyer::LinkParsers::Simple.new
201
+ }
202
+ conn_opts = @connection_options
203
+ conn_opts[:builder] = @middleware if @middleware
204
+ conn_opts[:proxy] = @proxy if @proxy
205
+ opts[:faraday] = Faraday.new(conn_opts)
206
+
207
+ opts
208
+ end
209
+
210
+ def parse_query_and_convenience_headers(options)
211
+ headers = options.fetch(:headers, {})
212
+ CONVENIENCE_HEADERS.each do |h|
213
+ if header = options.delete(h)
214
+ headers[h] = header
215
+ end
216
+ end
217
+ query = options.delete(:query)
218
+ opts = {:query => options}
219
+ opts[:query].merge!(query) if query && query.is_a?(Hash)
220
+ opts[:headers] = headers unless headers.empty?
221
+
222
+ opts
223
+ end
224
+
225
+ end
226
+ end
@@ -0,0 +1,42 @@
1
+ module Ohanakapa
2
+ class Client
3
+
4
+ # Methods for the Categories endpoint
5
+ #
6
+ # @see http://ohanapi.herokuapp.com/api/docs
7
+ module Categories
8
+
9
+ # List all categories
10
+ #
11
+ # This provides a dump of every category, in the order that they
12
+ # were uploaded to the Ohana DB.
13
+ #
14
+ # @see http://ohanapi.herokuapp.com/api/docs#!/api/GET-api-categories---format-_get_0
15
+ #
16
+ # @return [Array<Sawyer::Resource>] List of Categories.
17
+ #
18
+ # @example
19
+ # Ohanakapa.categories
20
+ # @example
21
+ # Ohanakapa.cats
22
+ def categories(options={})
23
+ paginate "categories", options
24
+ end
25
+ alias :cats :categories
26
+
27
+ # Replace all categories for a Service
28
+ #
29
+ # @param service_id [String] Number ID of the service
30
+ # @param cat_ids [Array] An array of category IDs to use as replacement
31
+ # @return [<Sawyer::Resource>] The updated service
32
+ # @see http://ohanapi.herokuapp.com/api/docs
33
+ # @example Replace categories for service with ID '521d339f1974fcdb2b00573e'
34
+ # Ohanakapa.replace_all_categories("521d339f1974fcdb2b00573e", ['52280f5c1edd37edff000001', '52280f5c1edd37edff000003'])
35
+ def replace_all_categories(service_id, cat_ids)
36
+ put "services/#{service_id}/categories", :query => { :category_ids => cat_ids }
37
+ end
38
+
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ module Ohanakapa
2
+ class Client
3
+
4
+ # Methods for adding Keywords to a service
5
+ #
6
+ # @see http://ohanapi.herokuapp.com/api/docs
7
+ module Keywords
8
+
9
+ # Add keywords to a Service
10
+ #
11
+ # @param service_id [String] Number ID of the service
12
+ # @param keywords [Array] An array of keywords to use as replacement
13
+ # @return [<Sawyer::Resource>] The updated service
14
+ # @see http://ohanapi.herokuapp.com/api/docs
15
+ # @example Add keywords to service with ID '521d339f1974fcdb2b00573e'
16
+ # Ohanakapa.add_keywords_to_a_service("521d339f1974fcdb2b00573e", ['testing', 'api'])
17
+ def add_keywords_to_a_service(service_id, keywords)
18
+ post "services/#{service_id}/keywords", :query => { :keywords => keywords }
19
+ end
20
+
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,67 @@
1
+ module Ohanakapa
2
+ class Client
3
+
4
+ # Methods for the Locations API
5
+ #
6
+ # @see http://ohanapi.herokuapp.com/api/docs
7
+ module Locations
8
+
9
+ # List all locations
10
+ #
11
+ # This provides a dump of every location, in the order that they
12
+ # were uploaded to the Ohana DB.
13
+ #
14
+ # @see http://ohanapi.herokuapp.com/api/docs#!/api/GET-api-locations---format-_get_0
15
+ #
16
+ # @return [Array<Sawyer::Resource>] List of Locations.
17
+ #
18
+ # @example
19
+ # Ohanakapa.locations
20
+ # @example
21
+ # Ohanakapa.locs
22
+ def locations(options={})
23
+ paginate "locations", options
24
+ end
25
+ alias :locs :locations
26
+
27
+ # Get a single location based on its ID
28
+ # @see http://ohanapi.herokuapp.com/api/docs#!/api/GET-api-locations--id---format-_get_1
29
+ #
30
+ # @param id [String] location ID.
31
+ # @return [Sawyer::Resource]
32
+ # @example
33
+ # Ohanakapa.location('519c44065634241897000023')
34
+ # @example
35
+ # Ohanakapa.loc('519c44065634241897000023')
36
+ def location(id)
37
+ get("locations/#{id}")
38
+ end
39
+ alias :loc :location
40
+
41
+ # Get nearby locations to an location, based on its ID
42
+ #
43
+ # @param id [String] location ID.
44
+ # @param options [Hash] A customizable set of options.
45
+ # @option options [Float] :radius
46
+ # @return [Sawyer::Resource] Hash representing nearby locations.
47
+ # @example
48
+ # Ohanakapa.nearby('519c44065634241897000023', :radius => 0.5)
49
+ def nearby(id, options={})
50
+ get("locations/#{id}/nearby", options)
51
+ end
52
+
53
+ # Update a location
54
+ #
55
+ # @param id [String] location ID.
56
+ # @param options [Hash] A customizable set of options.
57
+ # @option options [String] :kind
58
+ # @return [Sawyer::Resource]
59
+ # @example
60
+ # Ohanakapa.location("521d33a01974fcdb2b0036a9", :kind => "entertainment")
61
+ def update_location(id, options)
62
+ put "locations/#{id}", :query => options
63
+ end
64
+
65
+ end
66
+ end
67
+ end