ghost_google-api-client 0.4.7.1

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 (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