ghost_google-api-client 0.4.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/CHANGELOG.md +77 -0
  2. data/Gemfile +30 -0
  3. data/Gemfile.lock +80 -0
  4. data/LICENSE +202 -0
  5. data/README.md +71 -0
  6. data/Rakefile +42 -0
  7. data/bin/google-api +545 -0
  8. data/lib/compat/multi_json.rb +17 -0
  9. data/lib/google/api_client.rb +802 -0
  10. data/lib/google/api_client/batch.rb +296 -0
  11. data/lib/google/api_client/client_secrets.rb +106 -0
  12. data/lib/google/api_client/discovery.rb +19 -0
  13. data/lib/google/api_client/discovery/api.rb +287 -0
  14. data/lib/google/api_client/discovery/media.rb +77 -0
  15. data/lib/google/api_client/discovery/method.rb +369 -0
  16. data/lib/google/api_client/discovery/resource.rb +150 -0
  17. data/lib/google/api_client/discovery/schema.rb +119 -0
  18. data/lib/google/api_client/environment.rb +42 -0
  19. data/lib/google/api_client/errors.rb +49 -0
  20. data/lib/google/api_client/media.rb +172 -0
  21. data/lib/google/api_client/reference.rb +305 -0
  22. data/lib/google/api_client/result.rb +161 -0
  23. data/lib/google/api_client/service_account.rb +134 -0
  24. data/lib/google/api_client/version.rb +31 -0
  25. data/lib/google/inflection.rb +28 -0
  26. data/spec/fixtures/files/sample.txt +33 -0
  27. data/spec/google/api_client/batch_spec.rb +241 -0
  28. data/spec/google/api_client/discovery_spec.rb +670 -0
  29. data/spec/google/api_client/media_spec.rb +143 -0
  30. data/spec/google/api_client/result_spec.rb +185 -0
  31. data/spec/google/api_client/service_account_spec.rb +58 -0
  32. data/spec/google/api_client_spec.rb +139 -0
  33. data/spec/spec_helper.rb +7 -0
  34. data/tasks/gem.rake +97 -0
  35. data/tasks/git.rake +45 -0
  36. data/tasks/metrics.rake +22 -0
  37. data/tasks/spec.rake +57 -0
  38. data/tasks/wiki.rake +82 -0
  39. data/tasks/yard.rake +29 -0
  40. metadata +253 -0
@@ -0,0 +1,77 @@
1
+ # Copyright 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require 'addressable/uri'
17
+ require 'addressable/template'
18
+
19
+ require 'google/api_client/errors'
20
+
21
+
22
+ module Google
23
+ class APIClient
24
+ ##
25
+ # Media upload elements for discovered methods
26
+ class MediaUpload
27
+
28
+ ##
29
+ # Creates a description of a particular method.
30
+ #
31
+ # @param [Google::APIClient::API] api
32
+ # Base discovery document for the API
33
+ # @param [Addressable::URI] method_base
34
+ # The base URI for the service.
35
+ # @param [Hash] discovery_document
36
+ # The media upload section of the discovery document.
37
+ #
38
+ # @return [Google::APIClient::Method] The constructed method object.
39
+ def initialize(api, method_base, discovery_document)
40
+ @api = api
41
+ @method_base = method_base
42
+ @discovery_document = discovery_document
43
+ end
44
+
45
+ ##
46
+ # List of acceptable mime types
47
+ #
48
+ # @return [Array]
49
+ # List of acceptable mime types for uploaded content
50
+ def accepted_types
51
+ @discovery_document['accept']
52
+ end
53
+
54
+ ##
55
+ # Maximum size of an uplad
56
+ # TODO: Parse & convert to numeric value
57
+ #
58
+ # @return [String]
59
+ def max_size
60
+ @discovery_document['maxSize']
61
+ end
62
+
63
+ ##
64
+ # Returns the URI template for the method. A parameter list can be
65
+ # used to expand this into a URI.
66
+ #
67
+ # @return [Addressable::Template] The URI template.
68
+ def uri_template
69
+ return @uri_template ||= Addressable::Template.new(
70
+ @api.method_base.join(Addressable::URI.parse(@discovery_document['protocols']['simple']['path']))
71
+ )
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,369 @@
1
+ # Copyright 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require 'addressable/uri'
17
+ require 'addressable/template'
18
+
19
+ require 'google/api_client/errors'
20
+
21
+
22
+ module Google
23
+ class APIClient
24
+ ##
25
+ # A method that has been described by a discovery document.
26
+ class Method
27
+
28
+ ##
29
+ # Creates a description of a particular method.
30
+ #
31
+ # @param [Google::APIClient::API] api
32
+ # The API this method belongs to.
33
+ # @param [Addressable::URI] method_base
34
+ # The base URI for the service.
35
+ # @param [String] method_name
36
+ # The identifier for the method.
37
+ # @param [Hash] method_description
38
+ # The section of the discovery document that applies to this method.
39
+ #
40
+ # @return [Google::APIClient::Method] The constructed method object.
41
+ def initialize(api, method_base, method_name, discovery_document)
42
+ @api = api
43
+ @method_base = method_base
44
+ @name = method_name
45
+ @discovery_document = discovery_document
46
+ end
47
+
48
+ ##
49
+ # Returns the API this method belongs to.
50
+ #
51
+ # @return [Google::APIClient::API] The API this method belongs to.
52
+ attr_reader :api
53
+
54
+ ##
55
+ # Returns the identifier for the method.
56
+ #
57
+ # @return [String] The method identifier.
58
+ attr_reader :name
59
+
60
+ ##
61
+ # Returns the parsed section of the discovery document that applies to
62
+ # this method.
63
+ #
64
+ # @return [Hash] The method description.
65
+ attr_reader :description
66
+
67
+ ##
68
+ # Returns the base URI for the method.
69
+ #
70
+ # @return [Addressable::URI]
71
+ # The base URI that this method will be joined to.
72
+ attr_reader :method_base
73
+
74
+ ##
75
+ # Updates the method with the new base.
76
+ #
77
+ # @param [Addressable::URI, #to_str, String] new_base
78
+ # The new base URI to use for the method.
79
+ def method_base=(new_method_base)
80
+ @method_base = Addressable::URI.parse(new_method_base)
81
+ @uri_template = nil
82
+ end
83
+
84
+ ##
85
+ # Returns the method ID.
86
+ #
87
+ # @return [String] The method identifier.
88
+ def id
89
+ return @discovery_document['id']
90
+ end
91
+
92
+ ##
93
+ # Returns the HTTP method or 'GET' if none is specified.
94
+ #
95
+ # @return [String] The HTTP method that will be used in the request.
96
+ def http_method
97
+ return @discovery_document['httpMethod'] || 'GET'
98
+ end
99
+
100
+ ##
101
+ # Returns the URI template for the method. A parameter list can be
102
+ # used to expand this into a URI.
103
+ #
104
+ # @return [Addressable::Template] The URI template.
105
+ def uri_template
106
+ return @uri_template ||= Addressable::Template.new(
107
+ self.method_base.join(Addressable::URI.parse(@discovery_document['path']))
108
+ )
109
+ end
110
+
111
+ ##
112
+ # Returns media upload information for this method, if supported
113
+ #
114
+ # @return [Google::APIClient::MediaUpload] Description of upload endpoints
115
+ def media_upload
116
+ if @discovery_document['mediaUpload']
117
+ return @media_upload ||= Google::APIClient::MediaUpload.new(self, self.method_base, @discovery_document['mediaUpload'])
118
+ else
119
+ return nil
120
+ end
121
+ end
122
+
123
+ ##
124
+ # Returns the Schema object for the method's request, if any.
125
+ #
126
+ # @return [Google::APIClient::Schema] The request schema.
127
+ def request_schema
128
+ if @discovery_document['request']
129
+ schema_name = @discovery_document['request']['$ref']
130
+ return @api.schemas[schema_name]
131
+ else
132
+ return nil
133
+ end
134
+ end
135
+
136
+ ##
137
+ # Returns the Schema object for the method's response, if any.
138
+ #
139
+ # @return [Google::APIClient::Schema] The response schema.
140
+ def response_schema
141
+ if @discovery_document['response']
142
+ schema_name = @discovery_document['response']['$ref']
143
+ return @api.schemas[schema_name]
144
+ else
145
+ return nil
146
+ end
147
+ end
148
+
149
+ ##
150
+ # Normalizes parameters, converting to the appropriate types.
151
+ #
152
+ # @param [Hash, Array] parameters
153
+ # The parameters to normalize.
154
+ #
155
+ # @return [Hash] The normalized parameters.
156
+ def normalize_parameters(parameters={})
157
+ # Convert keys to Strings when appropriate
158
+ if parameters.kind_of?(Hash) || parameters.kind_of?(Array)
159
+ # Returning an array since parameters can be repeated (ie, Adsense Management API)
160
+ parameters = parameters.inject([]) do |accu, (k, v)|
161
+ k = k.to_s if k.kind_of?(Symbol)
162
+ k = k.to_str if k.respond_to?(:to_str)
163
+ unless k.kind_of?(String)
164
+ raise TypeError, "Expected String, got #{k.class}."
165
+ end
166
+ accu << [k, v]
167
+ accu
168
+ end
169
+ else
170
+ raise TypeError,
171
+ "Expected Hash or Array, got #{parameters.class}."
172
+ end
173
+ return parameters
174
+ end
175
+
176
+ ##
177
+ # Expands the method's URI template using a parameter list.
178
+ #
179
+ # @param [Hash, Array] parameters
180
+ # The parameter list to use.
181
+ #
182
+ # @return [Addressable::URI] The URI after expansion.
183
+ def generate_uri(parameters={})
184
+ parameters = self.normalize_parameters(parameters)
185
+ self.validate_parameters(parameters)
186
+ template_variables = self.uri_template.variables
187
+ upload_type = parameters.assoc('uploadType') || parameters.assoc('upload_type')
188
+ if upload_type
189
+ unless self.media_upload
190
+ raise ArgumentException, "Media upload not supported for this method"
191
+ end
192
+ case upload_type.last
193
+ when 'media', 'multipart', 'resumable'
194
+ uri = self.media_upload.uri_template.expand(parameters)
195
+ else
196
+ raise ArgumentException, "Invalid uploadType '#{upload_type}'"
197
+ end
198
+ else
199
+ uri = self.uri_template.expand(parameters)
200
+ end
201
+ query_parameters = parameters.reject do |k, v|
202
+ template_variables.include?(k)
203
+ end
204
+ # encode all non-template parameters
205
+ params = ""
206
+ unless query_parameters.empty?
207
+ params = "?" + Addressable::URI.form_encode(query_parameters.sort)
208
+ end
209
+ # Normalization is necessary because of undesirable percent-escaping
210
+ # during URI template expansion
211
+ return uri.normalize + params
212
+ end
213
+
214
+ ##
215
+ # Generates an HTTP request for this method.
216
+ #
217
+ # @param [Hash, Array] parameters
218
+ # The parameters to send.
219
+ # @param [String, StringIO] body The body for the HTTP request.
220
+ # @param [Hash, Array] headers The HTTP headers for the request.
221
+ # @option options [Faraday::Connection] :connection
222
+ # The HTTP connection to use.
223
+ #
224
+ # @return [Array] The generated HTTP request.
225
+ def generate_request(parameters={}, body='', headers=[], options={})
226
+ options[:connection] ||= Faraday.default_connection
227
+ if body.respond_to?(:string)
228
+ body = body.string
229
+ elsif body.respond_to?(:to_str)
230
+ body = body.to_str
231
+ else
232
+ raise TypeError, "Expected String or StringIO, got #{body.class}."
233
+ end
234
+ if !headers.kind_of?(Array) && !headers.kind_of?(Hash)
235
+ raise TypeError, "Expected Hash or Array, got #{headers.class}."
236
+ end
237
+ method = self.http_method
238
+ uri = self.generate_uri(parameters)
239
+ headers = headers.to_a if headers.kind_of?(Hash)
240
+ return options[:connection].build_request(
241
+ method.to_s.downcase.to_sym
242
+ ) do |req|
243
+ req.url(Addressable::URI.parse(uri).normalize.to_s)
244
+ req.headers = Faraday::Utils::Headers.new(headers)
245
+ req.body = body
246
+ end
247
+ end
248
+
249
+
250
+ ##
251
+ # Returns a <code>Hash</code> of the parameter descriptions for
252
+ # this method.
253
+ #
254
+ # @return [Hash] The parameter descriptions.
255
+ def parameter_descriptions
256
+ @parameter_descriptions ||= (
257
+ @discovery_document['parameters'] || {}
258
+ ).inject({}) { |h,(k,v)| h[k]=v; h }
259
+ end
260
+
261
+ ##
262
+ # Returns an <code>Array</code> of the parameters for this method.
263
+ #
264
+ # @return [Array] The parameters.
265
+ def parameters
266
+ @parameters ||= ((
267
+ @discovery_document['parameters'] || {}
268
+ ).inject({}) { |h,(k,v)| h[k]=v; h }).keys
269
+ end
270
+
271
+ ##
272
+ # Returns an <code>Array</code> of the required parameters for this
273
+ # method.
274
+ #
275
+ # @return [Array] The required parameters.
276
+ #
277
+ # @example
278
+ # # A list of all required parameters.
279
+ # method.required_parameters
280
+ def required_parameters
281
+ @required_parameters ||= ((self.parameter_descriptions.select do |k, v|
282
+ v['required']
283
+ end).inject({}) { |h,(k,v)| h[k]=v; h }).keys
284
+ end
285
+
286
+ ##
287
+ # Returns an <code>Array</code> of the optional parameters for this
288
+ # method.
289
+ #
290
+ # @return [Array] The optional parameters.
291
+ #
292
+ # @example
293
+ # # A list of all optional parameters.
294
+ # method.optional_parameters
295
+ def optional_parameters
296
+ @optional_parameters ||= ((self.parameter_descriptions.reject do |k, v|
297
+ v['required']
298
+ end).inject({}) { |h,(k,v)| h[k]=v; h }).keys
299
+ end
300
+
301
+ ##
302
+ # Verifies that the parameters are valid for this method. Raises an
303
+ # exception if validation fails.
304
+ #
305
+ # @param [Hash, Array] parameters
306
+ # The parameters to verify.
307
+ #
308
+ # @return [NilClass] <code>nil</code> if validation passes.
309
+ def validate_parameters(parameters={})
310
+ parameters = self.normalize_parameters(parameters)
311
+ required_variables = ((self.parameter_descriptions.select do |k, v|
312
+ v['required']
313
+ end).inject({}) { |h,(k,v)| h[k]=v; h }).keys
314
+ missing_variables = required_variables - parameters.map { |(k, _)| k }
315
+ if missing_variables.size > 0
316
+ raise ArgumentError,
317
+ "Missing required parameters: #{missing_variables.join(', ')}."
318
+ end
319
+ parameters.each do |k, v|
320
+ # Handle repeated parameters.
321
+ if self.parameter_descriptions[k] &&
322
+ self.parameter_descriptions[k]['repeated'] &&
323
+ v.kind_of?(Array)
324
+ # If this is a repeated parameter and we've got an array as a
325
+ # value, just provide the whole array to the loop below.
326
+ items = v
327
+ else
328
+ # If this is not a repeated parameter, or if it is but we're
329
+ # being given a single value, wrap the value in an array, so that
330
+ # the loop below still works for the single element.
331
+ items = [v]
332
+ end
333
+
334
+ items.each do |item|
335
+ if self.parameter_descriptions[k]
336
+ enum = self.parameter_descriptions[k]['enum']
337
+ if enum && !enum.include?(item)
338
+ raise ArgumentError,
339
+ "Parameter '#{k}' has an invalid value: #{item}. " +
340
+ "Must be one of #{enum.inspect}."
341
+ end
342
+ pattern = self.parameter_descriptions[k]['pattern']
343
+ if pattern
344
+ regexp = Regexp.new("^#{pattern}$")
345
+ if item !~ regexp
346
+ raise ArgumentError,
347
+ "Parameter '#{k}' has an invalid value: #{item}. " +
348
+ "Must match: /^#{pattern}$/."
349
+ end
350
+ end
351
+ end
352
+ end
353
+ end
354
+ return nil
355
+ end
356
+
357
+ ##
358
+ # Returns a <code>String</code> representation of the method's state.
359
+ #
360
+ # @return [String] The method's state, as a <code>String</code>.
361
+ def inspect
362
+ sprintf(
363
+ "#<%s:%#0x ID:%s>",
364
+ self.class.to_s, self.object_id, self.id
365
+ )
366
+ end
367
+ end
368
+ end
369
+ end
@@ -0,0 +1,150 @@
1
+ # Copyright 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require 'addressable/uri'
17
+
18
+ require 'google/inflection'
19
+ require 'google/api_client/discovery/method'
20
+
21
+
22
+ module Google
23
+ class APIClient
24
+ ##
25
+ # A resource that has been described by a discovery document.
26
+ class Resource
27
+
28
+ ##
29
+ # Creates a description of a particular version of a resource.
30
+ #
31
+ # @param [Addressable::URI] base
32
+ # The base URI for the service.
33
+ # @param [String] resource_name
34
+ # The identifier for the resource.
35
+ # @param [Hash] resource_description
36
+ # The section of the discovery document that applies to this resource.
37
+ #
38
+ # @return [Google::APIClient::Resource] The constructed resource object.
39
+ def initialize(api, method_base, resource_name, discovery_document)
40
+ @api = api
41
+ @method_base = method_base
42
+ @name = resource_name
43
+ @discovery_document = discovery_document
44
+ metaclass = (class <<self; self; end)
45
+ self.discovered_resources.each do |resource|
46
+ method_name = Google::INFLECTOR.underscore(resource.name).to_sym
47
+ if !self.respond_to?(method_name)
48
+ metaclass.send(:define_method, method_name) { resource }
49
+ end
50
+ end
51
+ self.discovered_methods.each do |method|
52
+ method_name = Google::INFLECTOR.underscore(method.name).to_sym
53
+ if !self.respond_to?(method_name)
54
+ metaclass.send(:define_method, method_name) { method }
55
+ end
56
+ end
57
+ end
58
+
59
+ ##
60
+ # Returns the identifier for the resource.
61
+ #
62
+ # @return [String] The resource identifier.
63
+ attr_reader :name
64
+
65
+ ##
66
+ # Returns the parsed section of the discovery document that applies to
67
+ # this resource.
68
+ #
69
+ # @return [Hash] The resource description.
70
+ attr_reader :description
71
+
72
+ ##
73
+ # Returns the base URI for this resource.
74
+ #
75
+ # @return [Addressable::URI] The base URI that methods are joined to.
76
+ attr_reader :method_base
77
+
78
+ ##
79
+ # Updates the hierarchy of resources and methods with the new base.
80
+ #
81
+ # @param [Addressable::URI, #to_str, String] new_base
82
+ # The new base URI to use for the resource.
83
+ def method_base=(new_method_base)
84
+ @method_base = Addressable::URI.parse(new_method_base)
85
+ self.discovered_resources.each do |resource|
86
+ resource.method_base = @method_base
87
+ end
88
+ self.discovered_methods.each do |method|
89
+ method.method_base = @method_base
90
+ end
91
+ end
92
+
93
+ ##
94
+ # A list of sub-resources available on this resource.
95
+ #
96
+ # @return [Array] A list of {Google::APIClient::Resource} objects.
97
+ def discovered_resources
98
+ return @discovered_resources ||= (
99
+ (@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
100
+ accu << Google::APIClient::Resource.new(
101
+ @api, self.method_base, k, v
102
+ )
103
+ accu
104
+ end
105
+ )
106
+ end
107
+
108
+ ##
109
+ # A list of methods available on this resource.
110
+ #
111
+ # @return [Array] A list of {Google::APIClient::Method} objects.
112
+ def discovered_methods
113
+ return @discovered_methods ||= (
114
+ (@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
115
+ accu << Google::APIClient::Method.new(@api, self.method_base, k, v)
116
+ accu
117
+ end
118
+ )
119
+ end
120
+
121
+ ##
122
+ # Converts the resource to a flat mapping of RPC names and method
123
+ # objects.
124
+ #
125
+ # @return [Hash] All methods available on the resource.
126
+ def to_h
127
+ return @hash ||= (begin
128
+ methods_hash = {}
129
+ self.discovered_methods.each do |method|
130
+ methods_hash[method.id] = method
131
+ end
132
+ self.discovered_resources.each do |resource|
133
+ methods_hash.merge!(resource.to_h)
134
+ end
135
+ methods_hash
136
+ end)
137
+ end
138
+
139
+ ##
140
+ # Returns a <code>String</code> representation of the resource's state.
141
+ #
142
+ # @return [String] The resource's state, as a <code>String</code>.
143
+ def inspect
144
+ sprintf(
145
+ "#<%s:%#0x NAME:%s>", self.class.to_s, self.object_id, self.name
146
+ )
147
+ end
148
+ end
149
+ end
150
+ end